This artifact detects screen captures by correlating events from the Microsoft-Windows-Win32k ETW provider which are triggered by common Windows API calls made when taking a screenshot. This can be useful for detecting remote access trojans, infostealers, and data exfiltration. Tested against Sliver, Meterpreter, and Empire. This will also trigger on legitimate tools such as ZoomIt, Greenshot, MsTeams, etc. which can be excluded on a case by case basis via the ProcessExceptionsRegex parameter.
name: Windows.ETW.ScreenshotTaken
author: Zane Gittins
description: |
This artifact detects screen captures by correlating events from the Microsoft-Windows-Win32k ETW provider which are triggered by common Windows API calls made when taking a screenshot. This can be useful for detecting remote access trojans, infostealers, and data exfiltration. Tested against Sliver, Meterpreter, and Empire. This will also trigger on legitimate tools such as ZoomIt, Greenshot, MsTeams, etc. which can be excluded on a case by case basis via the ProcessExceptionsRegex parameter.
# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT or NOTEBOOK
type: CLIENT_EVENT
parameters:
- name: ProcessExceptionsRegex
description: Except these processes.
type: string
default: "Explorer.exe"
- name: ScreenshotMaxRows
description: Maximum number of screenshot events to store in internal fifo queue for correlation.
type: int
default: 500
- name: ScreenshotMaxAge
description: Maximum age in seconds to retain screenshot events to store in internal fifo queue for correlation.
type: int
default: 90
sources:
- precondition:
SELECT OS From info() where OS = 'windows' AND version(plugin="dedup") >= 0
query: |
// WindowUpdate(1) - Triggered by BitBlt() we delay this by 5 seconds due to a race condition in correlating with screenshot events.
LET WindowUpdateEvents = SELECT
*
FROM delay(
query={
SELECT
*
FROM dedup(
query={
SELECT
*, System.ProcessID AS FirstPid
FROM watch_etw(
guid="{8c416c79-d49b-4f01-a467-e56d3aa8234c}",
level=4,
any=5120,
description="Microsoft-Windows-Win32k")
WHERE System.ID = 1
AND EventData.Hwnd = "0x0"
AND (EventData.Type = "2147483654" OR EventData.Type = "2147483655")
},
timeout=5,
key="FirstPid")
},
delay=5)
// GdiSysMemToken(33) - Created by EtwGdiSysMemToken() in win32kbase.sys
// PhysicalSurfCreate(52) - This is triggered by CreateCompatibleBitmap. Created by EtwPhysicalSurfCreateEvent() in win32kbase.sys
LET ScreenshotEvents = SELECT
*
FROM dedup(
query={
SELECT
*, System.ProcessID AS Pid
FROM watch_etw(
guid="{8c416c79-d49b-4f01-a467-e56d3aa8234c}",
level=4,
any=5120,
description="Microsoft-Windows-Win32k")
WHERE System.ID = 33 OR System.ID = 52
},
timeout=5,
key="Pid")
LET LastEvents = SELECT *, System.ProcessID AS ScreenshotPid
FROM fifo(query=ScreenshotEvents,
max_rows=ScreenshotMaxRows,
max_age=ScreenshotMaxAge)
LET Track = SELECT *
FROM foreach(row=WindowUpdateEvents,
query={
SELECT *, process_tracker_get(id=System.ProcessID).Data AS ProcInfo,
count(items=Pid) AS Count
FROM LastEvents
WHERE ScreenshotPid = FirstPid
GROUP BY Pid
})
WHERE Count >= 1
SELECT timestamp(string=System.TimeStamp) AS Timestamp,
ProcInfo,
ScreenshotPid AS Pid,
Count
FROM Track
WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex