This Artifact enables querying the MFT with advanced filters such as time, path or other ntfs attributes.
Output is to Timeline field format to enable simple review across Timeline queries. The TimeOutput paramater enables configuring which NTFS attribute timestamps are in focus as event_time. for example: STANDARD_INFORMATION (4), FILE_NAME (4) or ALL (8)
This artifact also has the same anomaly logic as AnalyzeMFT added to each row to assist analysis.
name: Windows.Timeline.MFT
description: |
# Output all filtered MFT records.
This Artifact enables querying the MFT with advanced filters
such as time, path or other ntfs attributes.
Output is to Timeline field format to enable simple review across Timeline
queries. The TimeOutput paramater enables configuring which NTFS attribute
timestamps are in focus as event_time. for example:
STANDARD_INFORMATION (4), FILE_NAME (4) or ALL (8)
This artifact also has the same anomaly logic as AnalyzeMFT added to
each row to assist analysis.
author: Matt Green - @mgreen27
precondition: SELECT OS From info() where OS = 'windows'
parameters:
- name: MFTFilename
default: "C:/$MFT"
- name: Accessor
default: ntfs
- name: PathRegex
description: "regex search over OSPath."
type: regex
- name: NameRegex
default: .
type: regex
description: "regex search over File Name"
- name: Inode
type: int64
description: "search for inode"
- name: DateAfter
type: timestamp
description: "search for events after this date. YYYY-MM-DDTmm:hh:ssZ"
- name: DateBefore
type: timestamp
description: "search for events before this date. YYYY-MM-DDTmm:hh:ssZ"
- name: SizeMax
type: int64
description: "Entries in the MFT over this size in bytes."
- name: SizeMin
type: int64
description: "Entries in the MFT under this size in bytes."
- name: EntryType
description: |
Type of entry. File, Directory or Both.
type: choices
default: Both
choices:
- File
- Directory
- Both
- name: AllocatedType
description: |
Type of entry. Allocated, Unallocated or Both.
type: choices
default: Both
choices:
- Allocated
- Unallocated
- Both
- name: TimeOutput
description: |
Timestamps to output as event_time. SI, FN or both.
NOTE: both will output 8 rows per MFT entry.
type: choices
default: STANDARD_INFORMATION
choices:
- STANDARD_INFORMATION
- FILE_NAME
- ALL
sources:
- query: |
LET hostname <= SELECT Fqdn FROM info()
LET DateAfterTime <= if(condition=DateAfter,
then=DateAfter, else=timestamp(epoch="1600-01-01"))
LET DateBeforeTime <= if(condition=DateBefore,
then=DateBefore, else=timestamp(epoch="2200-01-01"))
LET records = SELECT *,
Created0x10 < Created0x30 as FNCreatedShift,
Created0x10.Unix * 1000000000 = Created0x10.UnixNano as USecZero,
Created0x10 > LastModified0x10 as PossibleCopy,
( LastAccess0x10 > LastModified0x10 AND LastAccess0x10 > Created0x10 ) as VolumeCopy
FROM parse_mft(filename=MFTFilename, accessor=Accessor)
WHERE
FileName =~ NameRegex AND
OSPath =~ PathRegex AND
if(condition=Inode, then= EntryNumber=atoi(string=Inode)
OR ParentEntryNumber=atoi(string=Inode),
else=TRUE) AND
if(condition=SizeMax, then=FileSize < SizeMax,
else=TRUE) AND
if(condition=SizeMin, then=FileSize > SizeMin,
else=TRUE) AND
if(condition= EntryType="Both", then=TRUE,
else= if(condition= EntryType="File",
then= IsDir=False,
else= if(condition= EntryType="Directory",
then= IsDir=True))) AND
if(condition= AllocatedType="Both", then=TRUE,
else= if(condition= AllocatedType="Allocated",
then= InUse=True,
else= if(condition= AllocatedType="Unallocated",
then= InUse=False))) AND
(((Created0x10 > DateAfterTime) AND (Created0x10 < DateBeforeTime)) OR
((Created0x30 > DateAfterTime) AND (Created0x30 < DateBeforeTime)) OR
((LastModified0x10 > DateAfterTime) AND (LastModified0x10 < DateBeforeTime)) OR
((LastModified0x30 > DateAfterTime) AND (LastModified0x30 < DateBeforeTime)) OR
((LastRecordChange0x10 > DateAfterTime) AND (LastRecordChange0x10 < DateBeforeTime)) OR
((LastRecordChange0x30 > DateAfterTime) AND (LastRecordChange0x30 < DateBeforeTime)) OR
((LastAccess0x10 > DateAfterTime) AND (LastAccess0x10 < DateBeforeTime)) OR
((LastAccess0x30 > DateAfterTime) AND (LastAccess0x30 < DateBeforeTime)))
LET common_fields = SELECT EntryNumber, ParentEntryNumber,
OSPath, FileName, FileSize, IsDir,InUse,
Created0x10, Created0x30,
LastModified0x10, LastModified0x30,
LastRecordChange0x10, LastRecordChange0x30,
LastAccess0x10, LastAccess0x30,
FNCreatedShift, USecZero, PossibleCopy, VolumeCopy
FROM scope()
LET standard_information_rows = SELECT * FROM chain(
si_modified = {
SELECT *,
LastModified0x10 as event_time,
format(format="MFTEntry:%v $STANDARD_INFORMATION (0x10) LastModified time",
args=EntryNumber) as message
FROM common_fields
},
si_access = {
SELECT *,
LastAccess0x10 as event_time,
format(format="MFTEntry:%v $STANDARD_INFORMATION (0x10) LastAccess time",
args=EntryNumber) as message
FROM common_fields
},
si_created = {
SELECT *,
LastRecordChange0x10 as event_time,
format(format="MFTEntry:%v $STANDARD_INFORMATION (0x10) LastRecordChange time",
args=EntryNumber) as message
FROM common_fields
},
si_born = {
SELECT *,
Created0x10 as event_time,
format(format="MFTEntry:%v $STANDARD_INFORMATION (0x10) Created time",
args=EntryNumber) as message
FROM common_fields
})
LET file_name_rows = SELECT * FROM chain(
fn_modified = {
SELECT *,
LastModified0x30 as event_time,
format(format="MFTEntry:%v $FILE_NAME (0x30) LastModified time",
args=EntryNumber) as message
FROM common_fields
},
fn_access = {
SELECT *,
LastAccess0x30 as event_time,
format(format="MFTEntry:%v $FILE_NAME (0x30) LastAccess time",
args=EntryNumber) as message
FROM common_fields
},
fn_created = {
SELECT *,
LastRecordChange0x30 as event_time,
format(format="MFTEntry:%v $FILE_NAME (0x30) LastRecordChange time",
args=EntryNumber) as message
FROM common_fields
},
fn_born = {
SELECT *,
Created0x30 as event_time,
format(format="MFTEntry:%v $FILE_NAME (0x30) Created time",
args=EntryNumber) as message
FROM common_fields
})
SELECT
event_time,
hostname.Fqdn[0] as hostname,
"MFT" as parser,
MFTFilename as source,
message,
OSPath as path,
{ SELECT EntryNumber,ParentEntryNumber,FileSize,
IsDir, InUse
FROM scope() } as optional_1,
{ SELECT FNCreatedShift, USecZero, PossibleCopy,
VolumeCopy
FROM scope() } as optional_2,
{ SELECT LastModified0x10,LastAccess0x10,
LastRecordChange0x10,Created0x10
FROM scope() } as optional_3,
{ SELECT LastModified0x30,LastAccess0x30,
LastRecordChange0x30,Created0x30
FROM scope() } as optional_4
FROM foreach(
row=records,
query={
SELECT * FROM chain(
standard_information={
SELECT * FROM if(
condition=TimeOutput="STANDARD_INFORMATION" OR TimeOutput="ALL",
then=standard_information_rows)
},
file_name={
SELECT * FROM if(
condition=TimeOutput="FILE_NAME" OR TimeOutput="ALL",
then=file_name_rows)
})
})