A file on your Windows system says it is 4 KB. It contains a Word document. But inside the same file, invisible to Explorer, Task Manager, and most antivirus scanners, sits a fully functional executable. This is not a vulnerability — it is a documented feature of the Windows filesystem that attackers have been exploiting for over two decades.

TL;DR

  • NTFS filesystems support multiple named data streams per file — most tools only show the default (unnamed) stream
  • Attackers use Alternate Data Streams (ADS) to hide executables, scripts, and C2 configs inside innocent files
  • ADS survives reboots, is invisible in Explorer, and bypasses many AV scanners that only read the primary stream
  • Windows itself uses ADS legitimately (Zone.Identifier for Mark of the Web)
  • Detection requires specific tools: PowerShell Get-Item, Sysinternals Streams, or Sysmon Event ID 15

Why This Matters

Every security professional knows to look for suspicious executables in temp folders and to check running processes. Fewer think to look inside a legitimate file for hidden content attached to it.

ADS is a persistence and evasion technique that exploits a gap in how most tools display files. If your endpoint detection only inspects what a file looks like rather than what it contains, you have a blind spot. Threat actors from nation-state APTs to commodity ransomware groups have exploited this gap — and the feature has been in every version of Windows since NT 3.1.


What Are Alternate Data Streams?

To understand ADS, you first need to understand how NTFS — the Windows filesystem — stores files.

Think of a file like an envelope. The normal content of the letter goes in the main compartment. But the NTFS envelope has hidden pockets: you can attach additional named compartments to the same envelope, and the outside of the envelope only ever shows the main compartment’s size and content.

Technically: every file in NTFS has at least one data stream, called the default stream or $DATA. Its name is blank — you access it simply by opening the file. But NTFS also supports named streams, which are additional data attached to the same file using the syntax filename.ext:streamname.

invoice.pdf ← the file you see in Explorer
invoice.pdf:$DATA ← the default stream (the actual PDF content)
invoice.pdf:payload ← an alternate data stream (hidden from Explorer)
invoice.pdf:config.ini ← another ADS (can have multiple)

All streams share the same filename and directory entry. Explorer shows only the default stream’s size. The hidden streams are completely invisible unless you use a tool that specifically queries for named streams.


ADS in the Wild: Legitimate Uses First

Windows itself uses ADS for a legitimate security purpose: the Zone.Identifier stream. When you download a file from the internet, Windows attaches this stream to mark where the file came from.

Terminal window
# Check the Zone.Identifier on a downloaded file
Get-Content "C:\Users\User\Downloads\setup.exe" -Stream Zone.Identifier
# Output:
# [ZoneTransfer]
# ZoneId=3
# ReferringUrl=https://example.com/download

Zone ID 3 means “Internet zone” — this is what triggers the “Do you want to run this file?” warning when you launch downloaded executables. Attackers frequently strip this stream to suppress the warning (a technique called “Mark of the Web bypass”).

Other legitimate uses include application metadata, thumbnail caches, and Office document properties. ADS itself is not malicious — but its invisibility makes it attractive for abuse.


How Attackers Use ADS

Hiding an Executable Inside a Text File

The simplest ADS attack: embed a payload inside a completely innocent file.

Terminal window
:: Write a malicious executable into an ADS of a text file
:: The text file remains readable and looks normal
type C:\tools\payload.exe > C:\public\readme.txt:hidden.exe
:: Execute it directly from the ADS using wmic (a LOLBin)
wmic process call create "C:\public\readme.txt:hidden.exe"

After this, readme.txt shows as a normal text file in Explorer. Its file size reflects only the text content. The embedded executable is invisible — until you specifically look for named streams.


Payload Inside a Directory

ADS can also be attached to directories, not just files. This is even less expected.

Terminal window
:: Attach a payload to a folder itself
type payload.exe > "C:\Windows\System32\:hidden.exe"
:: Execute it
start "" "C:\Windows\System32\:hidden.exe"

Most incident responders check files in suspicious directories. Fewer think to check if the directory itself has data attached to it.


Persistence via Scheduled Task + ADS

A common real-world pattern: use ADS to store the payload, then create persistence that references it.

Terminal window
# 1. Hide the payload in an ADS of a legitimate system file
$payload = [System.IO.File]::ReadAllBytes("C:\tools\beacon.exe")
$fs = [System.IO.File]::Open("C:\ProgramData\logs.txt:svc",
[System.IO.FileMode]::Create)
$fs.Write($payload, 0, $payload.Length)
$fs.Close()
# 2. Create a scheduled task that runs it
schtasks /create /tn "WindowsLogService" /tr "wmic process call create 'C:\ProgramData\logs.txt:svc'" /sc onlogon /ru SYSTEM

The scheduled task references a path that looks like a text file. The payload runs at every logon with SYSTEM privileges.


Zone.Identifier Stripping

Attackers frequently remove the Zone.Identifier stream to suppress Windows’ download warnings:

Terminal window
# Remove the Mark of the Web from a downloaded file
Remove-Item "malware.exe" -Stream Zone.Identifier
# Alternative using cmd
echo. > "malware.exe:Zone.Identifier"

After removal, Windows treats the file as if it was never downloaded from the internet. No warning dialog, no SmartScreen check.


ADS for C2 Configuration Storage

Some malware families use ADS to store their C2 configuration persistently, attached to a system file that is unlikely to be deleted:

C:\Windows\System32\drivers\etc\hosts:c2cfg

The hosts file itself remains functional and unmodified. The configuration data lives invisibly in the attached stream, read by the malware on startup.


Real-World Malware Examples

ADS abuse has been documented in multiple malware families and threat actor toolsets:

Malware / GroupADS Usage
Poweliks (2014)Stored registry-based payload in ADS to survive reboots
EmotetUsed ADS to cache downloaded modules between stages
Various APTsZone.Identifier stripping to bypass SmartScreen
Backdoor.FynloskiHid configuration data in ADS of system DLLs
NTFS-targeting ransomwareChecked for ADS to locate and encrypt all data streams

The technique is old — it predates Windows XP — but it remains effective because awareness of it is low outside specialist security teams.


Detection

PowerShell — List All ADS on a File or Directory

Terminal window
# List all streams on a specific file
Get-Item "C:\ProgramData\logs.txt" -Stream *
# Recursively find all ADS in a directory (excluding Zone.Identifier)
Get-ChildItem -Path "C:\ProgramData" -Recurse -ErrorAction SilentlyContinue |
ForEach-Object { Get-Item $_.FullName -Stream * -ErrorAction SilentlyContinue } |
Where-Object { $_.Stream -ne ':$Data' -and $_.Stream -ne 'Zone.Identifier' }

This is your fastest triage tool during an incident. Any result that is not Zone.Identifier or a known application stream warrants investigation.


Sysinternals Streams

Streams.exe from Sysinternals is purpose-built for ADS discovery:

Terminal window
:: Scan a directory recursively for all ADS
streams.exe -s -accepteula C:\ProgramData\
:: Example suspicious output:
:: C:\ProgramData\logs.txt:
:: :svc:$DATA 245760240 KB hidden in a "text file"

The size column is your first indicator. A text file with a 240 KB unnamed stream is immediately suspicious.


Sysmon — Event ID 15

Sysmon (System Monitor — a free Microsoft tool for endpoint logging) generates Event ID 15 when a file stream is created. This is one of the most valuable detection signals for ADS abuse.

<!-- Sysmon config to capture all stream creations -->
<RuleGroup name="" groupRelation="or">
<FileCreateStreamHash onmatch="include">
<Rule name="ADS_Creation" groupRelation="and">
<!-- Flag any named stream that isn't Zone.Identifier -->
<TargetFilename condition="contains not">Zone.Identifier</TargetFilename>
</Rule>
</FileCreateStreamHash>
</RuleGroup>

Event ID 15 captures:

  • The full file path
  • The stream name
  • A hash of the stream content
  • The process that created it

This lets you catch ADS creation in real time, not just during forensic investigation.


Sigma Rule — Suspicious ADS Creation

title: Suspicious Alternate Data Stream Created
status: experimental
description: Detects creation of named data streams other than Zone.Identifier
logsource:
product: windows
category: file_event
detection:
selection:
EventID: 15 # Sysmon FileCreateStreamHash
filter_legitimate:
TargetFilename|contains:
- 'Zone.Identifier'
- 'SmartScreen'
- 'AFP_AfpInfo' # macOS compatibility streams
filter_browsers:
Image|endswith:
- '\chrome.exe'
- '\firefox.exe'
- '\msedge.exe'
condition: selection and not (filter_legitimate or filter_browsers)
level: medium
tags:
- attack.defense_evasion
- attack.t1564.004 # MITRE: Hide Artifacts: NTFS File Attributes

What a Forensic Investigation Looks Like

During an incident, work through this checklist:

  1. Scan temp and appdata directories first — these are highest-probability locations
  2. Check files with unusual size mismatches — a 1 KB .txt file with a 500 KB stream is a red flag
  3. Look at directories, not just files — ADS can be attached to folders
  4. Check known-good system files — hosts file, DLLs in System32, scheduled task XML files
  5. Hash the stream contents — submit to VirusTotal or compare against known-bad hashes
  6. Correlate with Sysmon 15 events — find the process that created the stream and trace backwards

Limitations of ADS as an Attack Technique

ADS is not a silver bullet for attackers. It has meaningful constraints:

LimitationImpact
NTFS only — ADS does not survive copying to FAT32/exFAT (USB drives, older media)Payload is lost if the file is moved to non-NTFS storage
Does not survive most archive operations — ZIP, TAR strip ADSAttacker cannot deliver ADS payloads inside zipped email attachments
Modern EDRs monitor stream creation — Sysmon 15 and commercial EDRs catch itIncreasingly detected at creation time
Some AV engines now scan all streams — not just the default $DATASignature-based detection can catch known payloads in ADS
File copy within NTFS preserves ADS — but xcopy /r and robocopy have flags to strip themIncident responders can sanitize files if needed

The technique works best as a secondary persistence mechanism or configuration store, not as a primary delivery channel.


What You Can Do Today

For defenders:

  1. Deploy Sysmon with Event ID 15 enabled — this is the single highest-value detection for ADS abuse. Use the SwiftOnSecurity Sysmon config as a baseline.
  2. Run a baseline scan of high-risk directories right now:
    Terminal window
    Get-ChildItem C:\ProgramData,C:\Windows\Temp,$env:APPDATA -Recurse -EA SilentlyContinue |
    % { Get-Item $_.FullName -Stream * -EA SilentlyContinue } |
    ? { $_.Stream -notin ':$Data','Zone.Identifier' } |
    Select PSParentPath, Stream, Length
  3. Add ADS scanning to your incident response playbook — include streams.exe in your IR toolkit
  4. Alert on Zone.Identifier removal — stripping Mark of the Web from downloaded executables is a strong indicator of intentional evasion

For red teamers:

  1. ADS for config storage is underdetected — storing C2 configuration in ADS of a system file is quieter than writing a new file to disk
  2. Test your target EDR’s Sysmon coverage — many deployments have Event ID 15 disabled or filtered too aggressively
  3. Combine with LOLBins for executionwmic, forfiles, and mshta can execute from ADS paths without dropping new files
  4. Remember the copy limitation — if your payload needs to survive exfiltration or be sent as an attachment, ADS is the wrong choice

The Bigger Picture

ADS is a reminder that the filesystem is an attack surface. Most security tooling focuses on processes, network connections, and registry keys. The filesystem gets treated as passive storage — but its structure, permissions, and less-known features like named streams are all exploitable.

The good news is that detection is straightforward once you know what to look for. Sysmon Event ID 15, PowerShell stream enumeration, and Sysinternals Streams cover the detection surface well. The bad news is that most environments have never checked for ADS, and the technique has been viable since Windows NT.

Run the PowerShell scan above. You might be surprised what you find.



Sources