Старый 22.03.2011, 23:33   #1
d0znpp
 
Аватар для d0znpp
 
Регистрация: 09.09.2010
Сообщений: 485
Репутация: 252
По умолчанию HTTP HEAD method trick in php scripts

https://students.mimuw.edu.pl/~ai292615/php_head_trick.pdf

HTTP HEAD method trick in php scripts
(Tested on php version 5.3.5)

Adam Iwaniuk
March 3, 2011

This article is about behavior of php scripts opened by http HEAD method.
A lot of coders assume that their scripts won't be interrupted and will run to
the end (especially for short scripts). When HEAD method is used, php script
stops on the rst output, what can provide some security holes.
php-5.3.5\main\SAPI.c line 315:
Код:
if (SG(request_info).request_method &&
!strcmp(SG(request_info).request_method, "HEAD")) {
SG(request_info).headers_only = 1;
php-5.3.5\main\output.c line 699
(fucntion php_ub_body_write which is executed when
output data arrives):
if (SG(request_info).headers_only) {
if(SG(headers_sent)) {
return 0;
{
php_header(TSRMLS_C);
zend_bailout(); // <--- this will stop script
{
Simple guestbook based on les script as seen in real world:
PHP код:
<?php
$line
='Nick: '.htmlspecialchars($_POST['nick']).'<br>
Text: '
.htmlspecialchars($_POST['text']).'<hr>';
$f=fopen("book.txt","r");
$data=fread($f,filesize("book.txt"));
fclose($f);
$f=fopen("book.txt","w");
$data=$line.$data;
echo 
$data;
fwrite($f,$data);
fclose($f);
<?
When someone will open that script using HEAD method script will stop on
"echo $data;", so book.txt will be empty.
Another simple example:
Цитата:
<?php
session_start();
$_SESSION['admin']=1;
if (!isset($_POST['pass']) || $_POST['pass']!='somepassword')
}
echo '<b>Wrong or empty password.</b><br>';
$_SESSION['admin_level']=0;
{
<?
In this example, after HEAD method script will stop on:
"echo '<b>Wrong or empty password.</b><br>';"
Variable $_SESSION['admin_level'] will stay set to 1. In a great deal of
servers output_buffering is set to 4096, so rst output will
ush when 4096
bytes will arrive to the buer. In this case vulnerable script should look like
this:
PHP код:
<?php
session_start
();
echo 
'A long string contains about 4090 characters';
$_SESSION['admin']=1;
if (!isset(
$_POST['pass']) || $_POST['pass']!='somepassword')
}
echo 
'<b>Wrong or empty password.</b><br>';
$_SESSION['admin_level']=0;
{
<?
This kind of vulnerabilities are not common, but a lot of scripts may have
interesting behavior when we stop running them in the middle.
d0znpp вне форума   Ответить с цитированием
Старый 23.03.2011, 13:14   #2
Beched
 
Регистрация: 06.07.2010
Сообщений: 364
Репутация: 115
По умолчанию

Что-то пример очень криво написан) С очепятками.
И кстати неясно, что это вот в таком случае даёт, если скрипт всё равно завершает выполнение.

И кстати у меня что-то не вышло.
PHP код:
<?php
session_start
();
echo 
str_repeat('a',5000);
$_SESSION['admin_level']=1;
if (!isset(
$_POST['pass']) || $_POST['pass']!='somepassword')
{
$_SESSION['admin_level']=0;
file_put_contents('asdasdasd.txt','asdasd');
}
?>
Пишу print_r(get_headers('http://localhost/headmethodtest.php'));
Ответ:
Код:
Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Wed, 23 Mar 2011 10:12:13 GMT
    [2] => Server: Apache/2.2.14 (Ubuntu)
    [3] => X-Powered-By: PHP/5.3.2-1ubuntu4.7
    [4] => Set-Cookie: PHPSESSID=tmbb471nlj00hg3n29ccbj7bd5; path=/
    [5] => Expires: Thu, 19 Nov 1981 08:52:00 GMT
    [6] => Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    [7] => Pragma: no-cache
    [8] => Vary: Accept-Encoding
    [9] => Content-Length: 5000
    [10] => Connection: close
    [11] => Content-Type: text/html
)
В итоге скрипт исполнился полностью, ничего не останавливалось. В файлик записался текст.
Beched вне форума   Ответить с цитированием
Старый 23.03.2011, 13:22   #3
Белый Тигр
 
Аватар для Белый Тигр
 
Регистрация: 29.08.2010
Сообщений: 118
Репутация: 25
По умолчанию

Пример описан для HEAD-запроса, а get_headers() отправляет GET-запрос.
Суть в том, что выполнение скрипта при HEAD-запросе обрывается при попытке вывода информации. То есть из примера с сессией видно что 0 в неё записаться просто не успеет.
Белый Тигр вне форума   Ответить с цитированием
Старый 23.03.2011, 13:40   #4
Beched
 
Регистрация: 06.07.2010
Сообщений: 364
Репутация: 115
По умолчанию

Ой, протупил.
Тогда надо вот так запрашивать:
PHP код:
$default_opts = array(
  
'http'=>array(
    
'method'=>"HEAD",
  )
);
stream_context_get_default($default_opts);
print_r(get_headers('http://localhost/headmethodtest.php')); 
Теперь скрипт и правда останавливается.

Надо только найти интересный контекст, где это действительно может пригодиться. Вот пример с гостевой более живой, но деструктивный.
Beched вне форума   Ответить с цитированием
Старый 23.03.2011, 17:24   #5
life_glider
 
Аватар для life_glider
 
Регистрация: 06.07.2010
Сообщений: 43
Репутация: 17
По умолчанию

https://students.mimuw.edu.pl/~ai292615/php_head_trick.pdf
перевод

трюк с методом HEAD протоколоа HTTP в php скриптах
(проверено на php версии 5.3.5)

Adam Iwaniuk
3 марта, 2011


это статья о php скриптах запущенных http HEAD методом.
множество программистов предполагают что из скрипты не будут прерваны и дойдут до конца (especially for short scripts). Когда мы используем метод HEAD, php-скрипт останавливается при первом выводе информацции
, что ведёт к появлению некоторых "дырок".
php-5.3.5\main\SAPI.c line 315:
Код:
if (SG(request_info).request_method &&
!strcmp(SG(request_info).request_method, "HEAD")) {
SG(request_info).headers_only = 1;
php-5.3.5\main\output.c line 699
(fucntion php_ub_body_write which is executed when
output data arrives):
if (SG(request_info).headers_only) {
if(SG(headers_sent)) {
return 0;
{
php_header(TSRMLS_C);
zend_bailout(); // <---здесь скрипт останавливается
{
скрипт простой гостевухи на файлах, которая встречается IRL:
PHP код:
<?php
$line
='Nick: '.htmlspecialchars($_POST['nick']).'<br>
Text: '
.htmlspecialchars($_POST['text']).'<hr>';
$f=fopen("book.txt","r");
$data=fread($f,filesize("book.txt"));
fclose($f);
$f=fopen("book.txt","w");
$data=$line.$data;
echo 
$data;
fwrite($f,$data);
fclose($f);
<?
Когда кто-то откроет этот скрипт через метод HEAD, он остановится на
"echo $data;", и book.txt будет пуст.
Ещё простой пример:

после метода HEAD скрипт остановится на:
"echo '<b>Wrong or empty password.</b><br>';"
Переменная $_SESSION['admin_level'] будет по прежнему иметь значение 1.
в большинстве серверов буферизация вывода(output_buffering) установлена 4096,так первый вывод
произойдёт, когда в буфере окажется 4096 байтов
в данном случае дырявый скрипт будет выглядеть так :
PHP код:
<?php
session_start
();
echo 
'A long string contains about 4090 characters';
$_SESSION['admin']=1;
if (!isset(
$_POST['pass']) || $_POST['pass']!='somepassword')
}
echo 
'<b>Wrong or empty password.</b><br>';
$_SESSION['admin_level']=0;
{
<?
Данный вид уязвимостей не является общим, но много скриптов
могут вести себя по интересному, если мы их остановим посередине.
__________________
Вы все такие классные
life_glider вне форума   Ответить с цитированием
Старый 24.03.2011, 14:06   #6
Raz0r
 
Аватар для Raz0r
 
Регистрация: 17.07.2010
Сообщений: 101
Репутация: 78
По умолчанию

Теоретически возможен такой вариант: имеется SQL-инъекция, с помощью которой можно получить доступ к таблице с пользователями. Так как все пароли зашифрованы и восстановить их по какой-либо причине нельзя, с помощью HEAD-запроса делается ретрив пароля на имейл, при этом код примерно такой:
PHP код:
<?php
$code 
genCode();
$user->updateField('code'$code);
echo 
"Code sent to your email";
$email->send($code);
Важно, чтобы отправка сообщения шла после вывода данных, тогда это позволит записать в БД активационный код и при этом владелец аккаунта ничего не заметит.
Raz0r вне форума   Ответить с цитированием
Старый 24.03.2011, 17:57   #7
Beched
 
Регистрация: 06.07.2010
Сообщений: 364
Репутация: 115
По умолчанию

Ну тут ещё надо чтоб код активации был недостаточно криптостойким, чтоб его можно было угадать. То есть тут метод с HEAD сам по себе никакой новой уязвимости не приносит =)
Beched вне форума   Ответить с цитированием
Старый 24.03.2011, 18:39   #8
Tim
 
Аватар для Tim
 
Регистрация: 24.03.2011
Сообщений: 60
Репутация: 3
По умолчанию

Цитата:
Сообщение от BECHED aka Root-access Посмотреть сообщение
Ну тут ещё надо чтоб код активации был недостаточно криптостойким, чтоб его можно было угадать. То есть тут метод с HEAD сам по себе никакой новой уязвимости не приносит =)
Raz0r же намекнул, что имея sql-инъекцию...
т.е после ретрива можно самому получить ссылку для восстановления пароля..
Tim вне форума   Ответить с цитированием
Старый 24.03.2011, 18:57   #9
Raz0r
 
Аватар для Raz0r
 
Регистрация: 17.07.2010
Сообщений: 101
Репутация: 78
По умолчанию

Цитата:
Сообщение от BECHED aka Root-access Посмотреть сообщение
тут метод с HEAD сам по себе никакой новой уязвимости не приносит =)
по сути да, профит в том, чтобы незаметно сменить пароль (с последующим восстановлением исходного хэша разумеется)
Raz0r вне форума   Ответить с цитированием
Старый 28.06.2012, 11:56   #10
tipsy
 
Аватар для tipsy
 
Регистрация: 10.07.2010
Сообщений: 415
Репутация: 311
По умолчанию

Хм, я писал об этом в теме про LFI через phpinfo()
вот, пункт номер 4
Цитата:
-доказана возможность удалённо завершить программу в произвольной точке, где программа делает вывод.
HEAD не нужен.
Можно тормознуть скрипт в точке, где он делает вывод (echo) заполнением буфера апача, и он (скрипт) будет прерван через [max_execution_time] минут.
Пригодны методы GET, POST.

Условие то же - на момент остановки в буфере должно быть >4кб.

Последний раз редактировалось tipsy; 28.06.2012 в 12:10..
tipsy вне форума   Ответить с цитированием
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2016, Jelsoft Enterprises Ltd. Перевод: zCarot