Kindergarten is the first pwn challenge of the HTB x UNI 2020 CTF, we are given a 64 bit ELF binary which we must exploit to read a flag stored on the server.
Using Ghidra we can decompile the binary and read a rough representation of the original code.
In the main method we find a C
read call which writes to an area of memory labelled
ans which is 90 bytes long at
Then a call to the
kinder function, which takes some more input and then does a suspicious
read call on line 36 with a length of 0x14c or 332 bytes into an array only 24 bytes long.
We can use GDB with PEDA to debug this binary and find ways to exploit it. First off we use PEDA's
pattern_create to generate a pattern of characters we can feed into the buffer overflow and check if the return pointer is overwritten. I used a pattern length of 150 and then wrote a command which would step through each question and eventually input our exploit string to the final question.
The program then crashes with a segfault and we can use
backtrace to find where our program went. Using
pattern_offset on the values in
backtrace and the contents of the
RBP register we can get the offsets needed to overwrite both the base pointer (128 bytes) and the return instruction pointer (136). The base pointer is not actually needed to exploit here but it could have been useful.
We can then write a short python script to generate our buffer overflow string which will jump us to
Sidenote: There is a function in the binary named
kids_are_not_allowed_here which contained a
CALL instruction on the
ans memory location but this was not needed as we can jump straight to
ans with our buffer overflow.
Testing this leads us to another segfault, but we segfault on memory address
0x60204c which is inside of the buffer, successful program execution redirection! Onto writing our shellcode.
As another quick sidenote, as the program is being setup there is a call to a function named
sec, this function does a few calls to
seccomp_rule_add which is a Linux-specific call for adding system call filters. Using
seccomp-tools I dumped the full ruleset and as we can see only the
open syscalls are available to us, which means no spawning shells without serious trickery.
Using this linux syscall table,
rasm2 an instruction compiler from radare2 and a python script to convert the hex values to raw bytes, I wrote assembly code which would push the string
flag.txt to the stack, open a file with that name, read N bytes from that file and then write them to stdout. This payload is 87 bytes long which probably means it writes the flag outside of the
ans buffer but it didn't seem to break anything.
I placed a file named
flag.txt with contents
testvalue on my desktop and attempted to read it using the generated shellcode + the buffer overflow and it was successful!
Next to execute it on the docker instance... (While editing the N value to print more characters until the end of the flag, the correct number of characters was 22)
And we get our flag: