• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья (RCE) Flask + Werkzeug генерируем куку на основе PIN кода

00429ca224699ddf60ce05b46ef08709.jpeg


Предисловие и карма
Впервые, с задачей генерации PIN кода я столкнулся во время прохождения лаборатории у Offensive, за день перед экзаменом OSCP. Мне было жутко лень решать машину Reconstruction, так как за спиной было много проделанной работы и я был почти уверен, что сдам экзамен, но на душе оставалось ощущение, что с данной задачей я еще встречусь. Так и произошло. В ходе противостояния The Standoff было не менее 5 машин, точкой входа для которых как раз была генерация PIN и удаленное выполнение Python кода через консоль Debug мода.

В процессе противостояния The Standoff данный вектор пыталось эксплуатировать множество команд, что привело к постоянной блокировке панели ввода PIN кода. Основная задача была – найти способ обойти ограничения на количество неудачных попыток ввода PIN кода, что удалось сделать моему коллеге.


Генерация PIN кода
Flask
— это Framework для создания веб-приложений на языке программирования Python, использующий набор инструментов Werkzeug.

Когда веб-сервер запущен с включенным Debug mode, в случае ошибки справа располагается иконка консоли (или необходимо перейти в веб-директорию console), где можно выполнять Python код, однако для этого необходимо предоставить PIN, генерируемый при старте веб-сервера.

1.png


Код генерации PIN находится в файле __init__.py, который может располагаться в следующих директориях:
/usr/local/lib/python*/site-packages/werkzeug/debug/__init__.py​
/usr/local/lib/python*/dist-packages/werkzeug/debug/__init__.py​
~/.local/lib/python*/site-packages/werkzeug/debug/__init__.py​
~/.local/lib/python*/dist-packages/werkzeug/debug/__init__.py​

За генерацию PIN отвечает метод get_pin_and_cookie_name(). Сам код генерируется на основе данных из массивов probably_public_bits и private_bits. При наличии уязвимости, позволяющей читать локальные файлы системы, можно собрать необходимые данные и сгенерировать собственный PIN код.

2.png


Необходимые данные для генерации PIN кода:
probably_public_bits[0] – пользователь, который запустил веб-сервер (анализируем /etc/passwd)​
probably_public_bits[1] – по умолчанию flask.app
probably_public_bits[2] – по умолчанию Flask
probably_public_bits[3] – абсолютный путь к файлу app.py во flask директории, данное значение можем найти из ошибки в Debug mode (/usr/local/lib/python3.6/dist-packages/flask/app.py)​

3.png


private_bits[0] – MAC адрес сетевого интерфейса (/sys/class/net/<INTERFACE>/address), который необходимо перевести в десятичную систему счисления.

4.png


private_bits[1] – machine id, можно получить из файла /etc/machine-id, также необходимо прочитать файл /proc/self/cgroup, если в первой cтроке после крайнего слеша будет некоторое значение, то его необходимо добавить к machine id, иначе используем только machine id.

5.png


Для генерации собственного PIN кода можно использовать следующий скрипт:

Однако, генерация PIN может немного различаться под разные версии Python. В моем случае основное отличие заключалось в различных алгоритмах хеширования. Рекомендую сравнить код метода get_pin_and_cookie_name() из файла __init__.py уязвимой машины с вашим кодом для генерации PIN, если это возможно.

6.png


Сгенерировав собственный PIN, вводим его и получаем доступ к консоли, где производим удаленное выполнение Python кода.

7.png


Генерация Cookie и обход ограничений
При превышении количества неудачных попыток ввода PIN, панель блокируется и спасти в данной ситуации может только рестарт веб-сервера.

8.jpg


Однако, если просмотреть запрос на выполнение Python кода, можно заметить некоторую куку, которая была присвоена после ввода легитимного PIN.

9.png


Данная кука является уникальной и состоит из трех частей:​
  • имя: __wzd4db50c13a80774d469cb, которое генерируется на стадии генерации PIN в методе get_pin_and_cookie_name();​
10.png
  • время: 1623743328, количество секунд с 1 января 1970 00:00:00 UTC минус високосные секунды;​
11.png
  • посоленный хешированный легитимный PIN: за генерацию данного значения отвечает функция hash_pin(), по умолчанию соль прописана в теле функции и равна “shittysalt”;​
12.png


Получается, для генерации собственной куки, которая позволит сразу перейти к этапу выполнения Python кода даже если панель ввода PIN заблокирована, необходимо сгенерировать легитимный PIN и вызвать функцию hash_pin() для генерации 3-тей части куки, которая не известна.

13.png


14.png


Далее перехватываем запрос на ввод любого PIN кода, заменяем GET параметр pin на frm=0 и добавляем сгенерированную нами куку.

15.png


В результате получаем удаленное выполнение Python кода обойдя заблокированную панель ввода PIN.

16.png


Ссылка на скрипт для генерации PIN кода и куки:

Платная лаборатория с только новыми тачками от Offensive (рекомендую для тех кто планирует сдать OSCP):

Дополнительную информацию по генерации PIN можно найти перейдя по ссылкам:
 

ripmandin

Red Team
13.03.2020
38
147
BIT
6
Отличная статья! Как нашел этот способ? Сам разреверсил flask движок или где-то прочитал?
 

explorer

Platinum
05.08.2018
1 080
2 470
BIT
0
Отличная статья! Как нашел этот способ? Сам разреверсил flask движок или где-то прочитал?

Ничего здесь реверсить не нужно, исходный код открытый. Топикстартер просто написал реализацию с argparse. В конце статьи есть некоторые ссылки.
 
  • Нравится
Реакции: gl0ckchan

WiIson

Grey Team
22.06.2020
3
60
BIT
6
Отличная статья! Как нашел этот способ? Сам разреверсил flask движок или где-то прочитал?
Именно эту реализацию я не сам нашел, написал в статье, что коллега откопал пока мы совместно пытались генерировать легитимные PIN коды. А вообще как по мне тут несколько векторов как можно найти это: 1. Можно обратить внимание на куку, которая присваивается при вводе легитимного PIN кода и попробовать поискать в коде процесс ее генерации, код не сложный, понять откуда что идет легко. 2. Читая код, чтобы сгенерировать корректно PIN код, там хочешь не хочешь нарвешься на генерацию куки, ну и имена переменных, методов и функций сами за себя говорят, главное чтобы в голову пришла мысль "а вдруг получится".
 
  • Нравится
Реакции: Edmon Dantes и ripmandin
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!