hacking

Studio della vuln. CVE-2022-23093 [prima parte]

Qualche giorno fa, durante una live, mi e’ stata ricordata la CVE in oggetto che interessa i sistemi FreeBSD e su cui avevo un po’ riflettuto a livello di potenziale offensivo. La CVE mi era tornata alla mente anche a seguito di una recente vulnerabilita’ che ha interessato l’implementazione di ICMP sui sistemi Microsoft (CVE-2023-23415). Le due vulnerabilita’ sono molto diverse tra loro: lato FreeBSD e’ l’utility “ping” a presentare la falla mentre lato Windows il problema sembra essere relativo ad una funzione della componente ICMP. Mi e’ venuta voglia di approfondire per capire meglio di cosa si tratta: analizzare e studiare le CVE e’, a mio parere, un ottimo esercizio in ambito cyber sec. E poi come resistere al fascino di uno stack overflow 🙂

Al di la della tipologia di vulnerabilita’, di per se interessante, vi e’ un altro elemento piu’ strategico che interessa il bug: FreeBSD, pur avendo un livello di diffusione non elevato, e’ alla base di molte appliance di vario tipo tra cui Firewall e Storage System come il mitico NetApp. Questo rende la vulnerabilita’ ancora piu’ interessante.

Preparazione del lab

Prima cosa da fare e’ documentarsi per valutare come riprodurre un ambiente vulnerabile su cui eseguire i test. L’advisory di FreeBSD stessa espone le versioni a cui a novembre e’ stata applicata la patch:

  • 2022-11-29 stable/13, 13.1-STABLE)
  • 2022-11-29 releng/13.1, 13.1-RELEASE-p5)
  • 2022-11-29 stable/12, 12.4-STABLE)
  • 2022-11-29 releng/12.4, 12.4-RC2-p2)
  • 2022-11-29 releng/12.3, 12.3-RELEASE-p10)

Un primo test lo ho condotto su una FreeBSD 11.4 con ultimo aggiornamento (della ISO) il 12 giugno 2020, teoricamente e’ quindi presente la vulnerabilita’. Purtroppo ho riscontrato diversi fastidi dovuti all’assenza delle repository. Versione troppo datata.

Ho ripiegato sulla release 12.2. In questo periodo il mio home-lab e’ un po’ sottosopra a causa di vari cambi di architettura, ad ogni modo ho preparato una VM amd64 su una installazione di Oracle VirtualBox.

Trovate le ISO qui: http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/amd64/.

installazione di freebsd

Una volta installata la macchina mi sono limitato a configurare l’accesso SSH per root ed installare il debugger gdb.

Avere a disposizione la macchina ci consente inoltre di scaricare i sorgenti dell’utility che presenta la vulnerabilita’: possiamo scaricarci integralmente la repository della distibuzione.

root@freebsd-12:~ # svnlite checkout https://svn.freebsd.org/base/releng/12.2 /usr/src

Una volta ottenuto il sorgente possiamo verificare nel path /usr/src/sbin/ping/ la presenza dei sorgenti di notro interesse:

ping.c

Ora che abbiamo la nostra base possiamo dedicarci un po’ allo studio della vulnerabilita’ partendo dalla documentazione a disposizione e da quanto reperibile in rete.

Raccolta delle informazione

L’advisory in oggetto e’ stata pubblicato il 29 novembre 2022, quindi quattro mesi fa rispetto alla pubblicazione di questo post. Nell’analisi partiamo proprio da questo documento disponibile qui: https://www.freebsd.org/security/advisories/FreeBSD-SA-22:15.ping.asc.

Al punto II troviamo la descrizione dell’errore che provo qui a sintetizzare. Il programma ping riceve e legge i pacchetti per elaborare la risposta tramite la funzione pr_pack(). Per eseguire questa elaborazione viene ricostruito il dato utilizzando l’IP header, l’ICMP header e, in caso di ICMP error, il QUOTED PACKET che ha generato l’errore. Visto che abbiamo a disposizione il sorgente del programma ping.c possiamo dare un occhio alla funzione per capire meglio di cosa si tratta.

La funzione la si puo’ trovare alla linea 1118 del sorgente di ping.c (sempre con riferimento alla versione 12.2 di FreeBSD) e da qui possiamo iniziare ad analizzare il comportamento del codice.

Partiamo dalle variabili che arrivano alla funzione:

pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv)

dove troviamo:

  • il buffer buf che contiene il pacchetto IP ricevuto in rispota dal comando ping
  • la lunghessa cc del pacchetto
  • l’indirizzo IP from della macchina che ha inviato il pacchetto
  • il tempo tv di arrivo del pacchetto

Subito dopo la dichiarazione delle variabili della funzione troviamo una porzione di codice che la patch va a modificare in parte:

1140         memcpy(&l, buf, sizeof(l));
1141         hlen = (l & 0x0f) << 2;
1142         memcpy(&ip, buf, hlen);

In parole povere il contenuto di buf, contenente il pacchetto IP ricevuto in risposta dal comando ping, viene copiato nella variabile l, viene poi calcolata la lunghezza hlen dell’IP header e quindi copiati hlen byte di buf nella variabile IP.

Come si vede meglio dalle modifiche della patch rilasciata il problema si annida proprio in questa ultima memcpy: se il contenuto del pacchetto IP in risposta fosse opportunamente modificato e’ teoricamente possibile utilizzare la lunghezza dei dati inseriti in buf per ottenere un overflow. L’attacker dovrebbe prima intercettare le richiesta ICPM (un ping dalla macchina target) e rispondere con un errore opportunamente modificato. Non impossibile ma decisamente non semplice.

Ho trovato molto utile quanto riportato in post di archcloudlabs.com dove viene proposto di modificare, utilizzando un debuger, il contenuto delle variabili per ottenere “artificialmente” l’overflow del buffer. Ho trovato il test molto interessante e utile da replicare.

Predisposizione debug del comportamento della funzione

Per poter eseguire il debug del nostro binary dobbiamo necessariamente ricompilare l’eseguibile con gli opportuni flag e anvendo i sorgenti a disposizione non si tratta di una operazione complessa.

opzione -g aggiunta nel MakeFile di ping.c

Se tutto in ordine con due comandi facili (make, make install) dovremmo ottenere in nostro nuovo binary di ping.

Il passo successivo e’ fare in modo di ottenere una risposta da noi gestibile, nel post citato precedentemente si fa riferimento ad uno script in scapy ed e’ proprio quello che avrei fatto anche io, ne abbiamo parlato priprio nella live del 31 marzo… scapy mi piace sempre di piu’.

Qui la prima versione dello script che si occupa di intercettare il pacchetto ICMP e rispondere con un pacchetto da noi opportunamente generato:

#!/usr/bin/env python
from scapy.all import *

def reply_ping(packet):
    if packet.haslayer(ICMP) and packet[ICMP].type == 8:
        eth = packet[Ether]
        ip = packet[IP]
        icmp = packet[ICMP]

        payload = [
		b'\x86\x28',
		b'\x41'*20
	]
        payload = b''.join(payload)


        reply = Ether(src=eth.dst, dst=eth.src)/IP(src=ip.dst, dst=ip.src, ihl=6, options=IPOption(payload))/ICMP(type=3, code=0)/icmp[ICMP].payload
        sendp(reply, iface='eth0')

        print('Invio risposta ICMP ping')

sniff(filter="icmp and icmp[icmptype] == icmp-echo", prn=reply_ping)

Dovrei in questo modo ottenere una risposta type=3 (Destination Unreachable) con la possibilita’ di manipolare il contenuto di IPOption, ovvero la parte di dati che, a quanto ho compreso dal codice di ping.c a dall’advisory, dovrebbe essere passata al buffer che presenta la vulnerabilita’.

Per garantirci una buona visibilita’ su cio’ che sta accadendo e’ comodo predisporre lo script su una macchina dove possiamo disporre anche di Wireshark. Nel mio lab ho utilizzato come macchina di destinazione una semplice kali che simulera’ la macchina dell’attacker in questo contesto.

lo script in ascolto

Lato Wireshark e’ sufficiente filtrare i pacchetti ICMP in arrivo sulla NIC della macchina, visto che saremo solo noi ad eseguire dei ping verso il sistema non avremo problemi ad identificare i pacchetti di nostro interesse.

Rispetto ad un normale ping quello che dobbiamo ottenere e’ una risposta che contenga il nostro payload. Il primo esperimento, tutto da perfezionare, ha ottenuto quanto segue:

cattura del pacchetto modificato

Il payload e’ presente nel pacchetto ma evidentemente la risposta richiede qualche ritocco. Nei prossimi giorni lavorero’ in modo specifico sulla rispsta dalla richiesta ICMP ed al debug del codice di ping.c ricompilato cosi’ da verificare anche cosa avviene a livello di sistema.

La live sul mio canale Twitch di venerdi’ 7 aprile riprende questo piccola lab e si procede con le analisi della vulnerabilita’. Nel prossimo post riportero’ le evoluzioni.