Сьогодні один перловщик запитав мене, чи не можна в PHP через suEXEC що-небудь і як-небудь запустити. Штудіювання мінлива показало, що ні, ніяк не можна. І це добре, мабуть… Однією діркою менше.
Зате в мануалі по PHP крім функцій exec system, про які я давно знав і начебто їх заборонив у себе на сервері, я знайшов ще функцію popen. Я насторожився, тому що точно пам’ятав — цієї функції я в налаштуваннях PHP не забороняв!
Тут же з мануала був скопійований і запущений приклад. Результат здивував…. Оголошень більшості папок сервера, вміст /etc/passwd, doc_root чужих віртуальних серверів… Все це постало перед моїм поглядом ?
Ось приклади:

Мені це не сподобалося і я поліз в конфіг Апача httpd.conf. У список disabled_functions я дописав popen, перезапустился… Нульовий результат. Спробував викликати функцію exec — викликається.

Шоковий стан…

Таким чином можна зробити?
Багато. Справа в тому, що PHP запускається з правами Апача. А тим часом, Апач має доступ до ВСІХ файлів ВСІХ віртуальних хостів. Така необхідність, інакше він не міг би їх відображати і віддавати клієнтам. Відповідно, їх можна видалити. Цього замало, щоб вважати цю дірку критичною?

Я не знаю, як справи йдуть у великих хостерів, але чомусь мені здається, що у 50% ця дірка є.

Як же все-таки заборонити користувачам віртуального хостингу через PHP робити гидоти, а саме:
A) Читати чужі файли з чужих папок
B) Викликати будь-які системні функції

Пункт A
За першим пунктом все виявилося просто. Не треба включати ніякої Safe Mode, заради бога. Це зло. Це дуже-дуже незручно і погано. Тим більше, є методи простіше.
Віртуальний хост в Апачі створюється директивою . Це природно, що для кожного віртуального хоста ви вказуєте DocumentRoot. Ну так давайте ж зробимо так, щоб скрипти, запущені з під цього віртуального хоста не могли читати файлу нізвідки, крім як з DocumentRoot’а. А ще, давайте зробимо так, щоб сесії для кожного віртуального хоста зберігалися в окремих папках. Це теж логічно, навіщо ж все перемішувати?

Додайте в секцію наступні рядки

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/

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»

Це мінімум. Я не впевнений, що це все. Я з 90% ймовірністю можу увтерждать, що ні один системний виклик на сервері не пройде. А ось яку-небудь гидоту напевно можна зробити.