Last active
September 22, 2018 09:47
-
-
Save FrankSpierings/16843fa18b2008efafab9415ef5da38c to your computer and use it in GitHub Desktop.
Out-EncryptedScript Python Edition. Encrypts content (like a script) and wraps a Powershell decryption routine around it.
This file contains 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 | |
from Crypto.Cipher import AES | |
from base64 import b64encode | |
from Crypto.Protocol import KDF | |
from Crypto.Random import get_random_bytes | |
import sys | |
import argparse | |
import string | |
import random | |
pstemplate = ''' | |
function {var_decrypt}([String] ${var_p}, [String] ${var_s}) | |
{{ | |
Set-Alias {var_new_object} New-Object; | |
${var_iv} = "{iv}"; | |
${var_iv} = [Convert]::FromBase64String(${var_iv}); | |
${var_ct} = "{ct}"; | |
${var_ct} = [Convert]::FromBase64String(${var_ct}); | |
${var_enc} = {var_new_object} System.Text.ASCIIEncoding; | |
${var_key} = {var_new_object} System.Security.Cryptography.PasswordDeriveBytes(${var_p}, ${var_enc}.GetBytes(${var_s}), "SHA1", {iternr}); | |
${var_key} = ${var_key}.GetBytes(16); | |
${var_aes} = {var_new_object} System.Security.Cryptography.AesManaged; | |
${var_aes}.Mode = [System.Security.Cryptography.CipherMode]::CBC; | |
${var_dc} = ${var_aes}.CreateDecryptor(${var_key}, ${var_iv}); | |
[Byte[]] ${var_pt} = {var_new_object} Byte[](${var_ct}.Length); | |
${var_ms} = {var_new_object} System.IO.MemoryStream(${var_ct}, $True); | |
${var_cs} = {var_new_object} System.Security.Cryptography.CryptoStream(${var_ms}, ${var_dc}, [System.Security.Cryptography.CryptoStreamMode]::Read); | |
${var_nr} = ${var_cs}.Read(${var_pt}, 0, ${var_pt}.Length); | |
${var_pt} = ${var_pt}[0..(${var_nr}-1)]; | |
${var_ms}.Close(); | |
${var_cs}.Close(); | |
${var_aes}.Clear(); | |
return ${var_enc}.GetString(${var_pt}); | |
}} | |
''' | |
def randomstring(l, pattern=string.ascii_lowercase): | |
return ''.join(random.choice(pattern) for _ in range(l)) | |
def obfuscate_vars(debug=False): | |
conf = {} | |
while (len(conf.keys()) != len(set(conf.values())) or len(conf.values()) == 0): | |
conf = { | |
'var_decrypt': '', | |
'var_p': '', | |
'var_s': '', | |
'var_iv': '', | |
'var_ct': '', | |
'var_enc': '', | |
'var_key': '', | |
'var_aes': '', | |
'var_dc': '', | |
'var_pt': '', | |
'var_nr': '', | |
'var_ms': '', | |
'var_cs': '', | |
'var_new_object': '', | |
} | |
if debug: | |
for k in conf.keys(): | |
conf[k] = k.replace('var_', '') | |
else: | |
for k in conf.keys(): | |
conf[k] = '{0}'.format(randomstring(random.randint(3, 6))) | |
return conf | |
def pkcs7pad(pt, bs): | |
nrpad = bs - (len(pt) % bs) | |
if nrpad == 0: | |
nrpad == bs | |
pt = pt + (chr(nrpad) * nrpad) | |
return pt | |
def generate(password, salt, pt, iternr=2, auto=False, debug=False): | |
bs = 16 | |
key = KDF.PBKDF1(password, salt, bs, iternr) | |
iv = get_random_bytes(bs) | |
mode = AES.MODE_CBC | |
encryptor = AES.new(key, mode, IV=iv) | |
ppt = pkcs7pad(pt, bs) | |
ct = encryptor.encrypt(ppt) | |
iv = b64encode(iv) | |
ct = b64encode(ct) | |
var_conf = obfuscate_vars(debug=debug) | |
ps = pstemplate.format(iv=iv, ct=ct, iternr=iternr, **var_conf) | |
if not debug: | |
ps = ps.replace('\n', '') | |
ps = ps.replace(' = ', '=') | |
ps = ps.replace(', ', ',') | |
extractline = 'iex ({0} {1} {2})'.format( | |
var_conf['var_decrypt'], password, salt) | |
if auto: | |
ps += extractline | |
return ps, extractline | |
def main(): | |
parser = argparse.ArgumentParser( | |
description='Outputs an encrypted PowerShell script.') | |
parser.add_argument( | |
'-a', | |
'--auto', | |
help='Automatic decryption of the PowerShell script. This will leave more traces on disk!', | |
action='store_true') | |
parser.add_argument( | |
'-d', | |
'--debug', | |
help="Don't obfuscate the PowerShell script.", | |
action='store_true') | |
parser.add_argument( | |
'-p', | |
'--password', | |
help='Password to use for the key derivation function.', | |
default=randomstring(14, pattern=string.ascii_letters + string.digits)) | |
parser.add_argument( | |
'-s', | |
'--salt', help='Salt to use, make sure it is 8 bytes long.', | |
default=randomstring(8, pattern=string.ascii_letters + string.digits)) | |
parser.add_argument('file', | |
help='File to convert, you may also use stdin.', | |
nargs='?', | |
type=argparse.FileType('r'), default=sys.stdin) | |
args = parser.parse_args() | |
out = generate(args.password, | |
args.salt, | |
args.file.read(), | |
auto=args.auto, | |
debug=args.debug) | |
print(out[0]) | |
if not args.auto: | |
sys.stderr.write("Command: PowerShell -command '. <PATH_TO_SCRIPT>; {0}'".format(out[1])) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment