Писал давненько статью для web-hacka, решил запостить и тут, наверняка найдутся люди которым она в чем то поможет. Итак. =========================== /********* Предисловие ***********/ В один прекрасный день я столкнулся с задачей сделать авторассыльщик по доскам объявлений прямо с сайта заказчика. Порыл гугль, но ничего конкретного на эту тему не нашел , решил сделать сам. Итак, для работы нам понадобится PHP как минимум четвертой версии (при младших версиях работоспособность не проверял) с прикрученной библиотекой CURL. Что это за штука и где ее найти можно прочитать здесь . Даже если вы не собираетесь делать то, что я тут описываю, настоятельно рекомендую ознакомится с этой библиотекой, она вам обязательно понравится и в будущем пригодится. Поставили курл - вызываем phpinfo() и ищем там строчку "CURL support ======== Enabled". Нашли? Тогда идем дальше. Помимо CURL'а вам понадобятся как минимум начальные знания языка PHP, минимальное представление о работе протокола http и хорошее настроение, организованное любимым треком в WinAmp'е. Прямые руки, как всегда, приветсвуются. /********* Преступим [теория]***********/ Чтобы не быть голословным, буду писать скриптег под реальный сайт - _optsib.ru. Заходим на сайт, тыкаем "Доска объявлений" => "Добавить объявление". Смотрим в адресную строку браузера и видим там какую то бяку типа этой s=20080ч221521288b93b4a822fe4e235843df043d76b774. Что то похожее на ПХП СессИд. Берем на заметку и открываем HTML код странички, плясать будем именно от него. Там находим код формы, и выписываем имена полей, обязательных для заполнения. У нас это: name, email, phone, razdel, zag, text. Их значения мы будем передавать на сервер заголовком POST (так как форма использует именно этот способ отправки). Так же мы видим в коде еще хидден поля - вот где на самом деле зарыта собака. У нас их три: ins, s, и sort. Не закрывая первого, открываем любой другой браузер переходим на ту же страничку добавления объявления и сравнивая ее ХТМЛ код с кодом первого браузера, убеждаемся что hidden поля ins и sort статичны и несут служебную информацию, а вот поле s изменило свое значение, это и есть защита от спама, оно же предупреждает нас что одним запросом на сервер нам не обойтись. /********* Преступим [кодим наконец то ]***********/ Итак создаем новый php-файл и начинаем кодить. Первым делом объявляем серверу что мы пришли, чтобы он выдал нам куки, по которым в последствии он будет сверять, не робот ли мы: Code: $url="http://optsib.ru/do.phtml"; $ua = 'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)'; $ch=curl_init(); //инициализируем сеанс CURL // ф-ция curl_setopt устанавливает параметры для запроса curl_setopt($ch, CURLOPT_URL, $url); //указываем URL для запроса curl_setopt($ch, CURLOPT_HEADER, 1); //просим CURL возвращать нам ответ [b]вместе[/b] с заголовками (обязательно) curl_setopt($ch, CURLOPT_USERAGENT, $ua); //утверждаем что мы браузер чтоб не спалили curl_setopt($ch, CURLOPT_TIMEOUT, 10); //без коментариев curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //говорим что ответ сервера нам нада возвращать, а не выводить прямо в браузер. $answer=curl_exec($ch); //выполняем сам запрос, ответ сервера сохраняем в $answer. [/quote] Далее выводим ответ в браузер чтобы глянуть что там у нас пришло в заголовках. Там видим что в заголовке нам выдают кукисы PHPSESSID. Выдираем их и сохраняем себе на память : [code] $sess_cookie=substr($answer, strpos($answer, "PHPSESSID=")+10, 32); Дальше вспоминаем что у нас еще есть хидден поле s, его значение тоже достаем: Code: $s_hidden=substr($answer, strpos($answer, 'name="s" value=')+16, 46); Прямо как настоящий браузер мы приняли сессию, выданную нам доской, теперь можно послать объявление на доску: Code: $post="name=$company&email=$email&phone=$contacts&razdel=$cat &zag=$ed_name&text=$text_full&ins=1&sort=2&s=$s_hidden"; /*сформировали строку пост данных состоящую из пар [i]поле=>значение[/i] разделенных амперсандом (при необходимости строку надо url-кодировать)*/ curl_setopt($ch, CURLOPT_URL, "http://optsib.ru/insert.php"); //адрес на который шлем запрос (выдираем значение из action нашей формы) curl_setopt($ch, CURLOPT_HEADER, 1); //дальше мы все уже видели curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIE, $sess_cookie); //а вот тут внимательнее! не забываем показать серверу наши, полученные ранее кукисы curl_setopt($ch, CURLOPT_POST, 1); //говорим что у нас есть POST данные для сервера curl_setopt($ch, CURLOPT_REFERER, "http://optsib.ru/do.phtml?d=ins&sort=2&s=$s_hidden"); /*ставим заголовок [b]referer[/b] чтоб не спалится, вспоминаем про байду в адресной строке, теперь мы уже знаем что эта байда как раз значение нашего защитного поля */ curl_setopt($ch, CURLOPT_POSTFIELDS, $post); //указываем на наши POST данные $answer=curl_exec($ch); //выполняем запрос на сервер Печатаем ответ в браузер, видим "Ваше объявление успешно добавлено" и радуемся. Думаю на первый раз достаточно, это моя первая статья, просьба сильно не пинать . Ах да, об оптимизации кода я особо не заботился, в первую очередь пытаясь написать все как можно яснее. Если на сайте стоит защитная картинка, придется вам порыскать информацию об ее распознавании, ибо это выходит за границы данной статьи.
Здравствуйте. Вот пробую приспособить этот способ к сайту memori.ru. Но там защита на регистрацию стоит. Никаких изменяемых полей вроде нет. PHP: $url = "http://memori.ru/login/"; $ua = 'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result=curl_exec($ch); $sess_cookie=substr($result, strpos($result, "PHPSESSID=")+10, 32); $post="login=LOGIN&passw=PASSWORD&go_logining=1"; curl_setopt($ch, CURLOPT_URL, "http://memori.ru/login/"); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIE, $sess_cookie); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_REFERER, "http://memori.ru/"); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); $result = curl_exec($ch); echo $result; Чего не так делаю??
В данном случае сайт не делает лишних проверок, поэтому перед авторизацией сессию ставить не нада, можно сразу слать данные. Вот рабочий вариант: PHP: $url = "http://memori.ru/login/"; $ua = 'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)'; $ch = curl_init(); $post="login=megalol&passw=nvidia&go_logining=1&book=0&sf=&remember=1"; curl_setopt($ch, CURLOPT_URL, "http://memori.ru/login/"); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_REFERER, "http://memori.ru/"); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); $result = curl_exec($ch); echo $result; В ответ получаем заголовки: Code: HTTP/1.1 302 Found Via: 1.1 RAID-PROXY Connection: Keep-Alive Proxy-Connection: Keep-Alive Content-Length: 0 Expires: Thu, 19 Nov 1981 08:52:00 GMT Date: Tue, 28 Oct 2008 10:02:41 GMT location: http://memori.ru/megalol/ Content-Type: text/html Server: nginx/0.5.28 X-Powered-By: PHP/5.2.3 Set-Cookie: PHPSESSID=3b731188cdf0c2369bf738f67ff1ce40; path=/ Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: isp=540df7f83845146f0287ff6d2da77900; expires=Sat, 27-Dec-2008 10:02:41 GMT; path=/ Set-Cookie: isl=megalol; expires=Sat, 27-Dec-2008 10:02:41 GMT; path=/ Вырезаем строку PHPSESSID=3b731188cdf0c2369bf738f67ff1ce40 и ее используем для дальнейших запросов к серверу, передавая кукисами, чтобы он считал вас авторизованым под вашим логином. ========================= Кстати, если параметр равен нулю, это не значит что его нет, при отправкее запроса передавайте ВСЕ параметры, имеющиеся в форме, в вашем не хватает параметра book.
копи-пасте с php.net/curl хотя бы показал про курл_мульти ... да и проверок на ошибки нету, не показано про прокси ничего.
Именно это все можно посмотреть углубленно на php.ner/curl/, я же показал на примере с объяснением что есть курл и с чем его едят. php.net хороший справочник по функциям, но наглядности в данном случае никакой. Кстати на момент написания статьи русской документации по курлу я не нашел.
Спасибо. Только я немного не так сделал. PHP: $url = "http://memori.ru/login/"; $ua = 'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)'; $ch = curl_init(); $post="login=megalol&passw=nvidia&go_logining=1&book=0&sf=&remember=1"; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HEADER, 1); //просим CURL возвращать нам ответ вместе с заголовками (обязательно) curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, "login=megalol&passw=nvidia&go_logining=1&book=0&sf=&remember=1"); curl_setopt($ch, CURLOPT_COOKIEFILE, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt'); $result = curl_exec($ch); echo $result; А то в браузер не выводится. Еще раз спасибо))
C мемори все хорошо получилось. А теперь вот тренеруюсь на другом сайте. Зарегистрировался, зашел на страницу добавления. Заголовок HTML: HTTP/1.1 200 OK Server: nginx/0.6.32 Date: Tue, 28 Oct 2008 13:43:39 GMT Content-Type: text/html Connection: close X-Powered-By: PHP/5.2.4 Content-Length: 4672 И все нормально, пока пост запрос не посылаю. Как только пост запрос идет, то пишет "пожалуйста зарегистрируйтесь". Я так понял, есои какая то переменная чему то равна, то я не зарегистрированный. Я сохранил страницу у себя, изменил post на get и добавил сообщение. выдал вот что PHP: note=0&url=11hhhh11&title=11111&desc=1111111&tags=11111&status=ALL&save=1&do_post=%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD В чем пожет быть подвох?
Круто! Там <input class=button type=submit name="do_post" value="Добавить" tabindex="9" > оказывается проверяется значение do_post, если его нету, то куки не даются =)
хм.. статья вроде называется "Пишем спам-бот/авторассыльщик/брутфорс на Php + cURL" вот только что то я не увидел тут ни спам бота, ни авторассыльщика, ни брутфорсера... имхо, просто ман по курлу...
Еще вопросик 1. Code: HTTP/1.1 200 OK Date: Thu, 06 Nov 2008 19:05:51 GMT Server: Apache Set-Cookie: wongsession=3d356bc2c9511305c17d0ad40d654b97; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: user_name=bobpbI; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_hash=072bebc157b072ce7d075be7ea5f9608; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: key_id=Ym9icGJJ; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_name=bobpbI; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_hash=072bebc157b072ce7d075be7ea5f9608; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8 вот такой заголовок возвращает, когда автарезировался Code: Set-Cookie: user_name=bobpbI; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_hash=072bebc157b072ce7d075be7ea5f9608; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: key_id=Ym9icGJJ; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_name=bobpbI; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Set-Cookie: user_hash=072bebc157b072ce7d075be7ea5f9608; expires=Fri, 06-Nov-2009 19:05:51 GMT; path=/ Надо все куки выдергивать?Или только эту? PHP: $sess_cookie=substr($result, strpos($result, "wongsession=")+12, 32); Потому что проблемма такая. Авторизировался, а при переходе на другую страницу пишет что сессия закончена =( Подскажите пожалуйста.
PHP: function pregCookie($headers) { preg_match_all('#Set-cookie: (.*;)#UiS',$headers,$headers); return implode('',$headers['1']); } Парсер всех кук из заголовков(возвращает string). Используйте.
Спасибо, только я несовсем тогда понимаю. Если пользоваться функцией substr, то мы вырезаем сам код f54aac52317d9697f745548af2dabe87 а если вашей функцией пользоваться, то в таком выде wongsession=f54aac52317d9697f745548af2dabe87; усли я правильно понял, то использовать так надо? curl_setopt($ch, CURLOPT_COOKIE, pregCookie($result)); В любом случае пишет что ваша сессия закончена. =(
PHP: function pregCookie($headers) { preg_match_all('#Set-cookie: (.*;)#UiS',$headers,$headers); return implode('',$headers['1']); } $url = "http://www.mister-wong.ru/index.php?action=login"; $ch = curl_init(); $post="iid=&user_name=login123&user_password=123123&login=%E2%EE%E9%F2%E8"; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIEFILE, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); $result = curl_exec($ch); $hash_hidden=substr($result, strpos($result, 'type="hidden" name="hash" value="')+33,32); $recommended_bmid_hidden=substr($result, strpos($result, 'type="hidden" name="recommended_bmid" id="bookmarkRecommend_bmid" value="')+33,74); $utf8check_bmid_hidden="ö"; $check_hidden="recommend"; $post='hash=$hash_hidden&recommended_bmid=$recommended_bmid_hidden&utf8-check_bmid=$utf8check_bmid_hidden&check=$check_hidden'; $sess_cookie=pregCookie($result); //сформировали строку пост данных состоящую из пар поле=>значение разделенных амперсандом (при необходимости строку надо url-кодировать) curl_setopt($ch, CURLOPT_URL, "http://www.mister-wong.ru/add_url/"); //адрес на который шлем запрос (выдираем значение из action нашей формы) curl_setopt($ch, CURLOPT_HEADER, 1); //дальше мы все уже видели curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // curl_setopt($ch, CURLOPT_COOKIEFILE,$sess_cookie); curl_setopt($ch, CURLOPT_COOKIE, $sess_cookie); //а вот тут внимательнее! не забываем показать серверу наши, полученные ранее кукисы curl_setopt($ch, CURLOPT_POST, 1); //говорим что у нас есть POST данные для сервера curl_setopt($ch, CURLOPT_POSTFIELDS, $post); //указываем на наши POST данные $result = curl_exec($ch); //выполняем запрос на сервер //echo $sess_cookie; echo $result; Может что не так делаю? Регистрация же проходит
3me9I, так попробуй PHP: curl_setopt($ch, CURLOPT_COOKIEFILE, "./cook"); curl_setopt($ch, CURLOPT_COOKIEJAR, "./cook"); }{0TT@БЬ)Ч_68, вот тебе. Это не спам бот, а просто автореггер (стебался над теми идиотами). Спам бот работает абсалютно так же. Вот: PHP: <?php set_time_limit(0); $limit = 10000; for ($i = 1; $i < $limit; $i++){ $ua = 'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)'; $url = 'http://traff2money.info/'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $res = curl_exec($ch); curl_setopt($ch, CURLOPT_URL, "http://traff2money.info/reg.php"); curl_setopt($ch, CURLOPT_REFERER, "http://traff2money.info/"); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $res = curl_exec($ch); curl_close($ch); preg_match('#http:\/\/(.*?)<br>#', $res, $link); $a = $link[1]; $fp = fopen("log.php","a"); fwrite($fp, "$a\r\n"); fclose($fp); } ?> Только в спамерах просто еще постзапросы присутсвуют =\
Народ, спасибо всем за инфо, которую здесь прочитал. Написал такой код (на оптимальность не претендует, еще будет оптимизироваться): PHP: <? $key = 1; function geturl($url,$postdata=0,$header=0,$additional_key=0) { $poststr=""; if ($postdata) while (list($name,$value)=each($postdata)){ if (strlen($poststr)>0) $poststr.="&"; $poststr.=$name."=".urlencode($value); } // инициализация сеанса $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // Формируем заголовок if ($header){ curl_setopt($ch, CURLOPT_HEADER, 1); // Помним кукисы $user_cookie_file = $_SERVER['DOCUMENT_ROOT'].'/poster/cookies.txt'; curl_setopt($ch, CURLOPT_COOKIEFILE, $user_cookie_file); curl_setopt($ch, CURLOPT_COOKIEJAR, $user_cookie_file); curl_setopt($ch, CURLOPT_NOBODY, 1); }else{ curl_setopt($ch, CURLOPT_HEADER, 0); } if ($postdata){ curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)"); $user_cookie_file = $_SERVER['DOCUMENT_ROOT'].'/poster/cookies.txt'; curl_setopt($ch, CURLOPT_COOKIEFILE, $user_cookie_file); curl_setopt($ch, CURLOPT_COOKIEJAR, $user_cookie_file); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $poststr); } curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $res = curl_exec($ch); if ($additional_key){ /* Скрытое поле token для memori */ if( preg_match('/name=\"token\" value=\"(.+?)\"/', $res, $out) ){ $res = $out[1]; } } curl_close($ch); return $res; } if (!isset($_GET['go'])) { // Собираем заголовок $header = geturl('http://memori.ru/registration/',0,1); // Берем значение скрытого поля $token = geturl('http://memori.ru/registration/',0,0,1); // Берем капчу $captcha = geturl('http://memori.ru/captcha/',$postdata); $im = imagecreatefromstring($captcha); $pic_name = time().'_'.$key.'.jpg'; imagejpeg($im, $pic_name, 100); // Сохраняем картинку у себя (подобие антикапчи) $postdata = array( 'method' => 'base64', 'key' => $key, 'body' => $pic_name, 'ext' => 'png' ); $rev = geturl("http://localhost/poster/in.php",$postdata); // регистрируем капчу у себя в системе if (substr($rev,0,2)=='ok'){ //получаем id капчи в системе $anti_captcha_id = substr($rev,3); }else{ echo "Upload ERROR"; echo $rev; exit; } echo '<img src="pic.php?id='.$anti_captcha_id.'">'; echo '<br /><form method="get"><input type="hidden" name="go" value="go"><input type="hidden" name="token" value="'.$token.'">Капча: <input type="text" name="captcha"><br /> Сессия: <input type="text" name="bobrologin" value="'.$session.'"><br /><input type="submit" value="Ну, была не была!"></form>'; } else { echo $captcha = $_GET['captcha']; echo '<br />'; echo $session = $_GET['session']; echo '<br />'; echo $token = $_GET['token']; echo '<br />'; $postdata = array( "login" => "testerqwerty23", "email" => "[email protected]", "inviter" => "", "token" => $token, "captcha" => $captcha, "password" => "123456", "password_confirm" => "123456", ); echo '<pre>'; print_r($postdata); echo '</pre>'; $recdata = geturl('http://memori.ru/registration/',$postdata); echo '<base href="http://memori.ru">'; echo $recdata; if (is_file('./cookies.txt')) unlink('./cookies.txt'); } ?> на всякий случай in.php: <?php //echo '<pre>'; print_r($_POST); echo '</pre>'; $filename = 'user_'.$_POST['key'].'.txt'; if (is_file($filename)) unlink($filename); $status = 'ok'; if ($status == 'ok') { $id = 1; $handle = fopen($filename, 'a'); if (is_writable($filename)) { fwrite($handle, $id.'|'.$_POST['body']); } fclose($handle); echo $status.'|'.$_POST['body']; } ?> pic.php: <? header('Content-Type: image/jpeg'); $im = imagecreatefromjpeg($_GET['id']); imagejpeg($im, NULL, 100); ?> Но форма на мемори остается глухой к такому запросу, т.е. не выводится ни сообщений об ошибках, ни об удачном завершении регистрации. На некоторых других формах такой скрипт отрабатывал. Кто нибудь может подсказать в чем дело?