Automated Exploit Generation 2 - Pwn
Challenge: Automated Exploit Generation 2
Author: Shotokhan
Description: Exploit of 10 random binaries with the same vulnerability
CTF: UTCTF 2022
Category: Pwn
Task
Now with printf!
By Tristan (@trab on discord) nc pwn.utctf.live 5002
Writeup
If we interact with the server:
$ nc pwn.utctf.live 5002
You will be given 10 randomly generated binaries.
You have 60 seconds to solve each one.
Solve the binary by making it exit with the given exit code
Press enter when you're ready for the first binary.
After pressing enter, we’re given a small binary in hexdump format.
We copy it in a file random_0.hex
and get the actual ELF with:
$ xxd -r random_0.hex > random_0
Now, we can guess that the randomly generated binaries are similar among them, the randomness will be in some input-modifying function.
So we analyze the obtained executable file:
$ file random_0
random_0: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=335c472b5b0059a4d4826b6c1f8218d59e757ff0, for GNU/Linux 3.2.0, not stripped
$ checksec random_0
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
$ ltrace ./random_0
fgets(AAAAAAAAAAA
"AAAAAAAAAAA\n", 514, 0x7f380aa14800) = 0x7ffcc61b7380
printf("") = 0
exit(0 <no return ...>
+++ exited (status 0) +++
It has some protections enabled, and it basically fgets
at most 514 bytes of data, then performs a printf
.
If we decompile it with Ghidra, we can see that the binary performs these actions:
So, it’s clearly the case of a format string attack; our ltrace showed that the printf had a null string as parameter because there is input permutation, which in this case has put a null byte at the start of the buffer.
The exit_code
is a global variable, so the idea is to perform the format string attack to overwrite it with the exit code given alongside the binary.
The permute
function calls 8 permutation sub-functions in random order, for example:
A combination of permutations is still a permutation, so we can get a complete mapping position i -> position j
by executing the program locally many times (we don’t need to use angr to solve this task).
The first thing to do is to patch the binary to develop a working exploit, without permutation; so we basically replace the call to permute
in main
with a sequence of NOP instructions.
We save the patched binary into random_0_patched
and developed the exploit for it (it wanted 168 as exit code):
Now that we have a working exploit, we need a function to get the permutation map, so that the executable will put the characters of the exploit in the right positions.
The permutation map can be obtained very fast by starting the executable a few times, but I went for an easy, non-optimized function:
It’s quick and dirty and it obtains just a single mapping for every execution (so, 514 processes for full mapping), but it does the job.
Now we can put the pieces together and test the exploit on the original binary:
It’s quite slow, but it works; the last thing to do is to automate the interaction with the remote service, to get the binary, decode it, make it executable, get the desired exit code, get the permutation mapping and craft the final exploit, then repeat this for 10 times. An implementation issue is that we have to make sure that the fgets
of a binary reads all our input, otherwise the fgets
of the next binary will read some non-flushed input and the exploit will not work. To overcome this issue, we have to truncate our exploit payload to the minimum length required to perform the format string attack (i.e., we must not add padding to reach 514 bytes).
By running it, we obtain:
$ python script.py
...
exploit = b'______________________________________________________________________________________________________________________________________________________________________________________________________A%5c%10$nAAAAAAA_\\@@\x00\x00\x00\x00\x00'
val = 5
elapsed = 8.956268072128296
[*] Switching to interactive mode
Process exited with return code 5
Congrats!
utflag{you_mix_me_right_round_baby_right_round135799835}