dsi/exploits/dsisavpatch_py/dsisavpatch.py
2011-01-26 18:05:01 -05:00

195 lines
5.4 KiB
Python

from __future__ import with_statement
import sys
import httplib, mimetypes
import urllib
# script for getting patch blobs for dsi sav
current_version=1000
host='bootmii.org'
path_base='/dsiexploits/inject/'
script_path='upload.php'
if len(sys.argv) != 3:
print 'need two options <inputfile> <outputfile>'
sys.exit(1)
## from http://code.activestate.com/recipes/146306/
def post_multipart(host, selector, fields, files):
"""
Post fields and files to an http host as multipart/form-data.
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return the server's response page.
"""
content_type, body = encode_multipart_formdata(fields, files)
h = httplib.HTTPConnection(host)
headers = {
'Content-Type': content_type
}
h.request('POST', selector, body, headers)
res = h.getresponse()
return res.status, res.reason, res.getheaders(), res.read()
def encode_multipart_formdata(fields, files):
"""
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return (content_type, body) ready for httplib.HTTP instance
"""
BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
CRLF = '\r\n'
L = []
for (key, value) in fields:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, filename, value) in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
L.append('Content-Type: %s' % get_content_type(filename))
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
## end of from http://code.activestate.com/recipes/146306/
with open(sys.argv[1], 'rb') as f:
contents = f.read()
footer = contents[0x40f4:0x4554]
print 'opening http://%s%s%s' %(host, path_base, script_path)
status, reason, headers, response = post_multipart(host, '%s%s' % (path_base, script_path), (), [('footer', 'footer.bin', footer)])
if status != 200 and status != 302:
print 'error getting: %s' % script_path
print status, reason
location='';
for a in headers:
if a[0] == 'location':
location = a[1]
if a[0] == 'x-protocolver':
if int(a[1]) > current_version:
print '"The client software was updated and this update is required, now aborting.'
sys.exit(1)
else:
print 'ProtocolVer %d is good!' % int(a[1])
if location=='':
print 'did not get location redirect! %d as status' % status
print response
sys.exit(0)
if location[0:5] != 'http:':
print 'not a http redirect, bad luck'
sys.exit(0)
end_of_redirect_host = location.find('/', 7)
redirect_host = location[7:end_of_redirect_host]
redirect_query = location[end_of_redirect_host:]
end_of_path = redirect_query.find('?')
redirect_path = redirect_query[0:end_of_path]
name,val = location[end_of_path+1:].split('=')
#print 'waiting for successful reply for %s' % redirect_path
params = urllib.urlencode({'hash': val})
headers = {"Content-type": "application/x-www-form-urlencoded"}
attempts = 20
payload = ''
while attempts > 0:
print 'trying %s with hash as %s'%(redirect_path ,val)
h = httplib.HTTPConnection(redirect_host)
h.request('POST', redirect_query, params, headers)
res = h.getresponse()
if res.status == 200:
payload = res.read()
# print 'got %d, and length %d' %(res.status, len(payload))
if payload[0:5] == 'ERROR':
print 'error: %s' % payload[5:]
attempts = -1
elif payload[0:7] == 'INFOMSG':
print 'info: %s' % payload[7:]
else:
break
attempts = attempts - 1
else:
print 'bad times, we got %d reply' % res.status
sys.exit(0)
if attempts == 0:
print 'too many attempts, not sure what happened!'
sys.exit(0)
# process payload
start_of_field=0
end_of_field=payload.find('\0', start_of_field)
if end_of_field == -1:
print 'whoops, end of field fail!'
sys.exit(0)
notes_size = int(payload[start_of_field:end_of_field], 16)
print 'noteslen: %d' % notes_size
start_of_field = end_of_field+1
end_of_field=payload.find('\0', start_of_field)
if end_of_field == -1:
print 'whoops, end of field fail!'
sys.exit(0)
num_objs = int(payload[start_of_field:end_of_field], 16)
print 'found %d objs' % num_objs
patch_blobs = []
for i in range(0,num_objs):
start_of_field = end_of_field+1
end_of_field = payload.find('\0', start_of_field)
if end_of_field == -1:
print 'whoops, end of field fail!'
sys.exit(0)
offset = int(payload[start_of_field:end_of_field], 16)
start_of_field = end_of_field+1
end_of_field = payload.find('\0', start_of_field)
if end_of_field == -1:
print 'whoops, end of field fail!'
sys.exit(0)
size = int(payload[start_of_field:end_of_field], 16)
patch_blobs.append((offset,size))
print 'queued patch_blob'
start_of_field = end_of_field + 1
notes = payload[start_of_field:start_of_field+notes_size]
start_of_field = start_of_field + notes_size
for (offset,size) in patch_blobs:
contents = contents[0:offset] + payload[start_of_field:start_of_field+size] + contents[offset+size:]
print 'applied patch_blob!'
start_of_field = start_of_field + size
with open(sys.argv[2], 'wb') as f:
f.write(contents)
print 'notes: \n%s' % notes
print 'done!'