Wanna enter the Secret Society? Well you have to find the secret code first!
Again, smash the keyboard.
Flag: csivit{Bu!!er_e3pl01ts_ar5_5asy}
Greta Thunberg 1 Administration 0
This was a different type of binary exploitation challenge. First, check the protections.
Much like the others. Let's run it.
So our input is sent back to us, along with the notice that we cannot log in with input. As we control the print, let's check if there's a format string bug.
And indeed there is. Interestingly, there's no buffer overflow. Let's decompile it to see what's going on.
main
is very simple - takes in input (using a secure fgets()
, explaining why there was no BoF) and passes the input to the login()
function.
Input it printed back to us, as we saw, with printf
. This causes the format string. The interesting part is it checks the global admin
variable before printing the flag.
Clearly, we have to overwrite the admin
variable somehow. To do this, we're going to have to leverage the format string %n
specifier for an arbitrary write.
%n
takes a pointer to a signed int, where the number of characters written so far is stored. Because we can control certain aspects of the stack (as the buffer is on the stack) we can tell it where to write the data. As we can control the input, we can tell it how much. This gives us an arbitrary write. If we want to write 20 bytes somewhere, we input 20 characters and then call %n
. We can even use other fancy format string specifiers to shorten it enough,
I would explain how to leverage this in detail, but frankly, others have done so much, much better than me :)
There are plenty more resources online.
Luckily for us, pwntools
contains a feature to automate %n
exploitation.
You should understand how the exploit works before you use tools to do it for you.
The pwntools module is fmtstr_payload
, and takes in two values: the offset for the format string and a dictionary. The keys in the dictionary are the location to write to, and the values are the data to write there.
Flag: csictf{n0_5tr1ng5_@tt@ch3d}
Again, smashing the keyboard doesn't work. Sadly. Let's check out the protections:
Again, smashing the keyboard doesn't work. Sadly. Let's check out the protections.
Same thing again, GHidra decompilation time.
Again, gets()
shows a clear buffer overflow vulnerability. Among other functions there is a flag()
function.
So, calling flag()
returns the flag. Unsurprisingly.
We'll be using the buffer overflow vulnerability to redirect code execution to the flag()
function. Some experimenting shows a padding of 40 bytes is needed to overwrite RIP.
Flag: csictf{ch4lleng1ng_th3_v3ry_l4ws_0f_phys1cs}
Travelling through spacetime!
Sadly, we can't just smash the keyboard. Let's check what protections are enabled.
NX is enabled, so unfortunately no shellcode, but no other protections. Let's perhaps decompile it in GHidra.
So we have a 44-byte-long buffer storing our input, which is read by gets()
- a clear buffer overflow vulnerability. Interestingly, the program seems to also return the flag if the if condition is met. I've known GHidra to make mistakes with numbers, so I check the disassembly in radare2.
As we can see, the buffer our input is stored in is lower down the stack to the variable that is compared, so if we overflow the buffer we will overflow into the other variable. From the decompilation we know the buffer is 44 bytes long, so we need 44 bytes of padding before we reach the checked variable and write 0xcafebabe
.
Flag: csictf{c4n_y0u_re4lly_telep0rt?}
My first C program that says hello, do you want to try it?
Smash was a very cool challenge where you were given the libc
version used by the binary. You had to bypass ASLR and then execute a ret2libc attack.
As per usual, run a quick checksec
Luckily for us, PIE is disabled and there is no canary. That makes our job much easier. Let's run it and see what happens.
Hmm, our input is printed back to us again. Is there another format string bug?
Indeed there is! Is a BoF possible this time?
Awesome.
There's nothing particularly interesting in the decompilation - main
takes input and calls say_hello
, which prints back to you.
No interesting strings either. As we are given the libc
, everything points to a good old ret2libc attack.
As we only had one input, the logical approach would be to use a ret2plt to leak the address of puts in libc
from the global offset table and call main again to let us have another input.
Flag: csictf{5up32_m4210_5m45h_8202}