Windows.Events.TrackProcesses

This artifact uses sysmon and pslist to keep track of running processes using the Velociraptor process tracker.

The Process Tracker keeps track of exited processes, and resolves process callchains from it in memory cache.

This event artifact enables the global process tracker and makes it possible to run many other artifacts that depend on the process tracker.


name: Windows.Events.TrackProcesses
description: |
  This artifact uses sysmon and pslist to keep track of running
  processes using the Velociraptor process tracker.

  The Process Tracker keeps track of exited processes, and resolves
  process callchains from it in memory cache.

  This event artifact enables the global process tracker and makes it
  possible to run many other artifacts that depend on the process
  tracker.

type: CLIENT_EVENT

tools:
  - name: SysmonBinary
    url: https://live.sysinternals.com/tools/sysmon64.exe
    serve_locally: true

  - name: SysmonConfig
    url: https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml
    serve_locally: true

parameters:
  - name: AlsoForwardUpdates
    type: bool
    description: |
      If set we also send process tracker state updates to
      the server.
  - name: MaxSize
    type: int64
    description: Maximum size of the in memory process cache (default 10k)

  - name: SysmonFileLocation
    description: If set, we check this location first for sysmon installed.
    default: C:/Windows/sysmon64.exe

  - name: AddEnrichments
    type: bool
    description: Add process information enrichments (can use more resources)

sources:
  - precondition:
      SELECT OS From info() where OS = 'windows'

    query: |
      // Make sure sysmon is installed.
      LET _ <= SELECT * FROM Artifact.Windows.Sysinternals.SysmonInstall(
         SysmonFileLocation=SysmonFileLocation)

      LET UpdateQuery =
            SELECT * FROM foreach(row={
              SELECT *,
                     get(member='EventData') AS EventData
              FROM watch_etw(
                guid='{5770385f-c22a-43e0-bf4c-06f5698ffbd9}',
                description='Microsoft-Windows-Sysmon/Operational')
            }, query={
              SELECT * FROM switch(
              start={
                SELECT EventData.ProcessId AS id,
                       EventData.ParentProcessId AS parent_id,
                       "start" AS update_type,

                       -- We need to manually build the dict here so
                       -- we can maintain column ordering.
                       dict(
                           Pid=EventData.ProcessId,
                           Ppid=EventData.ParentProcessId,
                           Name=split(sep_string="\\", string=EventData.Image)[-1],
                           StartTime=EventData.UtcTime,
                           EndTime=NULL,
                           Username=EventData.User,
                           Exe=EventData.Image,
                           CommandLine= EventData.CommandLine,
                           CurrentDirectory= EventData.CurrentDirectory,
                           FileVersion=EventData.FileVersion,
                           Description= EventData.Description,
                           Company= EventData.Company,
                           Product= EventData.Product,
                           ParentImage= EventData.ParentImage,
                           ParentCommandLine= EventData.ParentCommandLine,
                           TerminalSessionId= EventData.TerminalSessionId,
                           IntegrityLevel= EventData.IntegrityLevel,
                           Hashes=parse_string_with_regex(regex=[
                             "SHA256=(?P<SHA256>[^,]+)",
                             "MD5=(?P<MD5>[^,]+)",
                             "IMPHASH=(?P<IMPHASH>[^,]+)"],
                           string=EventData.Hashes)
                       ) AS data,
                       EventData.UtcTime AS start_time,
                       NULL AS end_time
                FROM scope()
                WHERE System.ID = 1
              },
              end={
                SELECT EventData.ProcessId AS id,
                       NULL AS parent_id,
                       "exit" AS update_type,
                       dict() AS data,
                       NULL AS start_time,
                       EventData.UtcTime AS end_time
                FROM scope()
                WHERE System.ID = 5
              })
            })

      LET SyncQuery =
              SELECT Pid AS id,
                 Ppid AS parent_id,
                 CreateTime AS start_time,
                 dict(
                   Name=Name,
                   Username=Username,
                   Exe=Exe,
                   CommandLine=CommandLine) AS data
              FROM pslist()

      LET Tracker <= process_tracker(
         max_size=MaxSize,
         enrichments=if(condition=AddEnrichments, then=[
           '''x=>if(
                condition=NOT x.Data.VersionInformation AND x.Data.Image,
                then=dict(VersionInformation=parse_pe(file=x.Data.Image).VersionInformation))
           ''',
           '''x=>if(
                condition=NOT x.Data.OriginalFilename OR x.Data.OriginalFilename = '-',
                then=dict(OriginalFilename=x.Data.VersionInformation.OriginalFilename))
           '''], else=[]),
        sync_query=SyncQuery, update_query=UpdateQuery, sync_period=60000)

      SELECT * FROM process_tracker_updates()
      WHERE update_type = "stats" OR AlsoForwardUpdates