This artifact enables triage to detect potential time stomped files.
Checks:
Optional:
Note: If an option is selected the artifact will also output additional metadata for context.
Available filters include:
PathRegex (OSPath): e.g ^C:\folder\file.ext$ or partial \folder\folder2\ or string|string2|string3
FileRegex: ^filename.ext$ or partial string1|string2
name: Windows.NTFS.Timestomp
author: "Matt Green - @mgreen27"
description: |
This artifact enables triage to detect potential time stomped files.
Checks:
- $STANDARD_INFORMATION “B” time prior to $FILE_NAME “B” time
- $STANDARD_INFORMATION “B” or "M" time has nanosecond precision.
- PE compile time prior to any $STANDARD_INFORMATION time stamp.
Optional:
- $STANDARD_INFORMATION “M” time prior to ShimCache timestamp
- $STANDARD_INFORMATION times prior to $I30 slack "B" or "M" times.
- Full PE metadata output.
Note: If an option is selected the artifact will also output additional metadata for context.
Available filters include:
PathRegex (OSPath): e.g ^C:\\folder\\file\.ext$ or partial \\folder\\folder2\\ or string|string2|string3
FileRegex: ^filename.ext$ or partial string1|string2
parameters:
- name: MFTDrive
description: |
The path to to the drive that holds the MFT file (can be a
pathspec).
default: "C:"
- name: PathRegex
description: "Regex search over FullPath."
default: "."
- name: FileRegex
description: "Regex search over FileName."
default: "."
type: regex
- name: UploadHits
type: bool
description: "Upload complete complete attribute data."
- name: ShimcacheTest
type: bool
description: "If PE, check $STANDARD_INFORMATION “M” time prior to ShimCache timestamp"
- name: I30Test
type: bool
description: "Check $STANDARD_INFORMATION times prior to $I30 slack B or M times."
- name: OutputPEInfo
type: bool
description: "Output full PE metadata information."
sources:
- query: |
-- find all MFT entries in scope
LET mft_entries = SELECT *,OSPath,FileName,FileNames,EntryNumber,
LastModified0x10,LastAccess0x10, LastRecordChange0x10,Created0x10, --SI used in test
LastModified0x30,Created0x30, -- FN used in test
IsDir,InUse,SI_Lt_FN,uSecZeros,
parse_pe(file=OSPath) as PE,
magic(path=OSPath) as Magic
FROM Artifact.Windows.NTFS.MFT(MFTDrive=MFTDrive,PathRegex=PathRegex,FileRegex=FileRegex)
--WHERE NOT IsDir
-- if MZ files collect shimcache to compare modification time
LET shimcache <= SELECT *
FROM if(condition= ShimcacheTest,
then= { SELECT Name, ModificationTime FROM Artifact.Windows.Registry.AppCompatCache() })
LET shimcache_mtime(target) = SELECT Name, ModificationTime FROM shimcache
WHERE Name = target
ORDER BY ModificationTime
LET i30 <= SELECT * FROM if(condition= I30Test,
then= {
SELECT * FROM foreach(
row={
SELECT dirname(path=OSPath) as Directory FROM mft_entries
GROUP BY Directory
},
query={
SELECT
split(sep_string='\\\\.\\',string=FullPath)[1] + '\\' + Name as FullPath,
IsSlack,MFTId,Mtime,Atime,Ctime,Btime
FROM Artifact.Windows.NTFS.I30(DirectoryGlobs=Directory,preconditions=True)
WHERE MFTId OR FullPath
})
})
LET find_i30_slack(inode,folder,filenames,mtime,ctime,slackcheck) = SELECT * FROM i30
WHERE MFTId = str(str=inode) OR ( split(sep_string='''\\.\''',string=FullPath)[1] = folder AND Name in filenames)
AND if(condition= slackcheck,
then= ( Mtime > mtime OR Btime > btime ) AND IsSlack,
else= True )
LET base_results = SELECT
OSPath,
dict(Created0x10=Created0x10,Created0x30=Created0x30) as CreatedTimestamps,
InUse,
SI_Lt_FN as `SI<FN`,uSecZeros,
if(condition=PE.FileHeader.TimeDateStamp,
then= if(condition= LastModified0x10 < PE.FileHeader.TimeDateStamp OR LastAccess0x10 < PE.FileHeader.TimeDateStamp OR LastRecordChange0x10 < PE.FileHeader.TimeDateStamp OR Created0x10 < PE.FileHeader.TimeDateStamp,
then= True,
else= False),
else= 'N/A') as SuspiciousCompileTime,
parse_ntfs(mft=EntryNumber, device=MFTDrive ) as NtfsMetadata,
Magic,
if(condition=PE, then=PE,else='N/A') as PE,
Created0x10,LastModified0x10,FileNames,EntryNumber,
if(condition= Magic=~'^PE' AND NOT Magic =~ '\(DLL\)',
then= if(condition= LastModified0x10 < shimcache_mtime(target=str(str=OSPath))[0].ModificationTime,
then= True,
else= False),
else= 'N/A') as SuspiciousShimcache,
if(condition= Magic=~'^PE' AND NOT Magic =~ '\(DLL\)',
then= shimcache_mtime(target=str(str=OSPath))[0],
else= 'N/A') as Shimcache,
if(condition = find_i30_slack(inode=EntryNumber,folder=dirname(path=OSPath),filenames=FileNames,mtime=LastModified0x10,ctime=Created0x10,slackcheck=True),
then= True,
else= False ) as SuspiciousI30,
find_i30_slack(inode=EntryNumber,folder=dirname(path=OSPath),filenames=FileNames,mtime=LastModified0x10,ctime=Created0x10,slackcheck=False) as I30
FROM mft_entries
LET results = SELECT * FROM if(condition= ShimcacheTest AND I30Test AND OutputPEInfo,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousShimcache,
SuspiciousI30,
NtfsMetadata,
Magic,
Shimcache,
I30,
PE
FROM base_results
},
else= if(condition= ShimcacheTest AND I30Test,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousShimcache,
SuspiciousI30,
NtfsMetadata,
Magic,
Shimcache,
I30
FROM base_results
},
else= if(condition= ShimcacheTest AND OutputPEInfo,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousShimcache,
NtfsMetadata,
Magic,
Shimcache,
PE
FROM base_results
},
else= if(condition= I30Test AND OutputPEInfo,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousI30,
NtfsMetadata,
Magic,
I30,
PE
FROM base_results
},
else= if(condition= ShimcacheTest,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousShimcache,
NtfsMetadata,
Magic,
Shimcache
FROM base_results
},
else= if(condition= I30Test,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
SuspiciousI30,
NtfsMetadata,
Magic,
I30
FROM base_results
},
else= if(condition= OutputPEInfo,
then={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
NtfsMetadata,
Magic,
PE
FROM base_results
},
else={
SELECT
OSPath,CreatedTimestamps,InUse,
`SI<FN`,uSecZeros,
SuspiciousCompileTime,
NtfsMetadata,
Magic
FROM base_results
})
))))))
LET upload_results = SELECT *, upload(file=OSPath) as Upload FROM results
SELECT * FROM if(condition= UploadHits,
then= upload_results,
else= results)