/@@@. @@@@@@@ @@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@& @@@@ #@@@@@@@@@@@@@@@, @@@@@ @@@@@@@@@@@@@@. @@@@@@* @ .@@@@@@@ @@@@@ @@@@@@@ @@@ @@@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@@@@@@@@@@@@@ @@@@, @@@@@@@@@@@@@@@@@@@@ @@@& @@@@ @@@@@@@@@@@@@@@@@@@@@. @@@ @, @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@ &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@. @@@@@@@@@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@@@ ,@@@ @@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@& @@@@ @@@@@@ *@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@ @@@@@@ @@@@@@@@@ @@@@@@@@. @@@@@@
This was a pwn challenge from the DefCamp CTF 2020 rated with 100 points. The description said:
We have a problem on the station on Mars, we suspect we would be attacked by some hackers so we put a little protection against them.
Flag format: CTF{sha256}
They give us a binary. When we run it we get:
I think that ‘Try harder!!’ message means that we have to put something there to actually do something. Well, let’s reverse it with Cutter
Let’s open it and check the general information on the dashboard window:
This give us some useful information:
- No canary so a buffer overflow is easier
- No crypto
- Not stripped so we can see the names of everything
- No PIC so the addresses of the instructions are static
- NX bit so we can’t execute anything on the stack
Let’s open the main function:
It is calling a helper function, then creating 2 buffers, calling system with the string “clear” and finally calling l00p.
Well, that system call looks promising to pop a shell. Let’s take note of that and move on to the helper function.
I’m not sure what’s the point of this so let’s move on to the l00p function:
This is definitely what we saw when we executed it. The welcome message and then a scanf the secret message. Then it compares it with the try_hard3r string and if they don’t match, print the Try_harder string and call fake. If they do, call vuln.
Let’s check that try_hard3r string. Copy the address (0x00400a21) and look at that address in the hexdump view:
Now we know the correct secret message was: #!@{try_hard3r}. Now we are going to check the vuln function because, I mean, that name looks promising.
Well, it is printing some strings back to us and finally calling scanf and printing ‘Hacker alert’. There is no length check so it looks like a buffer overflow. We can see that the programs write our input to var_70h and that is rbp - 0x70. So, if we write more than 0x78 bytes, we can override the return address.
THE EXPLOIT
At this moment, we know we can redirect the execution. The question now is what to do with that. It doesn’t look like the flag is loaded anywhere so we are trying to pop a shell. And that previous call to system will be perfect to get it.
From the man page of system we get:
This function just receives one parameter which is the command it’s going to be executed. This pointer to a string must be loaded into the rdi register.
We can put the string ‘/bin/sh’ in some part of the memory that we know and then use that address. For example, the .data section
Do you remember that helper function? Well, now it makes sense. It’s adding the contents of rax to rdi, which is loaded from the stack from the contents of rbp. So we just have to put the address of ‘/bin/sh’ where rbp is going to take the contents from and call this helper function. Finally, redirect it to that call to system (remember there is no PIC so addresses are always the same)
BUILD THE EXPLOIT
I’m going to use pwntools (https://github.com/Gallopsled/pwntools) which allows us to easily interact with binaries and plenty of other things.
First is to run the binary and send the ‘#!@{try_hard3r}’ string
We need the address of the helper function which is 0x00400815
*Note: there is an issue with Ubuntu 18.04 that makes mandatory that the stack is aligned before calling some functions of glibc, like system, so we are going to add a ‘ret’ so the stack gets aligned (https://www.cameronwickes.com/stack-alignment-ubuntu-18-04-movaps/) so i’m going to take the address of the ret in the _init function (0x400596)
The idea is to call a scanf with the address of .data (0x00601048) loaded so we can write there by using that helper function which puts the contents of rbp to rax so we can load the address.
We are going to use the fake call to use the scanf. We are going to jump to the instruction which is marked as red:
So the previous load of the address into rax is not executed because we already have the address of .data in rax. Then it just calls l00p again.
Let’s write that part:
Now, we have the string ‘/bin/sh’ in 0x00601048.
After that, we are going to use gdb to take a look at the contents of rdi right before the ret (because that rbp address is added to the contents of rdi) so we set a breakpoint at that instruction.
Run gdb with:
Then check the addresses of the instructions with:
And the instruction before the ret is at *vuln + 95:
So, let’s add that to our script:
Let’s send some test input:
Run it with python3 script.py so we can check what’s the amount in rdi with the info registers command:
Rdi is 0x1 so we have to subtract 1 to the address in the last position of the 8 bytes.
So the final address is going to be 0x00601048 - 1 = 0x00601047. Finally, the address of the system call in the main function: 0x00400872. So we send that:
Execute and we get the shell: