cb06262002
Those stagers will encrypt the initial stage with a 128-bit RC4 key and the stage length with a XOR key. Both keys are embedded in the stager. This should provide good evasion capabilities in addition to some protection against MITM reversing (if the stager is sent a different route, like in an executable on an USB key). Note that, from a cryptanalyst's standpoint, it is a bad idea to reuse the same stager (or stagers with the same RC4 and XOR keys) more than once since an identical key will result in an identical keystream and make correlation attacks easy. But I doubt that matters in practice. Also note that since communication after the initial statging is not encrypted, these stagers should be used in combination with additional encryption support in the payloads (like Meterpreter).
125 lines
5.5 KiB
Python
125 lines
5.5 KiB
Python
#=============================================================================#
|
|
# A simple python build script to build the singles/stages/stagers and
|
|
# some usefull information such as offsets and a hex dump. The binary output
|
|
# will be placed in the bin directory. A hex string and usefull comments will
|
|
# be printed to screen.
|
|
#
|
|
# Example:
|
|
# >python build.py stager_reverse_tcp_nx
|
|
#
|
|
# Example, to build everything:
|
|
# >python build.py all > build_output.txt
|
|
#
|
|
# Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
|
|
#=============================================================================#
|
|
import os, sys, time
|
|
from subprocess import Popen
|
|
from struct import pack
|
|
#=============================================================================#
|
|
def clean( dir="./bin/" ):
|
|
for root, dirs, files in os.walk( dir ):
|
|
for name in files:
|
|
os.remove( os.path.join( root, name ) )
|
|
#=============================================================================#
|
|
def locate( src_file, dir="./src/" ):
|
|
for root, dirs, files in os.walk( dir ):
|
|
for name in files:
|
|
if src_file == name:
|
|
return root
|
|
return None
|
|
#=============================================================================#
|
|
def build( name ):
|
|
location = locate( "%s.asm" % name )
|
|
if location:
|
|
input = os.path.normpath( os.path.join( location, name ) )
|
|
output = os.path.normpath( os.path.join( "./bin/", name ) )
|
|
p = Popen( ["nasm", "-f bin", "-O3", "-o %s.bin" % output, "%s.asm" % input ] )
|
|
p.wait()
|
|
xmit( name )
|
|
else:
|
|
print "[-] Unable to locate '%s.asm' in the src directory" % name
|
|
#=============================================================================#
|
|
def xmit_dump_ruby( data, length=16 ):
|
|
dump = ""
|
|
for i in xrange( 0, len( data ), length ):
|
|
bytes = data[ i : i+length ]
|
|
hex = "\"%s\"" % ( ''.join( [ "\\x%02X" % ord(x) for x in bytes ] ) )
|
|
if i+length <= len(data):
|
|
hex += " +"
|
|
dump += "%s\n" % ( hex )
|
|
print dump
|
|
#=============================================================================#
|
|
def xmit_offset( data, name, value ):
|
|
offset = data.find( value );
|
|
if offset != -1:
|
|
print "# %s Offset: %d" % ( name, offset )
|
|
#=============================================================================#
|
|
def xmit( name, dump_ruby=True ):
|
|
bin = os.path.normpath( os.path.join( "./bin/", "%s.bin" % name ) )
|
|
f = open( bin, 'rb')
|
|
data = f.read()
|
|
print "# Name: %s\n# Length: %d bytes" % ( name, len( data ) )
|
|
xmit_offset( data, "Port", pack( ">H", 4444 ) ) # 4444
|
|
xmit_offset( data, "LEPort", pack( "<H", 4444 ) ) # 4444
|
|
xmit_offset( data, "Host", pack( ">L", 0x7F000001 ) ) # 127.0.0.1
|
|
xmit_offset( data, "IPv6Host", pack( "<Q", 0xBBBBBBBBBBBBBBB1 ) ) # An IPv6 Address
|
|
xmit_offset( data, "IPv6ScopeId", pack( "<L", 0xAAAAAAA1 ) ) # An IPv6 Scope ID
|
|
xmit_offset( data, "HostName", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" ) # hostname filler
|
|
xmit_offset( data, "RetryCounter", "\x6a\x05" ) # socket retry
|
|
xmit_offset( data, "CodeLen", pack( "<L", 0x12345678 ) ) # Filler
|
|
xmit_offset( data, "Hostname", "https" )
|
|
xmit_offset( data, "ExitFunk", pack( "<L", 0x0A2A1DE0 ) ) # kernel32.dll!ExitThread
|
|
xmit_offset( data, "ExitFunk", pack( "<L", 0x56A2B5F0 ) ) # kernel32.dll!ExitProcess
|
|
xmit_offset( data, "ExitFunk", pack( "<L", 0xEA320EFE ) ) # kernel32.dll!SetUnhandledExceptionFilter
|
|
xmit_offset( data, "ExitFunk", pack( "<L", 0xE035F044 ) ) # kernel32.dll!Sleep
|
|
xmit_offset( data, "EggTag1", pack( "<L", 0xDEADDEAD ) ) # Egg tag 1
|
|
xmit_offset( data, "EggTag2", pack( "<L", 0xC0DEC0DE ) ) # Egg tag 2
|
|
xmit_offset( data, "EggTagSize", pack( ">H", 0x1122 ) ) # Egg tag size
|
|
xmit_offset( data, "RC4Key", "RC4KeyMetasploit") # RC4 key
|
|
xmit_offset( data, "XORKey", "XORK") # XOR key
|
|
if( name.find( "egghunter" ) >= 0 ):
|
|
null_count = data.count( "\x00" )
|
|
if( null_count > 0 ):
|
|
print "# Note: %d NULL bytes found." % ( null_count )
|
|
if dump_ruby:
|
|
xmit_dump_ruby( data )
|
|
#=============================================================================#
|
|
def main( argv=None ):
|
|
if not argv:
|
|
argv = sys.argv
|
|
try:
|
|
if len( argv ) == 1:
|
|
print "Usage: build.py [clean|all|<name>]"
|
|
else:
|
|
print "# Built on %s\n" % ( time.asctime( time.localtime() ) )
|
|
if argv[1] == "clean":
|
|
clean()
|
|
elif argv[1] == "all":
|
|
for root, dirs, files in os.walk( "./src/egghunter/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
for root, dirs, files in os.walk( "./src/migrate/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
for root, dirs, files in os.walk( "./src/single/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
for root, dirs, files in os.walk( "./src/stage/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
for root, dirs, files in os.walk( "./src/stager/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
for root, dirs, files in os.walk( "./src/kernel/" ):
|
|
for name in files:
|
|
build( name[:-4] )
|
|
else:
|
|
build( argv[1] )
|
|
except Exception, e:
|
|
print "[-] ", e
|
|
#=============================================================================#
|
|
if __name__ == "__main__":
|
|
main()
|
|
#=============================================================================#
|
|
|