191 lines
5.5 KiB
Python
191 lines
5.5 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# The following Python code will take shellcode (buf variable)
|
|
# and create SUB instructions that will generate shellcode four
|
|
# bytes at a time and push them to the stack.
|
|
#
|
|
# The trick with this code is that EAX needs to be zeroed out before
|
|
# each new set of SUB instructions. Also, the stack needs to be
|
|
# aligned to be where you can execute the pushed instructions. All of
|
|
# this is left to the reader.
|
|
#
|
|
# Author: Absane (blog.noobroot.comu)
|
|
# Modified by: Alton Johnson (alton.jx@gmail.com)
|
|
#
|
|
# Last Updated: March 12, 2015 (by Alton Johnson)
|
|
#
|
|
|
|
import sys, os, getopt
|
|
from random import choice
|
|
from sys import argv
|
|
|
|
total_length = 0
|
|
### CHARACTERS THAT ARE ALLOWED ###
|
|
|
|
code = ''
|
|
goodchars = []
|
|
|
|
# Add all characters to the "good character" list. Replaced with -g
|
|
for i in range(0, 256):
|
|
goodchars.append(format(i, "#04x").replace("0x", ""))
|
|
|
|
def compl(hexvalue):
|
|
return int("FFFFFFFF",16) - int(hexvalue,16)+1
|
|
|
|
def findvalues(code, carry, last):
|
|
total = 9999999999
|
|
wastetime = 99999
|
|
while (total != int(code,16)):
|
|
a = choice(goodchars)
|
|
b = choice(goodchars)
|
|
c = choice(goodchars)
|
|
total = int(a,16) + int(b,16) + int(c,16)+carry
|
|
if (( total - 256 == int(code,16) ) and (last != 1) & wastetime < 1):
|
|
return (a,b,c,1)
|
|
wastetime += -1
|
|
return (a,b,c,0)
|
|
|
|
def encode(x):
|
|
global code, total_length
|
|
y = x
|
|
endian = (y[6] + y[7]) + (y[4] + y[5]) + (y[2] + y[3]) + (y[0] + y[1])
|
|
twocompl = compl(endian)
|
|
k = str(hex(twocompl))[2:99].strip("L")
|
|
k = "0" * ( 8 - len(k) ) + k
|
|
|
|
first = k[0:2]
|
|
second= k[2:4]
|
|
third = k[4:6]
|
|
fourth= k[6:8]
|
|
|
|
a = findvalues(fourth,0,0)
|
|
b = findvalues(third,a[3],0)
|
|
c = findvalues(second,b[3],0)
|
|
d = findvalues(first,c[3],1)
|
|
|
|
output = ''
|
|
final = ''
|
|
plain = []
|
|
for i in range(0,3):
|
|
for k in (a,b,c,d):
|
|
output += "\\x" + k[i]
|
|
plain.append(k[i])
|
|
final += '\n\"\\x2d' + output + "\""
|
|
total_length += (len(output)/4+1)
|
|
final += "\t# SUB EAX," + plain[3] + plain[2] + plain[1] + plain[0]
|
|
output = ''
|
|
plain = []
|
|
|
|
code += "\n# Encoded: " + x
|
|
code += "\n\"" + r"\x25\x41\x41\x41\x41" + "\"\t# SUB EAX,41414141"
|
|
code += "\n\"" + r"\x25\x3E\x3E\x3E\x3E" + "\"\t# SUB EAX,3E3E3E3E"
|
|
code += final
|
|
code += "\n\"" + r"\x50" + "\"\t\t\t# PUSH EAX\n"
|
|
total_length += 11
|
|
|
|
def encoden(x):
|
|
global code, total_length
|
|
y = x
|
|
endian = (y[6] + y[7]) + (y[4] + y[5]) + (y[2] + y[3]) + (y[0] + y[1])
|
|
twocompl = compl(endian)
|
|
k = str(hex(twocompl))[2:99].strip("L")
|
|
k = "0" * ( 8 - len(k) ) + k
|
|
|
|
first = k[0:2]
|
|
second= k[2:4]
|
|
third = k[4:6]
|
|
fourth= k[6:8]
|
|
|
|
a = findvalues(fourth,0,0)
|
|
b = findvalues(third,a[3],0)
|
|
c = findvalues(second,b[3],0)
|
|
d = findvalues(first,c[3],1)
|
|
|
|
output = ''
|
|
final = ''
|
|
plain = []
|
|
for i in range(0,3):
|
|
for k in (a,b,c,d):
|
|
output += "\\x" + k[i]
|
|
plain.append(k[i])
|
|
final += '\\x2d' + output + ""
|
|
total_length += (len(output)/4+1)
|
|
output = ''
|
|
plain = []
|
|
|
|
code += "\n# Encoded: " + x
|
|
code += "\n\"" + r"\x25\x41\x41\x41\x41"
|
|
code += r"\x25\x3E\x3E\x3E\x3E"
|
|
code += final
|
|
code += r"\x50" + "\"" + "\""
|
|
total_length += 11
|
|
|
|
def main(shell):
|
|
global total_length
|
|
k = shell
|
|
while ( len(k)/2 % 4 != 0):
|
|
k += '90'
|
|
total_length += 1
|
|
|
|
z = ''
|
|
line = ''
|
|
rshell = []
|
|
for i in range(0, len(k), 8):
|
|
for j in range(0,8):
|
|
z += k[i + j]
|
|
line = z + line
|
|
rshell = [line] + rshell
|
|
line = ''
|
|
z = ''
|
|
for i in rshell:
|
|
encode(i)
|
|
for i in rshell:
|
|
encoden(i)
|
|
def help():
|
|
print ("\n Usage: %s <OPTIONS>" % argv[0])
|
|
print ("\n -s <string>\tEncode bytes from stdin (\\x00 format).")
|
|
print (" -f <file>\tEncodes shellcode from a file (\\x00 format).")
|
|
print (" -g <file>\tOptional parameter that restricts encoder to goodbytes. (\\x00 format).")
|
|
print ("\n Usage example: %s -s \"\\x75\\xE7\\xFF\\xE7\"" % argv[0])
|
|
print (" Usage example: %s -f shellcode.txt -g good_chars.txt\n" % argv[0])
|
|
exit()
|
|
|
|
def start(argv):
|
|
buf = ""
|
|
global code
|
|
global goodchars
|
|
if len(argv) < 1:
|
|
help()
|
|
try:
|
|
opts, args = getopt.getopt(argv, "f:s:g:")
|
|
except getopt.GetoptError as err:
|
|
print ("\n Error: %s" % err)
|
|
help()
|
|
|
|
for opt, arg in opts:
|
|
if opt == "-s":
|
|
buf = arg
|
|
buf = buf.replace("\\x","").replace("x","")
|
|
elif opt == "-g":
|
|
good_file = open(arg).read().replace("\n", "").replace("\\x", "").replace("\"", "")
|
|
goodchars = [good_file[i:i+2] for i in range(0, len(good_file), 2)][:-1]
|
|
elif opt == "-f":
|
|
try:
|
|
buf = open(arg).read().replace("\\x","").replace("\n","").replace("\"","")
|
|
except Exception as err:
|
|
print ("\n Error: %s" % err)
|
|
exit()
|
|
|
|
main(buf)
|
|
code = code[:-1]
|
|
print ("\nencoded_shellcode = (", code + "\n)")
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
start(argv[1:])
|
|
print ("\nTotal length in bytes: " + str(total_length) + "\n")
|
|
except Exception as err:
|
|
print ("\n Error: %s" % err)
|
|
except KeyboardInterrupt:
|
|
print ("\nExiting per user's request (ctrl-c)")
|
|
exit() |