Сегодня один перловщик спросил меня, а нельзя ли в PHP через suEXEC что-нибудь да как-нибудь запустить. Штудирование мануалов показало, что в случае mod_php нельзя, да и ненужно. Ну а в случае fastcgi — можно. И это хорошо, это безопасно, но сказка не о том, а о mod_php.
В мануале по PHP кроме функций exec и system, про которые я давно знал и вроде бы их запретил у себя на сервере, я нашел еще функцию popen. Я насторожился, потому что точно помнил — этой функции я в настройках PHP не запрещал!
Тут же из мануала был скопирован и запущен пример. Результат... удивил. Листинги большинства папок сервера, содержимое /etc/passwd, doc_root чужих виртуальных-серверов... Все это предстало перед моим взором :-) Конечно, виноват я. suEXEC'а нету, ведь нету же mod_php, да ну и не все файлы стояли с ограничением на чтение от all. Мой промах, признаю.
Вот код примера:
<? if(!isset($q)) { $q = 'ls -alp'; } ?><html>
<body>
<form method="post">
<input type="text" name="q" value="<?=$q?>">
<input type="submit">
</form><pre>
<?php
error_reporting(E_ALL);
$fp = popen($q, 'r');
$read = '';
while (!feof($fp))
{
$read .= fread($fp, 4096);
}
echo $read;
pclose($fp);
?></pre>
</body>
</html>
Мне это не понравилось и я полез в конфиг Апача httpd.conf. В список disabled_functions я дописал popen, перезапустился... Нулевой результат. Попробовал вызвать функцию exec — вызывается.
Шоковое состояние...
Что таким образом можно сделать?
Многое. Дело в том, что PHP запускается с правами Апача. А тем временем, Апач имеет доступ ко ВСЕМ файлам ВСЕХ виртуальных хостов. Такова необходимость, иначе он не мог бы их отображать и отдавать клиентам. Соответственно, их можно удалить. Этого мало, чтобы считать эту дырку критической?
Я не знаю, как дела обстоят у крупных хостеров, но почему-то мне кажется, что у 50% эта дырка есть (проверено на примере во время написания заметки)
Как же все-таки запретить пользователям виртуального хостинга через PHP делать гадости, а именно:
A) Читать чужие файлы из чужих папок
B) Вызывать любые системные функции
- Пункт A
По первому пункту все оказалось просто. Не надо включать никакой Safe Mode, бога ради. Это зло. Это очень-очень неудобно и плохо. Тем более, есть методы проще.
Виртуальный хост в Апаче создается директивой
Добавьте в секцию
<IfModule mod_php4.c>
php_admin_value open_basedir /home/username/
php_admin_value doc_root /home/username/html/
php_admin_value upload_tmp_dir /home/username/tmp/
php_admin_value session.save_path /home/username/tmp/
</IfModule>
mod_php4.c замените на mod_php5.c в зависимости от версии PHP.
В этом примере DocumentRoot этого виртуального хоста:
DocumentRoot «/home/username/html»
Таким образом, первая проблема решена. Попробуйте сделать fopen(«/home/anotheruser/html/hacked.txt»,"a"); — не получится.
- Пункт B
Переходим ко второму пункту.
В данном случае я совершил две ошибки: директиву disable_functions я задал там, где этого делать не стоит; да и список запрещенных функций был ДАЛЕКО неполный.
Не повторяйте мою ошибку, не пытайтесь задавать параметр disable_functions в httpd.conf отдельно для каждого виртуального хоста. У ВАС НИЧЕГО НЕ ВЫЙДЕТ! Это раньше так можно было, наверное... потому что у меня именно так и было, а я об этом где-то как-то прочитал.
disable_functions надо задавать в php.ini. Чтобы узнать, какой php.ini используется у вас, выполните в шелле следующую команду:
php -i | grep ini
И с большой вероятностью вы увидите, где лежит ваш php.ini
В нем, в районе 199 строки есть что-то вроде:
; This directive allows you to disable certain functions for security reasons.
; It receives a comma-delimited list of function names. This directive is
; *NOT* affected by whether Safe Mode is turned On or Off.
disable_functions =
Так вот. Список функций, которые НЕОБХОДИМО ОГРАНИЧИТЬ на виртуальном хостинге:
disable_functions = «popen,dl,set_time_limit,passthru,system,exec,proc_open,shell_exec,proc_close,symlink»
Это минимум. Я не уверен, что это все. Я с 90% вероятностью могу увтерждать, что ни один системный вызов на сервере не пройдет. А вот какую-нибудь еще гадость наверняка можно сделать.
UPD 2006.10.07
К списку опасных функций добавилась symlink.
- Ссылки
- Top 10 ways to crash PHP
Довольно интересная статья. Правда, боюсь, она немного устарела.
5 Comments
Обсудите эту новость на news2.ru.....
...
[...] Памятка начинающим хостерам по затыканию дырок в PHP. Любопытно, это только автору статьи так повезло, или эта «дырка» действительно широко распространена? Я, к сожалению, не специалист в этом вопросе, поэтому прошу помощи у аудитории. Я не знаю, как дела обстоят у крупных хостеров, но почему-то мне кажется, что у 50% эта дырка есть. [...]
А вообще, не исключено, что эта проблема на корню решается использованием php через FastCGI.
Угу. Надо почитать про плюсы и минусы такого решения.
Конечно же, PHP можно запускать через suEXEC.
А для PHP в режиме mod_php можно использовать mod_become и его родственников.
[...] Решение простое. В списку запрещенных функций надо добавить symlink. Как это делалось — можно почитать в моей маленькой памятке по затыканию дыр. Technorati tags: news, php, security [...]
А что насчет запрета ini_set? ini_set ('max_execution_time', 9000); и вуаля!
Интересно :)
Надо потестировать. Ведь таким макаром можно ВСЕ что угодно менять, так?
3 Trackbacks/Pingbacks
Обсудите эту новость на news2.ru.....
...
[...]Памятка начинающим хостерам по затыканию дырок в PHP. Любопытно, это только автору статьи так повезло, или эта «дырка» действительно широко распространена? Я, к сожалению, не специалист в этом вопросе, поэтому прошу помощи у аудитории. Я не знаю, как дела обстоят у крупных хостеров, но почему-то мне кажется, что у 50% эта дырка есть. [...]
[...]Решение простое. В списку запрещенных функций надо добавить symlink. Как это делалось — можно почитать в моей маленькой памятке по затыканию дыр. Technorati tags: news, php, security [...]