
Vulnerabilità di Stack Buffer Overflow nel IGD UPnP di LINKSYS AC1900 EA7500v3 che consente l'Esecuzione Remota di Codice
Questa vulnerabilità consente a un aggressore adiacente alla rete di eseguire codice arbitrario sulle installazioni interessate dei router LINKSYS EA7500. Non è richiesta autenticazione per sfruttare questa vulnerabilità.
Il difetto specifico risiede nella gestione dei dati delle richieste HTTP verso il servizio IGD UPnP. Durante l'analisi dei contenuti di una variabile fornita dall'utente in una data richiesta SOAP UPnP Action Request, il processo non convalida correttamente la lunghezza dei dati forniti dall'utente prima di copiarli in un buffer dello stack di lunghezza fissa. Un aggressore può sfruttare questa vulnerabilità per eseguire codice nel contesto di root.
Prodotto/Firmware: Firmware Linksys EA7500 TUTTE LE VERSIONI inclusa Ver.3.0.1.207964 - Sono interessati anche altri modelli di router e versioni firmware che utilizzano questo binario
Il binario del servizio UPnP IGD si trova in /usr/sbin/IGD ed è in esecuzione di default sulla porta 49152. Questo servizio fornisce il file di descrizione UPnP XML IGDdevicedesc.xml che elenca diverse funzioni che possono essere invocate utilizzando richieste HTTP con un corpo XML. Una di queste funzioni è SetDefaultConnectionService. Questa funzione richiede una variabile di tipo stringa. Quando viene invocata ed eseguita la funzione SetDefaultConnectionService, il programma non convalida la lunghezza della variabile fornita dall'utente prima di effettuare una chiamata a strncpy che coinvolge questo buffer. Sia l'indirizzo sorgente che la dimensione della copia della chiamata strncpy sono controllati dall'utente, con la dimensione della copia pari alla lunghezza della variabile fornita dall'utente. I dati vengono quindi copiati in un buffer fisso di 184 byte, portando a una vulnerabilità di stack buffer overflow.
La funzione SetDefaultConnectionService è etichettata come _set_connection_type. La funzione inizia inizializzando un buffer di 184 byte e quindi ottiene un puntatore al buffer contenente la variabile stringa fornita dall'utente inclusa nella richiesta, se non è NULL. Ciò avviene chiamando PAL_xml_node_GetFirstbyName e quindi PAL_xml_node_get_value. Vedi codice qui sotto:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* Initializing 184-byte buffer */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 now points to the user-supplied value */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Ensures the user-supplied value is not empty and obtains a pointer to it */
...
Successivamente nella stessa funzione, viene effettuata una chiamata strlen per ottenere la dimensione della stringa fornita dall'utente più un offset statico di 0x174. La condizione vulnerabile viene attivata nella successiva chiamata strncpy dove l'argomento destinazione è l'indirizzo del buffer appena inizializzato di 184 byte, la sorgente è il puntatore alla stringa fornita dall'utente, e la dimensione dell'operazione di copia è la dimensione della stringa fornita dall'utente restituita dalla chiamata a strlen più un offset statico di 0x174. Ciò porta a una vulnerabilità di buffer overflow poiché sia l'indirizzo sorgente che le variabili di dimensione sono controllati dall'utente e non vengono effettuati controlli di validazione della dimensione. Vedi codice qui sotto:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 is a pointer to the user supplied string */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Vulnerable strncpy call */
...
L'offset per sovrascrivere un indirizzo di ritorno della funzione nello stack è di 276 byte. I successivi 4 byte possono essere utilizzati per reindirizzare l'esecuzione verso un indirizzo arbitrario e quindi dirottare il flusso di controllo del programma.
Utilizzare una funzione di copia di stringhe più sicura: invece di usare strncpy, che non garantisce la terminazione con null del buffer di destinazione, si può usare una funzione più sicura come strncpy_s o memcpy_s. Queste funzioni assicurano che il buffer di destinazione sia sempre terminato con null e non permettono la copia di più dati di quanti il buffer possa contenere.
Convalida dell'input: validare l'input dell'utente per assicurarsi che non superi la dimensione del buffer di destinazione. Se l'input è più lungo della dimensione del buffer, rifiutarlo o troncarlo per adattarlo al buffer.
Utilizzare un buffer allocato dinamicamente: allocare memoria per il buffer di destinazione dinamicamente invece di usare un buffer dello stack di dimensione fissa. Questo approccio consente di regolare la dimensione del buffer in base alla dimensione dei dati di input. (Non consigliato per un sistema con risorse limitate)
PoC Execution: python poc.py 192.168.1.1 49152
Link per il download del software: https://support.linksys.com/kb/article/559-en/ (Versione firmware Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv disponibile qui: https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt).pkill IGD per terminare il binario e poi riavviarlo usando ./gdbserver :1337 /usr/sbin/IGD. Il seguente file .gdbinit può essere utilizzato per avviare una sessione di debug stabile:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c