Chapter 30

Alternate Data Streams

NTFS Alternate Data Streams (ADS) allow a file to have multiple named data streams — content invisible to normal file listing but fully accessible via the filesystem. The Zone.Identifier stream is the most forensically important, recording the internet zone and URL for any file downloaded from the internet.

Scenario

A suspicious executable — invoice.exe — is found on a compromised workstation. The MFT shows it was created yesterday. But was it compiled on this machine, copied from another internal system, or downloaded from the internet? The answer is in the Zone.Identifier ADS: the file has a :Zone.Identifier stream with Zone=3 (Internet) and a ReferrerUrl pointing to a malicious domain. This proves the file was downloaded from the internet — not compiled locally or copied from an internal share. This evidence is crucial for attributing the initial access vector.

ADS Fundamentals

  NTFS Alternate Data Streams
  ═══════════════════════════════════════════════════════════════════

  Every NTFS file has at least one data stream: the main stream ($DATA)
  with no name. ADS are additional named streams on the same file.

  Accessing ADS:
    Normal file content:  filename.exe
    Named stream:         filename.exe:streamname
    Example:              invoice.exe:Zone.Identifier

  Key properties:
    ├── ADS are invisible to dir (no /r), File Explorer, most programs
    ├── ADS share the parent file's MFT record
    ├── ADS have their own size (separate from main stream)
    ├── ADS survive file copy (within NTFS volumes)
    └── ADS do NOT survive copy to FAT/exFAT (stripped when copying to USB)

  Forensic uses:
    1. Zone.Identifier: download origin tracking (most common)
    2. Malware hiding payload in ADS (less common but documented)
    3. Data hiding: attacker stores exfiltration staging in ADS
    4. Watermarking: Microsoft Office SmartArt data in document streams

  Common stream names:
    :Zone.Identifier     → Internet zone + URL of origin (all Windows downloads)
    :SmartScreen         → SmartScreen check result
    :encryptable         → Encryption flag (rare)
    :DATA                → Additional data streams (malware/steganography)

Zone.Identifier Analysis

PowerShellzone-identifier.ps1
# Find and analyze Zone.Identifier streams on the live system
# Also works on files extracted from disk images (copy to analysis workstation first)

# List all files with ADS in a directory
Get-ChildItem -Path "C:\Users\jsmith\Downloads" -Recurse |
    Get-Item -Stream * |
    Where-Object { $_.Stream -ne ':$DATA' } |
    Select-Object FileName, Stream, Length |
    Format-Table -AutoSize

# Read Zone.Identifier for a specific file
Get-Content "C:\Users\jsmith\Downloads\invoice.exe" -Stream "Zone.Identifier"
# Output:
# [ZoneTransfer]
# ZoneId=3
# ReferrerUrl=http://evil-phish-site.com/
# HostUrl=http://evil-phish-site.com/invoice.exe

# ZoneId values:
# 0 = Local Computer (no web download)
# 1 = Local Intranet
# 2 = Trusted Sites
# 3 = Internet (most common for malware downloads)
# 4 = Restricted Sites

# Bulk Zone.Identifier analysis — find all internet-zone downloads
Get-ChildItem "C:\Users" -Recurse -File -ErrorAction SilentlyContinue |
    ForEach-Object {
        try {
            $zone = Get-Content $_.FullName -Stream "Zone.Identifier" -ErrorAction Stop
            if ($zone -match "ZoneId=3") {
                $refUrl = ($zone | Select-String "ReferrerUrl=").Line -replace "ReferrerUrl=", ""
                $hostUrl = ($zone | Select-String "HostUrl=").Line -replace "HostUrl=", ""
                [PSCustomObject]@{
                    File        = $_.FullName
                    Modified    = $_.LastWriteTime
                    ZoneId      = 3
                    ReferrerUrl = $refUrl
                    HostUrl     = $hostUrl
                }
            }
        } catch {}
    } | Export-Csv "D:\analysis\zone-identifier.csv" -NoTypeInformation

Detecting ADS in Disk Images

Bashads-detection-tsk.sh
IMAGE="/cases/CASE-2026-009/FINANCE-SRV01.E01"
OFFSET=2048

# fls -a shows alternate data streams (ADS) in file listings
fls -a -o $OFFSET $IMAGE -r | grep ":" | grep -v ":$DATA\|:$I30\|:$ObjId\|:$REPARSE_POINT\|:$Security_Id"
# The grep filters out common NTFS metadata streams
# Remaining : entries are user-created or interesting named streams

# icat to extract the ADS content
# Zone.Identifier stream inode syntax: inode-stream
# Get the inode from fls, then specify the stream
fls -r -o $OFFSET $IMAGE | grep "invoice.exe"
# → r/r 123456-128-1: invoice.exe
# ADS for that file:
# r/r 123456-128-3: invoice.exe:Zone.Identifier

# Extract Zone.Identifier content:
icat -o $OFFSET $IMAGE 123456-128-3
Bashads-with-mftecmd.sh
# MFTECmd also reports ADS in its CSV output
# HasAds column = True means the file has named streams
# IsAds column = True means this row is an ADS entry (not the main file)

# From KAPE-collected MFT:
MFTECmd.exe -f "$TRIAGE\C\$MFT" --csv "$OUT\mft" --csvf mft.csv

# In PowerShell, filter for ADS entries:
$mft = Import-Csv "$OUT\mft\mft.csv"
$mft | Where-Object { $_.IsAds -eq "True" } |
    Select-Object FileName, ParentPath, FileSize, Created0x10 |
    Where-Object { $_.FileName -notmatch "^\:(\$|REPARSE|ObjId|Security)" } |
    Format-Table -AutoSize

Malware Hidden in ADS

ADS malware techniqueExampleDetection
Hiding executable in ADS of harmless filereadme.txt:payload.exe — the .txt appears empty but :payload.exe contains a PEfls -a shows the ADS with executable size; icat extracts it; file(1) identifies PE header
Data staging in ADSAttacker writes credential dump to desktop.ini:creds.txt — invisible to dir, appears as 0-byte desktop.ini to casual inspectionMFTECmd HasAds=True; dir /r shows streams; Get-Item -Stream * reveals the hidden content
Loading executable from ADSwscript.exe readme.txt:payload.js — executes script hidden in ADSPrefetch records wscript.exe execution; Event 4688 shows the colon-notation command line; AMSI logs the script content
Why Zone.Identifier is one of the most valuable evidence sources in initial access investigations

When an attacker delivers malware via phishing, drive-by download, or watering hole — the delivered file has a Zone.Identifier stream recording exactly where it came from (ReferrerUrl = the phishing page, HostUrl = the actual download URL). This stream is set by Windows automatically when any file is downloaded from the internet: browser downloads, Outlook attachments, Teams files — all get Zone.Identifier. The attacker can't control whether this stream is created (it's OS-level) and often doesn't remove it. Zone.Identifier analysis is frequently the fastest way to confirm initial access vector and extract the delivery URL for further threat intelligence investigation.

Q & A

Q: Zone.Identifier shows the file was downloaded from the internet, but the HostUrl points to a legitimate CDN. How do you get the real attacker domain?

Zone.Identifier records both the HostUrl (direct download URL, which may be a CDN) and the ReferrerUrl (the page that initiated the download). For spear-phishing campaigns, the ReferrerUrl is often the attacker's phishing page — even if the file was hosted on AWS S3 or Azure Blob (for reliability and evasion). Look at both fields: HostUrl might be https://s3.amazonaws.com/legitimate-looking-bucket/invoice.exe while ReferrerUrl is https://corp-finance-portal.evil.com/payments — the attacker's infrastructure. If both URLs are CDN-hosted, the phishing delivery chain may have additional hops. Cross-reference with browser history (which page was visited before the download?) and proxy logs (which HTTP request directly preceded the download?) to trace back to the original attacker domain.