A small, localhost-only lab that walks through a complete Windows initial-access chain end-to-end:
malware.bat / payload.bat (obfuscated dropper, runs on "victim")
│
└──> mshta + VBScript (T1218.005)
│
└──> powershell -EncodedCommand (T1059.001 + T1027)
│
└──> IEX(DownloadString(...)) (T1105)
│
└──> reverse.ps1 (T1059.001)
│
└──> TCP 127.0.0.1:9001 --> nc -lvnp 9001
Everything runs against 127.0.0.1. There is no real target. This is a teaching artifact for OSCP / red-team / detection-engineering students who want to read and run each stage without setting up a multi-VM lab.
⚠️ Lab use only. Run this against systems you own. See LICENSE.
| File | Role | What to read it for |
|---|---|---|
server.py |
Minimal HTTP "C2" stand-in (8080). Serves payload.bat and reverse.ps1. |
LOLBin delivery; hosting + logging |
payload.bat |
Plain mshta + VBScript dropper. Smallest readable form of the chain. |
How the encoded-PowerShell handoff actually looks |
malware.bat |
Same payload, wrapped in batch-level obfuscation (8-part assembly, decoys, time-branching). | What batch obfuscation looks like — and what it does NOT defeat |
reverse.ps1 |
TCP reverse shell with reconnect + UTF-8 streaming + ScriptBlock-isolated iex. |
Reverse-shell ergonomics; AMSI-visible PowerShell |
obfuscation-techniques.md |
Walks each obfuscation technique in malware.bat. Read with detection-and-defense.md open. |
What each layer is and isn't doing |
detection-and-defense.md |
Honest companion: AMSI, ScriptBlock Logging (4104), ETW, Sysmon. What catches each layer in 2026. | The reality check |
| Tool | Output |
|---|---|
tools/encode_ps.py |
Encode/decode PowerShell -EncodedCommand (base64 + UTF-16LE). Dual-use — IR uses this on captured payloads. |
tools/build_chain.py |
Reconfigure the lab for a fresh LHOST/LPORT/HTTP host. Regenerates the base64 in payload.bat, server.py, and reverse.ps1 in one shot. Prints a runbook. |
tools/lolbin_droppers.py |
Same payload URL → 13 LOLBin dropper one-liners (mshta, regsvr32, rundll32, wmic, certutil, bitsadmin, msiexec, cscript, msbuild, curl, three PowerShell flavors), each tagged with its MITRE ID and parent-child chain. Useful for studying the catalog and writing detections for it. |
tools/listener.py |
Stdlib TCP listener with timestamps + per-session log files + post-drop wait. Replaces nc -lvnp when you want logs. |
tools/obfuscate_ps.py |
8 command-line obfuscation transforms (backtick, concat, format, variable, reverse, case, env-binary, split-flags). Defeats string-match rules, not AMSI — see detection-and-defense.md. |
All tools are stdlib-only, single-file, CLI-first. Same MIT / lab-use terms.
Requires Python 3.8+, nc (netcat) or ncat, and a Windows host or VM with PowerShell 5+.
The server and listener can run on WSL, Kali, or any Linux box, and the dropper runs on the same machine (or a separate Windows host on the same network if you set LISTENER_HOST accordingly). All defaults assume everything on one box.
nc -lvnp 9001python server.pyYou'll see endpoint registrations and a hint about the listener.
Run one of:
payload.bator — to exercise the obfuscation chain:
malware.batA PS C:\...> prompt should appear in the netcat terminal. Type whoami, Get-Process | select -First 5, etc.
Use tools/build_chain.py to regenerate every file with new addresses in one shot:
python tools/build_chain.py \
--lhost 10.10.14.5 --lport 4444 \
--http-host 10.10.14.5 --http-port 8000 \
--writeThat rewrites payload.bat, reverse.ps1, and server.py with the new base64 and prints the runbook (listener command, target one-liner, etc.).
Almost nothing against modern defenders. The PowerShell stage is plaintext to AMSI the instant -EncodedCommand is decoded — the batch wrapper's 8-part assembly, XOR decoys, and time-branched control flow never reach the AV's view of the payload. See detection-and-defense.md for the full breakdown of which layers help, which are theatre, and what kills each one.
This is intentional. The repo's job is to make those failure modes legible by showing you a complete chain and then telling you exactly where it falls apart.
After reading and running this, you should be able to:
- Explain the LOLBin delivery chain:
cmd → mshta → wscript → powershelland why each step exists. - Read PowerShell
-EncodedCommandpayloads by base64-decoding from UTF-16LE. - Identify which obfuscation layers an analyst will see in static review vs. dynamic.
- Point to the specific Windows logging primitives that defeat each layer (AMSI, EID 4104, Sysmon EID 1, ETW PowerShell provider).
- Articulate why
mshta+ VBScript is end-of-life on Windows 11 23H2+.
- AMSI bypass code. Public bypasses are detected and rotate quickly; this lab is about understanding the surface, not chasing a bypass treadmill.
- Persistence. Out of scope.
- Privilege escalation. Out of scope.
- Real C2 framework integration. If you want this against Sliver / Mythic / Havoc, swap
server.pyfor the framework's stager.
- Run
malware.batwith Defender enabled. Note the alert path (file, then payload, then network). - Enable PowerShell ScriptBlock Logging (
HKLM\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging\EnableScriptBlockLogging = 1) and observe Event ID 4104 inMicrosoft-Windows-PowerShell/Operational— the decoded script appears in full. - Watch
SysmonEvent ID 1 for the parent chaincmd.exe → mshta.exe → powershell.exe. That single transition is a high-fidelity rule on its own. - Modify
reverse.ps1to remove theiex-equivalent ([ScriptBlock]::Create) and see whether AMSI still flags it.
MIT. Educational use only.