Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Подделка cookies и сессий
 
 автор: Sfinks   (03.11.2005 в 06:58)   письмо автору
 
 

Это продолжение темы "Подделка реферера"

to cheops:
> Нет, но могу рассказать как cookie опрашивать и отправлять потом в
> HTTP-заголовках :))). Т.е. как поддерживать заставить скрипт поддерживать
> cookie и сессии
Ну не томите уже =))))))))))))))))))))))))))))))))

   
 
 автор: cheops   (03.11.2005 в 13:39)   письмо автору
 
   для: Sfinks   (03.11.2005 в 06:58)
 

Я приведу здесь два примера: подделка cookies и подделка сессии (SID) средствами PHP, которые наряду с другими примерами будут подробно рассмотрены в нашей новой книге "PHP-головоломки для хакера", которая выйдет в 2006 году. Книга построена по принципу задачника - можно решать задачи и создавать собственную библиотеку интересных и эффективных скриптов, а можно сразу воспользоваться ответами, если допустим нет времени решать их.

Пусть имеется скрипт, который проверяет наличие cookie, установленной у посетителя при аутентификации. В cookie name устанавливается имя пользователя, а в установленные cookie admin, editor и user, позволяют провести авторизацию для администратора, редактора и пользователя, соответственно.
<?php
  
if(isset($_COOKIE['name']))
  {
     if(isset(
$_COOKIE['admin']))
     {
        echo 
"Здравствуйте, администратор $_COOKIE[name] !<br>";
     }
     if(isset(
$_COOKIE['editor']))
     {
        echo 
"Здравствуйте, редактор $_COOKIE[name] !<br>";
     }
     if(isset(
$_COOKIE['user']))
     {
        echo 
"Здравствуйте, пользователь $_COOKIE[name] !<br>";
     }
  }
?>

Подделать cookie можно отослав HTTP-заголовок следующего формата:
Cookie: name1=value1; name2=value2; …

где name1, name2 и т.д. имена cookie, а value1, value2 и т.д их значения. Данную операцию можно выполнить при помощи браузера, позволяющего редактировать cookie или специализированных программ. Мы выполним подделку при помощи PHP-скрипта, который будет отсылать запрос и получать ответ от сервера при помощи сокетов. Скрипт, осуществляющий авторизацию с правами администратора, представлен ниже.
<?php
  $hostname 
"localhost";
  
$path "/test/1.php";

  
// Устанавливаем соединение, имя которого
  // передано в параметре $hostname
  
$fp fsockopen($hostname80$errno$errstr30); 
  
// Проверяем успешность установки соединения
  
if (!$fp) echo "$errstr ($errno)<br />\n"
  else
  { 
    
// Формируем HTTP-заголовки для передачи
    // его серверу
    
$headers "GET $path HTTP/1.1\r\n"
    
$headers .= "Host: $hostname\r\n"
    
// Подделываем cookie
    
$headers .= "Cookie: name=cheops; admin=1;\r\n";
    
$headers .= "Connection: Close\r\n\r\n"
    
// Отправляем HTTP-запрос серверу
    
fwrite($fp$headers); 
    
// Получаем ответ
    
while (!feof($fp))
    { 
      
$line .= fgets($fp1024); 
    } 
    
fclose($fp); 
  } 
  echo 
$line;
?>

Теперь не составляет труда авторизоваться с правами редактора и пользователя. Достаточно заменить имя cookie admin на editor или user. Более того, в условиях скрипта можно произвести авторизацию одновременно для всех трёх видов пользователей. Для этого достаточно отправить HTTP-заголовок:
Cookie: name=cheops; admin=1; editor=1; user=1;\r\n

   
 
 автор: cheops   (03.11.2005 в 13:44)   письмо автору
 
   для: Sfinks   (03.11.2005 в 06:58)
 

Пусть имеется HTML-форма index.php, прошитая сессией
<?php
  
// Инициируем сессию
  
session_start();
?>
<table>
   <form action=handler.php method=post>
   <input type=hidden name=session_id value='<?= session_id(); ?>'>
   <tr>
     <td>Имя:</td>
     <td><input type=text name=name></td>
   </tr>
   <tr>
     <td>Пароль:</td>
     <td><input type=password name=pass></td>
   </tr>
   <tr>
     <td>&nbsp;</td>
     <td><input type=submit value='Войти'></td>
   </tr>
   </form>
</table>

а её обработчик handler.php имеет следующий вид
<?php
  
// Инициируем сессию
  
session_start();
  
// Текущий SID и переданный из HTML-формы не совпадают,
  // останавливаем работу скрипта
  
if($_POST['session_id'] != session_id()) exit();
  if(
$_POST['name'] == 'admin' && $_POST['pass'] == 'admin')
  {
     echo 
"<br><br>Письмо отправлено<br><br>";
     @
mail("admin@somewhere.ru""Статистика""тело письма");
  }
?>

Т.е. просто поместив HTML-форму на стороннем хосте воспользоваться сервисом не удастся, так как HTML-форма прошита сессией. Необходимо получить сессионную cookie сессии и отправить её обработчику.
Для того чтобы получить cookie, а затем отправить её серверу, необходимо воспользоваться сокетами. Сессионная cookie устанавливается при помощи HTTP-заголовка
Set-Cookie: PHPSESSID=d8a29cae8e9eae318ac19e8d48831dea; expires=Fri, 28 Oct 2005 20:04:05 GMT; path=/

Здесь PHPSESSID — имя сессионной cookie для хранения уникального идентификатора сессии, expires — срок действия cookie, а path — директория действия cookie. При обращении при помощи сокетов, достаточно дождаться строки имеющей данных формат и извлечь SID при помощи регулярного выражения: "|Set-Cookie: PHPSESSID=([\d\w]+);|i". После того, как SID получен можно обращаться к обработчику форму handler.php методом POST.
Метод POST в отличие от метода GET посылает данные не в строке запроса, а в области данных, после заголовков. Передача нескольких переменных аналогична методу GET: группы имя=значения объединяются при помощи символа амперсанда. Учитывая что HTML-форма принимает параметр name=admin, pass=admin и session_id со значением, полученным в первом обращении через сокеты, строка данных может выглядеть следующим образом
name=admin&pass=admin&session_id= d8a29cae8e9eae318ac19e8d48831dea&\r\n\r\n
Последний амперсанд добавляется, чтобы в значение session_id не попали завершающие данные символы перевода строки. При отправке данных методом POST необходимо отправить HTTP-заголовок Content-Length с числом байт в строке данных и HTTP-заголовок Content-type: application/x-www-form-urlencoded, сообщающий метод пересылки данных.
<?php
  $hostname 
"localhost";
  
$path "/test/index.php";

  
// Устанавливаем соединение, имя которого
  // передано в параметре $hostname
  
$fp fsockopen($hostname80$errno$errstr30); 
  
// Проверяем успешность установки соединения
  
if (!$fp) echo "$errstr ($errno)<br />\n"
  else
  { 
    
// Формируем HTTP-заголовки для передачи
    // его серверу
    
$headers "GET $path HTTP/1.1\r\n"
    
$headers .= "Host: $hostname\r\n"
    
$headers .= "Connection: Close\r\n\r\n"
    
// Отправляем HTTP-запрос серверу
    
fwrite($fp$headers); 
    
// Получаем ответ
    
while (!feof($fp))
    { 
      
$line fgets($fp1024); 
      
// Ищем строку вида 
      // Set-Cookie: PHPSESSID=6197e647566bdaa24da3ab42ae7604b2;
      // Именно она устанавливает cookie
      
preg_match("|Set-Cookie: PHPSESSID=([\d\w]+);|i",$line,$out);
      if(!empty(
$out[1]))
      {
        
$SID $out[1];
        break;
      }
    } 
    
fclose($fp); 
  } 

  
$hostname "localhost";
  
$path "/test/handler.php";
  
$line "";

  
// Передаём методом POST имя пользователя (admin),
  // его пароль (admin), скрытое поле session_id ($SID)
  // В заголовках, передаём cookie PHPSESSID
  // Устанавливаем соединение, имя которого
  // передано в параметре $hostname
  
$fp fsockopen($hostname80$errno$errstr30); 
  
// Проверяем успешность установки соединения
  
if (!$fp) echo "$errstr ($errno)<br />\n"
  else
  { 
    
// Данные POST-запроса
    
$data "name=admin&pass=admin&session_id=$SID&\r\n\r\n";
    
// Формируем HTTP-заголовки для передачи
    // его серверу
    
$headers "POST $path HTTP/1.1\r\n"
    
$headers .= "Host: $hostname\r\n"
    
$headers .= "Content-type: application/x-www-form-urlencoded\r\n";
    
$headers .= "Content-Length: ".strlen($data)."\r\n";
    
// Подделываем cookie
    
$headers .= "Cookie: PHPSESSID=$SID;\r\n";
    
$headers .= "Connection: Close\r\n\r\n"
    
// Отправляем HTTP-запрос серверу
    
fwrite($fp$headers.$data); 
    
// Получаем ответ
    
while (!feof($fp))
    { 
      
$line .= fgets($fp1024); 
    } 
    
fclose($fp); 
  } 
  echo 
$line;
?>

PS Только внимательно следите за путями к файлам
<?php
  $hostname 
"localhost";
  
$path "/test/index.php";
?>

   
 
 автор: Sfinks   (04.11.2005 в 21:02)   письмо автору
 
   для: cheops   (03.11.2005 в 13:44)
 

И тем не менее головоолмка продолжается.....
Объясню задачу подробнее.....
По адресу http://www.beonline.ru/portal/comm/send_sms/simple_send_sms.sms имеется форма отправки смс... при загрузке передает такие заголовки:
HTTP/1.1 200 OK
Date: Fri, 04 Nov 2005 17:16:59 GMT
Server: Apache/2.0.49 (Linux/SuSE)
Cache-Control: private
Vary: Accept-Encoding
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Set-Cookie: JSESSIONID=aPtg-lrYsle7; path=/
Set-Cookie: JSESSIONID=amDl8nszl2U_; path=/
Connection: close
Content-Type: text/html; charset=windows-1251
Отправку я сделал.

Далее, после отправки, есть кнопка получения статуса доставки такого вида:
<input type="image" src="status.gif" alt="Статус сообщения"
  onclick="window.open('/status_frame.xsp?id=1014179340&lang=rus', '',
  'scrollbars=0, width=528, height=306'); return false;">

Открывается окно с frameset'ом, в левом фрейме рекла, в правом статус доставки.
Но если открываешь его скриптом, то в окне вместо статуса пишется
"Извините, статус доставки сообщения не может быть получен"

Возвращаемые status_frame.xsp'ом заголовки такие:
HTTP/1.1 200 OK
Date: Fri, 04 Nov 2005 17:20:55 GMT
Server: Apache/2.0.49 (Linux/SuSE)
Vary: Accept-Encoding
Content-Length: 2905
Connection: close
Content-Type: text/html;charset=windows-1251

А открываю я его таким набором заголовков:
<?php
  $id 
$_POST["id"]; // -это выдмраем со страницы ответа на отправку из /status_frame.xsp?id=1014179340&lang=rus
  
$sid $_POST["sid"]; // -это JSESSIONID из первой формы
  
$host "www.beonline.ru";
  
$path "/status.xsp?id=$id&lang=rus"// -тут я обращаюсь не к status_frame.xsp, а к содержимому правого фрейма.
  
$fp fsockopen($host,80,$errno,$errstr,30);
  if(!
$fp) echo"$errstr ($errno)<br />\n";
  else{
    
$headers "GET $path HTTP/1.0\r\n";
    
$headers .= "Host: $host\r\n";
    
$headers .= "Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1\r\n";
    
$headers .= "Accept-Charset: windows-1251, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1\r\n";
    
$headers .= "Accept-Encoding: deflate\r\n";
    
$headers .= "Accept-Language: ru,en;q=0.9\r\n";
    
$headers .= "Referer: http://www.beonline.ru/portal/comm/send_sms/simple_send_sms.sms\r\n";
    
$headers .= "User-Agent: Opera/8.01 (Windows NT 5.1; U; ru)\r\n";
    
$headers .= "Cookie: JSESSIONID=$sid;\r\n";
    
$headers .= "Connection: Close\r\n\r\n";
    
fwrite($fp,$headers);
    
$head "";
    while(
$text != "\r\n"){
      
$text fgets($fp,128);
      
$head .= $text;
    }
    
$text "";
    while(!
feof($fp)) $text .= fgets($fp,4096);
    
fclose($fp);
  }
  echo 
$text;
?>

Так в чем еще может быть проблема?.... Чего еще не хватает?!

   
 
 автор: cheops   (04.11.2005 в 23:39)   письмо автору
 
   для: Sfinks   (04.11.2005 в 21:02)
 

Для отправки сообщения введите код, указанный на картинке

Так там же число на картинке - HTML-форма генерирует изображение - пока вы его не введёте - никаких вам sms. Самый убойный способ против отправителей sms в обход сайта. Причём эту картинку даже не пытайтесь расшифровать, как только вам это удасться, будет созданна новая, которая испепелит ваши усилия.

   
 
 автор: Sfinks   (06.11.2005 в 12:34)   письмо автору
 
   для: cheops   (04.11.2005 в 23:39)
 

Да это решено! Просто таже картинка отображается на моей страничке (http://sendsms.dimok.hostvit.ru) и юзер ее вводит. SMS отправляются без проблем! Проблема дальше с получением статуса сообщения.

   
 
 автор: cheops   (06.11.2005 в 13:24)   письмо автору
 
   для: Sfinks   (06.11.2005 в 12:34)
 

В том то и прелесть, что сервер билайн знать не знает этого кода который вы вводите - ему подавай тот, который сгенерировал его сервис... При генерации формы код на картинке каждый раз разный и скорее всего форма помещает его в сессию - приходите к обработчику - если в сессии код совпадает с тем, что ввёл посетитель - отсылаем sms, если не совпадает - ничего не отсылаем. А данные сессии в отличие от SID подделать уже не получится. Единственный способ - это получить сессию, расшифровать картинку и послать код, который генерируется для этой сессии и приведён на картинке.

   
 
 автор: Sfinks   (06.11.2005 в 22:04)   письмо автору
 
   для: cheops   (06.11.2005 в 13:24)
 

Повторяю еще раз.....
С кодом на картинке все нормально! BeeLine его принимает и смс отправляется и доходит! Я проверял уже 100 раз отправкой смс самому себе.
Проблемы дальше.... Уже на следующей странице..... Когда нажимаешь кнопку "Статус сообщения". И код картинки там уже абсолютно не при делах. Это чисто информационнная страница, на которой пишется тока доставлено, в процессе или не доставлено. И вот этот статус и не читается.
Я это подробно описал в посте от 04.11.2005 в 21:02

   
 
 автор: cheops   (06.11.2005 в 23:35)   письмо автору
 
   для: Sfinks   (06.11.2005 в 22:04)
 

А статус сообщения как извлекается?

   
 
 автор: Sfinks   (07.11.2005 в 01:33)   письмо автору
 
   для: cheops   (06.11.2005 в 23:35)
 

Весь код файла status.php приведен в листинге в конце поста от 04.11.2005 21:02 в этой теме.
Переменные $_POST["sid"] и $_POST["id"] передаются из http://sendsms.dimok.hostvit.ru/send1.php, которые в свою очередь извлекаются из заголовка чтения http://www.beonline.ru/portal/comm/send_sms/simple_send_sms.sms и из урла кнопки статуса /status_frame.xsp?id=1014179340&lang=rus, соответсятвенно.
Прочтите еще раз этот пост (от 04.11.2005 21:02). Я в нем все четко описал, просто Вы не о том вопросе подумали, когда стали отвечать.

   
 
 автор: Sfinks   (07.11.2005 в 01:41)   письмо автору
 
   для: cheops   (06.11.2005 в 23:35)
 

Что примечательно, статус выдается только если нажать кнопку "Статус сообщения" на странице отчета после отправки смс с их сайта. Т.е. даже если напрямую с их сайта отправляешь смс, а затем открываешь исходник отчета, берешь оттуда что-то вроде http://www.beonline.ru/status_frame.xsp?id=1014179340&lang=rus и просто вводишь в строку адреса, то всерн загружается фраза "Извините, статус доставки сообщения не может быть получен", а не действительный адрес.... Но в скрипте я же устанавливаю и куку и реферера.... А результата ноль =((

   
 
 автор: Sfinks   (07.11.2005 в 22:01)   письмо автору
 
   для: cheops   (06.11.2005 в 23:35)
 

cheops, неужели не будет ни каких подсказок?!!!! Я не могу в это поверить!!!
____
Кстати, cheops, Гоша и Игорь Вячеславович - это одно лицо?... Просто интересно =)))))

   
 
 автор: cheops   (08.11.2005 в 00:28)   письмо автору
 
   для: Sfinks   (07.11.2005 в 22:01)
 

А какие HTTP-заголовки эта строптивая страница посылает клиенту?

>Кстати, cheops, Гоша и Игорь Вячеславович - это одно
>лицо?... Просто интересно =)))))
Да.

   
 
 автор: Sfinks   (08.11.2005 в 07:00)   письмо автору
 
   для: cheops   (08.11.2005 в 00:28)
 

simple_send_sms.sms:
HTTP/1.1 200 OK 
Date: Fri, 04 Nov 2005 17:16:59 GMT 
Server: Apache/2.0.49 (Linux/SuSE) 
Cache-Control: private 
Vary: Accept-Encoding 
Expires: Thu, 01 Jan 1970 00:00:00 GMT 
Pragma: no-cache 
Set-Cookie: JSESSIONID=aPtg-lrYsle7; path=/ 
Set-Cookie: JSESSIONID=amDl8nszl2U_; path=/ 
Connection: close 
Content-Type: text/html; charset=windows-1251

status_frame.xsp:
HTTP/1.1 200 OK 
Date: Fri, 04 Nov 2005 17:20:55 GMT 
Server: Apache/2.0.49 (Linux/SuSE) 
Vary: Accept-Encoding 
Content-Length: 2905 
Connection: close 
Content-Type: text/html;charset=windows-1251

   
 
 автор: cheops   (08.11.2005 в 12:18)   письмо автору
 
   для: Sfinks   (08.11.2005 в 07:00)
 

Старнно, а почему он просит браузер установить две куки с одним и тем же именем... Вы первую ставите или обе пробовали? Если ещё вторую не пробовали нужно просто убрать break; при нахождении соответствия Set-Cookie:

   
 
 автор: Sfinks   (09.11.2005 в 07:14)   письмо автору
 
   для: cheops   (08.11.2005 в 12:18)
 

Конечно я уже пробовал и первую и вторую и обе, также как он их пишет.... Без разницы =(

   
 
 автор: cheops   (09.11.2005 в 13:40)   письмо автору
 
   для: Sfinks   (09.11.2005 в 07:14)
 

А я чего-то кнопки статуса не вижу: только получить ответ на e-mail и на сотовый телефон. После отправки тоже ничего...

PS А сами SMS отправляются?

   
 
 автор: Sfinks   (10.11.2005 в 19:39)   письмо автору
 
   для: cheops   (09.11.2005 в 13:40)
 

> А я чего-то кнопки статуса не вижу: только получить ответ на e-mail и
> на сотовый телефон. После отправки тоже ничего...
Нужно на странице отправки поставить флажок на чекбоксе "Отслеживать статус сообщения", тогда после отправки будет эта кнопка.

> А сами SMS отправляются?
Да, отправляются и доставляются.

   
 
 автор: cheops   (10.11.2005 в 23:07)   письмо автору
 
   для: Sfinks   (10.11.2005 в 19:39)
 

Может флажок этот как у вас не отмечается - назван не правильно или ещё что-то в этом духе?

   
 
 автор: Sfinks   (12.11.2005 в 20:43)   письмо автору
 
   для: cheops   (10.11.2005 в 23:07)
 

Да нет, все верно:
$data .= "&status=".urlencode("on");

Меня вот смущают заголовки:
Cache-Control: private 
Vary: Accept-Encoding 
Expires: Thu, 01 Jan 1970 00:00:00 GMT
....из этого ничего не надо передавать?

   
 
 автор: cheops   (12.11.2005 в 23:21)   письмо автору
 
   для: Sfinks   (12.11.2005 в 20:43)
 

1, 3 - ничего не страшного - это для прокси-серверов, сообщают, что содержимое страницы не следует кэшировать. А вот второй вполне какую-нибудь бяку может в ответ требовать... вроде кодирования в base64 вместо urlencode... надо порыться в справочниках и в rfc2616 - что второй заголовок означает...

   
 
 автор: Sfinks   (13.11.2005 в 10:57)   письмо автору
 
   для: cheops   (12.11.2005 в 23:21)
 

Так страница статуса, вроде, вообще открывается GET-запросом.... Там в POST-форме появляется вторая кнопка с урлом типа: /file.xsp?id=xxxxxxxxxx&lang=rus?....
Соответственно, я и в запросе ниче не кодирую, а передаю ток заголовки:
  $host = "www.beonline.ru";
  $path = "/status.xsp?id=$id&lang=rus";
  $fp = fsockopen($host,80,$errno,$errstr,30);
  if(!$fp) echo"$errstr ($errno)<br />\n";
  else{
    $headers = "GET $path HTTP/1.0\r\n";
    $headers .= "Host: $host\r\n";
    $headers .= "Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1\r\n";
    $headers .= "Accept-Charset: windows-1251, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1\r\n";
    $headers .= "Accept-Encoding: deflate\r\n";
    $headers .= "Accept-Language: ru,en;q=0.9\r\n";
    $headers .= "Referer: http://www.beonline.ru/portal/comm/send_sms/simple_send_sms.sms\r\n";
    $headers .= "User-Agent: Opera/8.01 (Windows NT 5.1; U; ru)\r\n";
    $headers .= "Cookie: JSESSIONID=$sid;\r\n";
    $headers .= "Connection: Close\r\n\r\n";

   
 
 автор: cheops   (13.11.2005 в 14:10)   письмо автору
 
   для: Sfinks   (13.11.2005 в 10:57)
 

Да вижу openBrWind(), который просто открывает новое окно... чёрт его знает что ему ещё нужно - вроде всё корректно и правильно...

   
 
 автор: JIEXA   (05.11.2005 в 01:03)   письмо автору
 
   для: cheops   (03.11.2005 в 13:44)
 

отличная информация, спасибо

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования