This artifact hunts for Alternate Data Streams on NTFS file systems. Adversaries may use NTFS file attributes for covert storage in order 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 in order 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)