Песнь о багах в PHP или админ в шкуре скрипт-кидди Как обезопасить свой сервер с PHP

Loh Matov (blabl@7350.org)

Xakep, номер #050, стр. 050-066-3


/file.php?file=aaaaaaaaaaaaaaaaaaaaаааааааа

Если скрипт уязвим, то ответом будет предупреждение о том, что не удается подключить файл:

Warning: Failed opening 'aaaaaaaaaaaaaaaaaaaa' for inclusion (include_path='.:/usr/local/php-4.2.3/lib/php') in /opt2/home3/prop/public_html/file.php on line 7

В PHP до версии 4.0.3pl1 включительно была такая бага, как null-byte. Это должно быть всем знакомо еще со времен родного перла. После того, как о ней сообщили, ошибка была исправлена. В некоторых функциях она сохранилась и в более поздних версиях. Это возможно и сейчас, но "эксплоитировать" их очень сложно... При старом PHP такая ошибка реализовывается крайне просто. Допустим, на сервере есть скрипт с куском кода такого плана (порывшись в сырцах php-nuke, найдешь много подобного):

<?

..

fopen("$file.php");

?>

Переменная $file не определена ранее и передается как параметр, то есть мы можем ее задать как script?file=../../../../../../etc/passwd%00, получится строка:

<?

..

fopen("../../../../../../etc/passwd%00.php");

?>

Соответственно, открывается файл с пользователями этого сервера вместо скрипта. До сих пор очень много серверов используют старые версии пхп, скорее всего это ленивые админы. Я даже видел пхп версии 2.0. А если попался ленивый админ, то задача еще более упрощается.

Теперь о сочетании функций eval(), print() и echo(). Функция eval() появилась в пхп3, она представляет текст в виде кода, который затем исполняется. Это важно в тех случаях, когда кусок кода хранится в базе данных. В php3 она не возвращает ничего. В php4 она возвращает NULL, если код ничего не возвращает. Чем нам полезна эта функция? А тем, что это потенциальная дыра, code injection, как и с функцией include(), только несколько другого плана. Вот пример из phpBB 1.4:

<example code from page_header.php>

if ($new_message != 0) {

eval($l_privnotify);

print $privnotify;

}

</end example code>

Переменная $l_privnotify не определена ранее, а значит, мы можем определить ее в параметрах, передаваемых к скрипту, scripts.php?l_privnotify=phpinfo(). Функция phpinfo() выдает все, что нужно для успешной атаки.

Вплоть до предпоследней версии PHP(4.2.2), существует ошибка, исправленная только в 4.2.3. Суть ее состоит в том, что можно обойти "safe mode" и выполнить произвольный код без ограничений "safe mode". Ошибка находится в пятом аргументе функции mail(). Эксплоит можно найти на security.nnov.ru. Вообще, пятый аргумент функции mail() используют достаточно редко, и здесь я привожу эту ошибку только для того, чтобы оградить тебя от этой досадной ошибки и помочь сделать код более безопасным.

Еще один путь обхода "safe mode". Ошибка содержалась в функции getpw() и ей подобных. Эта функция показывает имя пользователя по его UID, но она не проверяет, включен ли режим "safe mode" и ограничение на выход из домашней директории пользователя open_basedir. Вот простой кусок кода, который покажет всех пользователей в системе:

Назад на стр. 050-066-2  Содержание  Вперед на стр. 050-066-4