This artifact hunts for Alternate Data Streams on NTFS file systems. Adversaries may use NTFS file attributes for covert storage to evade detection. Alternate Data Streams (ADS) are additional $DATA attributes for an MFT entry in NTFS file systems. In NTFS, the primary $DATA attribute is never named but subsequent $DATA attributes must be named.
Targeting is via mix of path globs and include / exclude regex.
name: Windows.NTFS.ADSHunter
author: "Matt Green - @mgreen27"
description: |
This artifact hunts
for Alternate Data Streams on NTFS file systems.
Adversaries may use NTFS file attributes for covert storage to evade
detection.
Alternate Data Streams (ADS) are additional $DATA attributes for an MFT entry in
NTFS file systems. In NTFS, the primary $DATA attribute is
never named but subsequent $DATA attributes must be named.
Targeting is via mix of path globs and include / exclude regex.
- TargetGlob is a glob to target for ADS. NOTE **\* is recursive. To hit C drive we need to search for C:\*
- AdsName is name in glob format: e.g *, Zone.Identifier or Zone.*.
- AdsNameExclusion - A regex value, common ADS added to exclusions have been
added by default. The artifact also excludes NTFS system files by default.
reference:
- https://attack.mitre.org/techniques/T1564/004/
type: CLIENT
parameters:
- name: TargetGlob
description: A Glob to search for target files. **\* is recursive. To hit C drive we need to search for C:\*
default: C:\{*,**\*}
- name: AdsNameGlob
description: AdsName in glob format. e.g *, Zone.Identifier or Zone.*
default: '*'
- name: AdsNameExclusion
description: Regex of ADS name to exclude.
default: 'SmartScreen|WofCompressedData|encryptable|favicon|AFP_AfpInfo|OECustomProperty|Win32App_1|com\.dropbox|icasource|\{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\}\.(MetaData|SyncRootIdentity)'
type: regex
- name: AdsContentRegex
description: ADS content to search for by regex.
default: .
type: regex
- name: AdsContentExclusion
description: ADS content to exclude by regex.
type: regex
- name: MinSize
description: Optional - only include alternate data streams above this size in bytes.
type: int
- name: MaxSize
description: Optional - only include alternate data streams below this size in bytes.
type: int
- name: UploadDataStream
description: If selected wil upload non-resident data streams.
type: bool
sources:
- query: |
-- Collect ADS entries using glob but exclude ntfs objects that contain ads
LET ads_entries = SELECT OSPath,
split(string=Name,sep=':')[1] as AdsName,
Data.mft as Inode,
Size,
OSPath.Dirname + split(string=Name,sep=':')[0] as HostObject,
dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as HostTimestampsSI
FROM glob(globs=TargetGlob + ":" + AdsNameGlob,
accessor="ntfs",
nosymlink='Y')
WHERE
NOT OSPath =~ '''[a-z]:\\(\$Extend\\|\$Secure|\$UpCase|\$BadClus|\$Bitmap|\$Repair)'''
AND if(condition=MinSize,
then= Size > MinSize,
else= True )
AND if(condition= MaxSize,
then= Size < MaxSize,
else= True )
AND NOT if(condition=AdsNameExclusion,
then= AdsName =~ AdsNameExclusion,
else= False )
-- Extract content and filter
LET hits = SELECT *,
read_file(filename=OSPath[0]+Inode, accessor="mft",offset=0,length=1024) as AdsContent -- only upload first 1k of each hit
FROM ads_entries
WHERE AdsContent =~ AdsContentRegex
AND NOT if(condition=AdsContentExclusion,
then= AdsContent =~ AdsContentExclusion,
else= False )
-- upload hits
LET upload_hits = SELECT *,
upload(file=OSPath,accessor='ntfs') as Upload
FROM hits
-- output rows
SELECT * FROM if(condition=UploadDataStream,
then= upload_hits,
else= hits)