TwoMillion

TwoMillion is an Easy difficulty Linux box that was released to celebrate reaching 2 million users on HackTheBox

Iniziamo verificando che la macchina sia up e che risponda. Una volta fatto ciò proseguiamo verificando quali siano le sue porte aperte. Attraverso un semplice comando nmap del tipo

nmap -sC -sV <indirizzoIP>

Ci verranno mostrate le due seguenti porte aperte

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Per poter visitare il sito web andiamo ad aggiungere al file etc/hosts l'indirizzo ip con il suo domain name

echo "10.10.11.221 2million.htb" > /etc/hosts

Una volta fatto ciò ci troveremo all'interno del sito web. Esplorandola le varie pagine ci troveremo davanti alla pagina /invite

In questa pagina è possibile iscriversi al sito solo tramite codice di invito. Il sito ci suggerisce "Feel free to hack your way in :)", ed è proprio quello che faremo.

Come prima cosa analizziamo i contenuti della pagina e andiamo alla ricerca del file javascript contenente la funzione che effettua la verifica del codice di invito. Tra i file javascript troviamo quello chiamato inviteapi.min.js.

L'estensione del file ci suggerisce che il suo contenuto è offuscato/minificato, ma è comunque possibile cercare le stringhe nel codice che potrebbero rappresentare delle funzioni. Per comprendere meglio il codice, è possibile abbellire il codice JavaScript minificato utilizzando strumenti come de4js.

Inserendo il codice ed effettuando l'auto decode otterremo le due seguenti funzioni

function verifyInviteCode(code) {
    var formData = {
        "code": code
    };
    $.ajax({
        type: "POST",
        dataType: "json",
        data: formData,
        url: '/api/v1/invite/verify',
        success: function (response) {
            console.log(response)
        },
        error: function (response) {
            console.log(response)
        }
    })
}

function makeInviteCode() {
    $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/v1/invite/how/to/generate',
        success: function (response) {
            console.log(response)
        },
        error: function (response) {
            console.log(response)
        }
    })
}

Con sorpresa vediamo che esiste una funzione che genera un codice di invito e che effettua una richiesta POST all'indirizzo /api/v1/invite/how/to/generate. Scopriamo inoltre che, come spesso accade per le API, le richieste sono effettuate trasmettendo ed ottenendo dati in formato JSON.

Da terminale procediamo quindi ad effettuare una richiesta di questo tipo e analizziamo il risultato

Ci viene restituito nel campo data un testo cifrato e ci veiene anche suggerito il tipo di cifratura, ovvero ROT13. A questo punto procediamo a decifrarlo con un qualsiasi tool online. Il risultato è il seguente:

Procediamo quindi ad effettuare una nuova richiesta POST al seguente indirizzo e analizziamo il risultato

In questo caso ci viene fornito un altro codice cifrato che sembra essere base64. Provando a decifrarlo otteniamo infatti, finalmente, il nostro codice di invito: 4Z9YZ-S1BUX-9C872-PWXF0.

Una volta creato il nostro account esploriamo la nostra home alla ricerca di qualcosa che ci possa essere utile. Vediamo che, tra le molte pagine presenti nella homepage, pochi di questi reindirizzano ad una pagina.

Le pagine accessibili sono:

  • Rules

  • Change log

  • Access

Tra queste tre, l'unica non contenente solamente testo ma anche elementi interagibili è /access.

All'interno di questa pagina sono presenti due bottoni che ci permettono di generare e scaricare il file VPN relativo al nostro account.

Analizzando il funzionamento dei bottoni e delle richieste effettuate, tramite Burpsuite o semplicemente tramite il nostro browser, è possibile vedere come questi effettuino una richiesta GET a /api/v1/users/vpn/generate. Proviamo ad effettuare una richiesta ad /api e analizziamo il risultato.

Possiamo vedere come il server ci risponda con un 401 Unauthorized. Procediamo quindi con fornire alla richiesta il nostro cookie di sessione e ripetiamo la richiesta

Così facendo abbiamo ottenuto informazioni riguardo gli endpoint API, tra cui tre relativi a funzioni di admin. Tra questi risalta all'occhio /api/v1/admin/settings/update. Come suggerito, questo endpoint accetta solamente richieste PUT. Se provassimo, invece, ad effettuare richieste agli altri due endpoint riceveremmo come risposta401 Unauthorized.

Proviamo quindi ad effettuare una richiesta con metodo PUT e vediamo il risultato

Bene, non ci viene restituito il solito 401 Unauthorized, però ci viene detto che il tipo del contenuto non valido. Questo però è normale, visto che, come visto prima, il contenuto della richiesta era in formato JSON.

Cambiamo quindi l'header della richiesta e vediamo come cambia la risposta

Finalmente la richiesta viene accettata ma ci viene indicato che manca un parametro, quello dell'emai. Ricostruiamo il messaggio fornendo anche i dati in formato JSON tramite parametro -d . Ripetendo il comando ci viene indicato un nuovo parametro mancante, ovvero is_admin. Passando vari valori scopriamo che accetta solo 0 e 1 come valori. Costruiamo finalmente il comando completo

Verifichiamo di avere le autorizzazioni da admin utilizzando l'endpoint specifico

Foothold

Trovato il "punto d'appiglio" per entrare nel sistema, procediamo. Innanzitutto proviamo a generare il file VPN per l'utente admin tramite il seguente comando completo.

Il file viene creato correttamente. Ci si chiede se questa viene generata tramite la funzione PHP execo system e, nel caso, se ci siano o meno misure di verifica per filtrare quanto passatogli. Verifichiamo questa ipotesi iniettando il comando ;pwd; dopo il nome utente.

Ottimo, non c'è alcun tipo di filtro su quanto passatogli durante la chiamata. Mettiamoci in ascolto sulla nostra macchina tramite comando

Scriviamo il payload per la reverse shelle e inviamolo nella richiesta.

Questo comando non ci da alcune risposta per cui codifichiamo il payload in base64 e riproviamo

Siamo dentro. Da qui la prima cosa che facciamo e verificare dove ci troviamo e quali sono i file presenti.

Notiamo il file .env, normalmente utilizzato nelle applicazioni PHP per memorizzare i valori delle variabili d'ambiente. Vediamo cosa c'è dentro

Sembrano essere informazioni riguardando un DB chiamato htb_prod con annesse credenziali per un account di amministrazione chiamato admin. Vediamo se le stesse credenziali possono essere usate per effettuare il login tramite shh

Sulla macchina, invece, procederemo ad utilizzare l'exploit tramite i seguenti comandi

La compilazione tramite make all da alcuni warning, ma nulla di preoccuparci. Una volta eseguiti tutti i comandi proviamo ad usare il comando id e verifichiamo che abbiamo i permessi di root

Last updated