Adversaries may use NTFS file attributes for defence evasion to hide malicious data. This artifact parses NTFS Extended attributes ($EA). The artifact firstly queries the MFT, then enriches NTFS data to check for Extended Attributes. Several filters can be applied such as file search, Extended Attribute size, name or content.
NOTE: By default an EAName exclusion has been applied to filter some common $EA names found on Windows System. Recommended hunt would be by rare name or $EA size. By default we only parse $EA and discard $EA_INFORMATION. $EA_INFORMATION typically is very small and available in NtfsMetadata field of output.
name: Windows.NTFS.ExtendedAttributes
author: "Matt Green - @mgreen27"
description: |
Adversaries may use NTFS file attributes for defence evasion to hide malicious
data. This artifact parses NTFS Extended attributes ($EA).
The artifact firstly queries the MFT, then enriches NTFS data to check for
Extended Attributes. Several filters can be applied such as file search,
Extended Attribute size, name or content.
NOTE:
By default an EAName exclusion has been applied to filter some common $EA names
found on Windows System. Recommended hunt would be by rare name or $EA size.
By default we only parse $EA and discard $EA_INFORMATION. $EA_INFORMATION
typically is very small and available in NtfsMetadata field of output.
reference:
- https://attack.mitre.org/techniques/T1564/004/
- https://posts.specterops.io/host-based-threat-modeling-indicator-design-a9dbbb53d5ea
- http://inform.pucp.edu.pe/~inf232/Ntfs/ntfs_doc_v0.5/attributes/ea.html
parameters:
- name: MFTDrive
default: "C:"
- name: HostPathRegex
description: "Regex search over OSPath."
default: "."
type: regex
- name: DateAfter
type: timestamp
description: "search for host files with timestamps after this date. YYYY-MM-DDTmm:hh:ssZ"
- name: DateBefore
type: timestamp
description: "search for host files with timestamps before this date. YYYY-MM-DDTmm:hh:ssZ"
- name: AllDrives
type: bool
description: "Select MFT search on all attached ntfs drives."
- name: EANameRegex
description: "$EA Name regex filter to include in results."
default: .
type: regex
- name: EANameExclusion
description: Regex of ADS name to exclude.
default: ^(\$KERNEL\.PURGE\.(ESBCACHE|APPXFICACHE)|\$CI\.CATALOGHINT|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\.CSC\.\w+)$
type: regex
- name: EAContentRegex
description: "$EA content to search for by regex."
default: .
type: regex
- name: SizeMax
type: int64
description: "Total $EA attributes in the MFT under this size in bytes."
default: 100000
- name: SizeMin
type: int64
description: "Total $EA attributes in the MFT over this size in bytes."
default: 0
- name: UploadHits
type: bool
description: "Upload complete complete attribute data."
sources:
- query: |
LET Profile = '''[
["EAData", 0, [
["Entries", 0, "Array",{
"type": "EA",
"count": 99 }],
]],
["EA", "x=>x.__NextOffset", [
["__NextOffset", 0, "uint32"],
["__NameLength", 5, "uint8"],
["__ValueLength", 6, "uint16"],
["Name", 8, String, {
length: "x=>x.__NameLength" }],
["Flags", 4, "uint8"],
["ValueLength", 6, "uint16"],
["Value", "x=>9 + x.__NameLength", "String",{
term: "********** NO TERM **********",
length: "x=>x.__ValueLength",
max_length: 10000 }],
]]
]'''
-- find all MFT entries with an $EA - ignore VSS
LET mft_entries = SELECT *,
parse_ntfs(mft=EntryNumber, device=MFTDrive ) as NtfsMetadata
FROM Artifact.Windows.NTFS.MFT(
MFTDrive=MFTDrive,
Accessor='ntfs',
PathRegex=HostPathRegex,
DateAfter=DateAfter,
DateBefore=DateBefore,
AllDrives=AllDrives)
WHERE -- NOT OSPath =~ 'HarddiskVolumeShadowCopy' AND
NtfsMetadata.Attributes.Type =~ '^\\$EA'
-- enrich results for size filter, dropping metadata field output as this attribute is viewable in Ntfs field.
LET enriched_results = SELECT OSPath,NtfsMetadata,
--{ SELECT * FROM NtfsMetadata.Attributes WHERE Type = '$EA_INFORMATION'} as _EA_INFORMATION_Metadata,
{ SELECT * FROM NtfsMetadata.Attributes WHERE Type = '$EA'} as _EA_Metadata
FROM mft_entries
WHERE _EA_Metadata.Size > SizeMin AND _EA_Metadata.Size < SizeMax
-- parse EA attribute
LET parse_ea = SELECT OSPath, NtfsMetadata, _EA_Metadata,
parse_binary(accessor="mft",
filename=NtfsMetadata.Device + _EA_Metadata.Inode,
profile=Profile, struct="EAData").Entries AS EA
FROM enriched_results
-- flattern results and output a row for each EA parsed
LET flatten_results = SELECT OSPath, NtfsMetadata, EA, _EA_Metadata
FROM flatten(
query={
SELECT *
{
SELECT Name,Value,Flags,ValueLength
FROM foreach(row=EA)
} as EA
FROM parse_ea
WHERE EA.Name =~ EANameRegex
AND NOT if(condition=EANameExclusion,
then= EA.Name =~ EANameExclusion,
else= False )
AND EA.Value =~ EAContentRegex
})
-- upload extended EA data
LET upload_hits=SELECT OSPath, NtfsMetadata, EA,
upload(file=NtfsMetadata.Device + _EA_Metadata.Inode,accessor='mft') AS Upload
--upload(file=Ntfs.Device + _EA_INFORMATION_Metadata.Inode,accessor='mft') AS EA_INFORMATION_Upload
FROM flatten_results
-- return rows
SELECT *
FROM if(condition=UploadHits,
then=upload_hits,
else=flatten_results)