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 Explorerinvoice.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.
# Check the Zone.Identifier on a downloaded fileGet-Content "C:\Users\User\Downloads\setup.exe" -Stream Zone.Identifier
# Output:# [ZoneTransfer]# ZoneId=3# ReferringUrl=https://example.com/downloadZone 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.
:: Write a malicious executable into an ADS of a text file:: The text file remains readable and looks normaltype 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.
:: Attach a payload to a folder itselftype payload.exe > "C:\Windows\System32\:hidden.exe"
:: Execute itstart "" "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.
# 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 itschtasks /create /tn "WindowsLogService" /tr "wmic process call create 'C:\ProgramData\logs.txt:svc'" /sc onlogon /ru SYSTEMThe 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:
# Remove the Mark of the Web from a downloaded fileRemove-Item "malware.exe" -Stream Zone.Identifier
# Alternative using cmdecho. > "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:c2cfgThe 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 / Group | ADS Usage |
|---|---|
| Poweliks (2014) | Stored registry-based payload in ADS to survive reboots |
| Emotet | Used ADS to cache downloaded modules between stages |
| Various APTs | Zone.Identifier stripping to bypass SmartScreen |
| Backdoor.Fynloski | Hid configuration data in ADS of system DLLs |
| NTFS-targeting ransomware | Checked 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
# List all streams on a specific fileGet-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:
:: Scan a directory recursively for all ADSstreams.exe -s -accepteula C:\ProgramData\
:: Example suspicious output::: C:\ProgramData\logs.txt::: :svc:$DATA 245760 ← 240 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 Createdstatus: experimentaldescription: Detects creation of named data streams other than Zone.Identifierlogsource: product: windows category: file_eventdetection: 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: mediumtags: - attack.defense_evasion - attack.t1564.004 # MITRE: Hide Artifacts: NTFS File AttributesWhat a Forensic Investigation Looks Like
During an incident, work through this checklist:
- Scan temp and appdata directories first — these are highest-probability locations
- Check files with unusual size mismatches — a 1 KB
.txtfile with a 500 KB stream is a red flag - Look at directories, not just files — ADS can be attached to folders
- Check known-good system files — hosts file, DLLs in System32, scheduled task XML files
- Hash the stream contents — submit to VirusTotal or compare against known-bad hashes
- 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:
| Limitation | Impact |
|---|---|
| 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 ADS | Attacker cannot deliver ADS payloads inside zipped email attachments |
| Modern EDRs monitor stream creation — Sysmon 15 and commercial EDRs catch it | Increasingly detected at creation time |
Some AV engines now scan all streams — not just the default $DATA | Signature-based detection can catch known payloads in ADS |
File copy within NTFS preserves ADS — but xcopy /r and robocopy have flags to strip them | Incident 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:
- 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.
- 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 - Add ADS scanning to your incident response playbook — include
streams.exein your IR toolkit - Alert on Zone.Identifier removal — stripping Mark of the Web from downloaded executables is a strong indicator of intentional evasion
For red teamers:
- ADS for config storage is underdetected — storing C2 configuration in ADS of a system file is quieter than writing a new file to disk
- Test your target EDR’s Sysmon coverage — many deployments have Event ID 15 disabled or filtered too aggressively
- Combine with LOLBins for execution —
wmic,forfiles, andmshtacan execute from ADS paths without dropping new files - 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.
Related Posts
- Trust Me, I’m a Shortcut: How LNK Files Lie to Windows Explorer — another technique where Windows hides malicious content behind a trusted-looking facade
- LOLBins in 2026: How Attackers Use Windows Against Itself — ADS payloads are often executed via LOLBins to avoid spawning obvious processes
- Invisible Characters as an Attack Vector — related theme: hiding malicious intent in data that looks harmless
- Windows Event Log Security Analysis — understanding which Windows events matter most for detecting attacks like ADS abuse
Sources
- MITRE ATT&CK T1564.004 — Hide Artifacts: NTFS File Attributes
- Microsoft Docs — NTFS Alternate Data Streams
- Sysinternals Streams — ADS discovery tool
- Sysmon Event ID 15 — FileCreateStreamHash
- SwiftOnSecurity Sysmon Config — production-ready Sysmon baseline