<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Artifact Exchange on Velociraptor - Digging deeper!</title><link>https://docs.velociraptor.app/exchange/</link><description>Recent content in Artifact Exchange on Velociraptor - Digging deeper!</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://docs.velociraptor.app/exchange/index.xml" rel="self" type="application/rss+xml"/><item><title>Alert.Windows.EVTX.PowerPickHostVersion</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/powerpickhostversion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/powerpickhostversion/</guid><description>&lt;p&gt;This artifact by itself only indicates that the PowerPick tool may have
been invoked on the client. To capture additional context, ensure that
Powershell script block and module logging are enabled on the clients and
deploy the Windows.ETW.Powershell artifact from the Exchange.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This artifact is based on on PowerPick research by Crowdstrike in
&lt;a href="https://www.crowdstrike" target="_blank" &gt;https://www.crowdstrike&lt;/a&gt;
[.]com/blog/getting-the-bacon-from-cobalt-strike-beacon/&lt;/p&gt;
&lt;p&gt;As noted in the blog post, when PowerPick tool is run, the PowerShell logs
on the target system may contain an EID 400 event where the
HostVersion and EngineVersion fields in the message have different values.&lt;/p&gt;
&lt;p&gt;In recent puprle team exercises, we observed that the mismatched HostVersion
value was always &amp;ldquo;1.0&amp;rdquo;, providing a simple way to monitor for this activity
as a backup to other PowerShell or CobaltStrike rules.&lt;/p&gt;
&lt;p&gt;If this artifact generates an event on a client, check the PowerShell Operational
logs for suspicious 410x events (especially 4104). If the Windows.ETW.Powershell
artifact is also enabled on the client and did not fire an event, update that
artifact&amp;rsquo;s IOC list with the new information and redeploy it.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Alert.Windows.EVTX.PowerPickHostVersion
author: sbattaglia-r7
description: |
 
 This artifact by itself only indicates that the PowerPick tool may have
 been invoked on the client. To capture additional context, ensure that
 Powershell script block and module logging are enabled on the clients and
 deploy the Windows.ETW.Powershell artifact from the Exchange.
 
 -----
 
 This artifact is based on on PowerPick research by Crowdstrike in 
 https://www.crowdstrike[.]com/blog/getting-the-bacon-from-cobalt-strike-beacon/
 
 As noted in the blog post, when PowerPick tool is run, the PowerShell logs
 on the target system may contain an EID 400 event where the
 HostVersion and EngineVersion fields in the message have different values.
 
 In recent puprle team exercises, we observed that the mismatched HostVersion
 value was always "1.0", providing a simple way to monitor for this activity 
 as a backup to other PowerShell or CobaltStrike rules.
 
 If this artifact generates an event on a client, check the PowerShell Operational
 logs for suspicious 410x events (especially 4104). If the Windows.ETW.Powershell
 artifact is also enabled on the client and did not fire an event, update that
 artifact's IOC list with the new information and redeploy it.
 

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT_EVENT

parameters:
 - name: pseventLog
 default: 'C:\Windows\System32\winevt\Logs\Windows PowerShell.evtx'

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

 query: |
 SELECT
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) AS EventTime,
 System.Computer as Computer,
 System.Channel as Channel,
 System.Provider.Name as Provider,
 System.EventID.Value as EventID,
 System.EventRecordID as EventRecordID,
 get(field="Message") as Message
 FROM watch_evtx(filename=pseventLog)
 WHERE EventID = 400 AND Message =~ 'HostVersion=1.0'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>CyberTriage.Collector</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/cybertriagecollector/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/cybertriagecollector/</guid><description>&lt;p&gt;Runs the Cyber Triage (&lt;a href="http://cybertriage.com" target="_blank" &gt;http://cybertriage.com&lt;/a&gt;
) Collector to copy forensic artifacts for automated analysis. The Dynamic collection will include EXEs, DLLs, and other files referenced by artifacts.
The output of the collection can be saved to a Velociraptor server, a Cyber Triage server, or cloud storage (S3 or Azure).
Configuration information is available at - &lt;a href="https://docs.cybertriage.com/en/latest/chapters/integrations/velociraptor_collect.html" target="_blank" &gt;https://docs.cybertriage.com/en/latest/chapters/integrations/velociraptor_collect.html&lt;/a&gt;

It requires the Velociraptor server to have copies of the Cyber Triage Deployer script and optional configuration files.
History. 1.0 - Initial artifact creation
Contact &lt;a href="mailto:support@cybertriage.com" &gt;support@cybertriage.com&lt;/a&gt;
 with any questions.
Copyright (c) 2025 Sleuth Kit Labs LLC. All rights reserved.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: CyberTriage.Collector
description: 
 Runs the Cyber Triage (http://cybertriage.com) Collector to copy
 forensic artifacts for automated analysis. The Dynamic collection
 will include EXEs, DLLs, and other files referenced by artifacts. 

 The output of the collection can be saved to a Velociraptor server, 
 a Cyber Triage server, or cloud storage (S3 or Azure).

 Configuration information is available at - 
 https://docs.cybertriage.com/en/latest/chapters/integrations/velociraptor_collect.html
 
 It requires the Velociraptor server to have copies of the Cyber Triage Deployer script and 
 optional configuration files. 
 
 History.
 1.0 - Initial artifact creation

 Contact support@cybertriage.com with any questions.

 Copyright (c) 2025 Sleuth Kit Labs LLC. All rights reserved. 
 
type: CLIENT

resources:
 timeout: 14400
 max_upload_bytes: 4294967296

parameters:
 - name: PowerShellExe
 default: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
 description: Where the PowerShell executable is located, this should not be changed unless you are using 
 a newer verison of PowerShell
 
 - name: script_temp_location
 default: "C:\\Windows\\temp\\deploy_cyber_triage_collector.ps1"
 description: Where the Deployer script will be downloaded to

 - name: CollectorConfig_temp_location
 default: "C:\\Windows\\temp\\CollectorConfig.yaml"
 description: Where the (optional) cloud storage configuration file will be copied to
 
 - name: filesets_temp_location
 default: "C:\\Windows\\temp\\filesets.yaml"
 description: Where the custom file rules configuration file will be copied to

 # This needs to be updated if the Deployer script writes data to a different location
 - name: outputFilesSpec
 description: List of files to copy back after the Collector runs. 
 type: csv
 default: |
 Glob
 Windows\Temp\file.json.gz*

 - name: Root
 description: |
 On Windows, this is the device to apply all the glob on
 (e.g. `C:`). On *NIX, this should be a path to a subdirectory or
 /.
 default: "C:"

 - name: Accessor
 default: auto
 description: |
 On Windows, this can be changed to `ntfs`.

tools:
 - name: deploy_cyber_triage_collector
 serve_locally: false

# TODO: Uncomment this if using cloud storage
# - name: CollectorConfig.yaml
# serve_locally: false

# TODO: Uncomment this if using custom file rules
# - name: filesets.yaml
# serve_locally: false

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

sources:
 - name: Run Deployer Script
 query: |
 // Get the path to the Deployer script on the server.
 LET collector &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName= "deploy_cyber_triage_collector", IsExecutable=FALSE,
 TemporaryOnly=FALSE)

 // Copy powershell script from Tools to c:\Windows\Temp. We had escaping issues when running from the download location.
 LET cp &amp;lt;= SELECT copy(filename=collector[0].OSPath, accessor="file", 
 dest=script_temp_location)
 FROM scope()

 
 // TODO: Uncomment below if using cloud storage config file. This copies the file from the server to temp folder. 
 //LET CollectorConfig &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 // ToolName= "CollectorConfig.yaml", IsExecutable=FALSE,
 // TemporaryOnly=FALSE)
 //LET cp1 &amp;lt;= SELECT copy(filename=CollectorConfig[0].OSPath, accessor="file", 
 // dest=CollectorConfig_temp_location)
 // FROM scope()


 
 // TODO: Uncomment below if using custom file collection rules. This copies the file from the server to temp folder. 
 //LET filesets &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 // ToolName= "filesets.yaml", IsExecutable=FALSE,
 // TemporaryOnly=FALSE)
 //LET cp2 &amp;lt;= SELECT copy(filename=filesets[0].OSPath, accessor="file", 
 // dest=filesets_temp_location)
 // FROM scope()

 
 // Launch the script - it will download and run the Collector
 SELECT * FROM execve(argv=[PowerShellExe,
 "-ExecutionPolicy", "Unrestricted", "-encodedCommand",
 base64encode(string=utf16_encode(string=script_temp_location))])

 // TODO: Remove the rest of this file if the Deployer script sends data to cloud or CT Server. 
 // This section will send the JSON file back to the server. 
 - name: Get Collector File Metadata and Upload
 query: |
 LET RootPath &amp;lt;= pathspec(Path=Root, accessor=Accessor)

 // Generate the collection globs for each device
 LET specs = SELECT RootPath + Glob AS Glob
 FROM outputFilesSpec
 WHERE log(message=format(
 format="Processing Device %v with %v: glob is %v",
 args=[Root, Accessor, Glob]))

 // Join all the collection rules into a single Glob plugin. This ensure we
 // only make one pass over the filesystem. We only want LFNs.
 LET hits = SELECT OSPath AS SourceFile, Size
 FROM glob(globs=specs.Glob, accessor=Accessor)
 WHERE NOT IsDir AND log(message="Found " + SourceFile)

 // Pass all the results to the next query. This will serialize
 // to disk if there are too many results.
 LET all_results &amp;lt;=
 SELECT Size, SourceFile
 FROM hits
 // Upload the files
 LET uploaded_files = SELECT * FROM foreach(row={
 SELECT * FROM all_results
 },
 workers=30,
 query={
 SELECT SourceFile, Size,
 upload(file=SourceFile, accessor=Accessor) AS Upload
 FROM scope()
 })

 // Separate the hashes into their own column.
 SELECT now() AS CopiedOnTimestamp, SourceFile,
 Upload.Path AS DestinationFile,
 Size AS FileSize, Upload.sha256 AS SourceFileSha256
 FROM uploaded_files

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Detection.Application.CursedChrome</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/detection.application.cursedchrome/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/detection.application.cursedchrome/</guid><description>&lt;p&gt;Detects the &lt;a href="https://github.com/mandatoryprogrammer/CursedChrome" target="_blank" &gt;Cursed Chrome&lt;/a&gt;
 extension. Starts by searching for permissive extensions configured within &lt;code&gt;Secure Preferences&lt;/code&gt;. Locates the path of the extensions and scans using Yara.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Detection.Application.CursedChrome
author: Matt Dri - @mattdri-ir
description: |
 Detects the [Cursed Chrome](https://github.com/mandatoryprogrammer/CursedChrome) extension. Starts by searching for permissive extensions configured within `Secure Preferences`. Locates the path of the extensions and scans using Yara.

type: CLIENT

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

 query: |
 LET yaraScan = '''
 rule cursed_chrome
 {
 strings:
 $s0 = "new WebSocket(\"ws://"
 $s1 = "new WebSocket(\"wss://"
 $s2 = "[1e7]+-1e3+-4e3+-8e3+-1e11"
 condition:
 ($s0 or $s1) and $s2
 }
 '''
 
 LET ext = SELECT parse_json(data=read_file(filename=FullPath)).extensions.settings AS ext
 FROM glob(
 globs=['''*:\Users\*\AppData\Local\Google\Chrome\User Data\*\Secure Preferences''', '''/Users/*/Library/Application Support/Google/Chrome/*/Secure Preferences'''])
 
 LET ext_of_interest = SELECT _value.path AS path
 FROM flatten(
 query={
 SELECT _value
 FROM foreach(
 row={
 SELECT items(item=ext) AS config
 FROM ext
 },
 column=["config"])
 })
 WHERE _value.granted_permissions.api =~ "webRequest"
 and (_value.granted_permissions.explicit_host =~ "&amp;lt;all_urls&amp;gt;" or _value.granted_permissions.explicit_host =~ "https://*/*")
 
 SELECT *
 FROM foreach(
 row={
 SELECT FullPath
 FROM foreach(
 row={
 SELECT path
 FROM ext_of_interest
 },
 query={
 SELECT *
 FROM glob(root=path,
 globs="**")
 WHERE NOT IsDir
 })
 },
 query={
 SELECT *
 FROM yara(files=FullPath,
 rules=yaraScan)
 })



&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Docker.Image.Export</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/docker.image.export/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/docker.image.export/</guid><description>&lt;p&gt;Uses the Docker UNIX socket to export a Docker image to a
tempfile and upload to Velociraptor.&lt;/p&gt;
&lt;p&gt;Analysis Tips:&lt;br&gt;
- &lt;a href="https://jellyparks.com/posts/compromised-container-analysis-primer/" target="_blank" &gt;https://jellyparks.com/posts/compromised-container-analysis-primer/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;#docker&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Docker.Image.Export
author: Brady Semm - @btsemm / DoppioRistretto
description: |
 Uses the Docker UNIX socket to export a Docker image to a
 tempfile and upload to Velociraptor.
 
 Analysis Tips: 
 - https://jellyparks.com/posts/compromised-container-analysis-primer/

 #docker
 
parameters:
 - name: dockerSocket
 description: |
 Docker server socket. You will normally need to be root to connect.
 default: /var/run/docker.sock
 - name: ImageNameOrID
 description: |
 Docker Image name or ID to export. Can include tag (eg. "image:latest")
 default: empty

sources:
 - precondition: |
 SELECT OS From info() where OS = 'darwin' OR OS = 'linux'
 query: |

 LET EncodedImageNameOrID = regex_replace(source=ImageNameOrID, replace_lambda="x=&amp;gt;format(format='%%%02x',args=x)", re="[^a-z0-9\\-_.~?]")
 LET docker_api_path = format(format="%v:unix/images/%v/get", args=[dockerSocket, EncodedImageNameOrID])
 LET response &amp;lt;= SELECT Content FROM http_client(url=docker_api_path, tempfile_extension=".tar", remove_last=true)
 
 SELECT upload(file=response.Content) from scope()

 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Exchange.Label.User</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.label.user/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.label.user/</guid><description>&lt;p&gt;This artifact watches for new client enrollments and automatically
label the client with the required label if the user exists.&lt;/p&gt;
&lt;p&gt;This artifact can be the starting point for automatically labeling
a machine based on any other property - just change the artifact to
watch and the result filter.&lt;/p&gt;
&lt;p&gt;#server #event #labels&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Exchange.Label.User
description: |
 This artifact watches for new client enrollments and automatically
 label the client with the required label if the user exists.

 This artifact can be the starting point for automatically labeling
 a machine based on any other property - just change the artifact to
 watch and the result filter.

 #server #event #labels

type: SERVER_EVENT

parameters:
 - name: Label
 default: MikesBox
 - name: NameRegex
 default: mike

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

 query: |
 LET user_flows = SELECT *
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ "Generic.Client.Info/Users"

 LET results = SELECT *,
 label(client_id=ClientId, labels=Label, op="set")
 FROM source(artifact="Generic.Client.Info/Users" ,
 client_id=ClientId, flow_id=FlowId)
 WHERE Name =~ NameRegex

 SELECT * FROM foreach(row=user_flows, query=results)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Exchange.Linux.Kunai</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.kunai/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.kunai/</guid><description>&lt;p&gt;Kunai is a Linux-based security monitoring and threat hunting tool written in Rust. This artifact parses the Kunai log file.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Exchange.Linux.Kunai
author: Wes Lambert -- @therealwlambert, @weslambert@infosec.exchange
description: |
 Kunai is a Linux-based security monitoring and threat hunting tool written in Rust. This artifact parses the Kunai log file. 
reference:
 - https://github.com/0xrawsec/kunai 
parameters:
 - name: LogFile
 default: kunai.log
 description: Path of Kunai log file

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

 query: |
 SELECT
 info.utc_time AS Timestamp,
 info.host.hostname AS Hostname,
 info.host.container AS _Container,
 info.event.id AS EventID,
 info.event.name AS EventName,
 info.event.uuid AS EventUUID,
 data.command_line AS CommandLine,
 data.exe AS Exe,
 data.path AS Path,
 info.event.batch AS _EventBatch,
 info.task AS Task,
 info.parent_task AS ParentTask
 FROM parse_jsonl(filename=LogFile)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Exchange.Server.Enrichment.Gimphash</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.server.enrichment.gimphash/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.server.enrichment.gimphash/</guid><description>&lt;p&gt;Calculate the Gimphash for a Golang binary.&lt;/p&gt;
&lt;p&gt;See: &lt;a href="https://github.com/NextronSystems/gimphash" target="_blank" &gt;https://github.com/NextronSystems/gimphash&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking for Golang binaries) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.Gimphash(File=$YOURFILE)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;NOTE: You will need to change the tool URL if using Linux as your server OS.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Exchange.Server.Enrichment.Gimphash
description: |
 Calculate the Gimphash for a Golang binary.
 
 See: https://github.com/NextronSystems/gimphash
 
 This artifact can be called from within another artifact (such as one looking for Golang binaries) to enrich the data made available by that artifact.
 
 Ex.
 
 `SELECT * from Artifact.Server.Enrichment.Gimphash(File=$YOURFILE)`
 
 NOTE: You will need to change the tool URL if using Linux as your server OS.
 
author: Wes Lambert -- @therealwlambert
tools:
 - name: Gimphash
 url: https://github.com/NextronSystems/gimphash/releases/download/0.2.0/go_gimphash_windows.exe
parameters:
 - name: File
 type: string
 description: File for which Gimphash is to be calculated
 default:
sources:
 - query: |
 LET GH &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Gimphash", IsExecutable=FALSE)
 LET ExecGH &amp;lt;= SELECT * FROM execve(argv=[
 GH.FullPath[0], File])
 SELECT grok(grok=("%{DATA:gimphash} %{GREEDYDATA:file}"), data=Stdout).file AS File, grok(grok=("%{DATA:gimphash} %{GREEDYDATA:file}"), data=Stdout).gimphash AS Gimphash FROM ExecGH 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Exchange.Windows.EventLogs.Hayabusa.Takajo</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.windows.eventlogs.hayabusa.takajo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.windows.eventlogs.hayabusa.takajo/</guid><description>&lt;p&gt;[Takajo] (&lt;a href="https://github.com/Yamato-Security/takajo" target="_blank" &gt;https://github.com/Yamato-Security/takajo&lt;/a&gt;
) is a fast forensics analyzer
for Hayabusa results written in Nim. Takajō means &amp;ldquo;Falconer&amp;rdquo; in Japanese
and was chosen as it analyzes Hayabusa&amp;rsquo;s &amp;ldquo;catches&amp;rdquo; (results).&lt;/p&gt;
&lt;p&gt;First, it will call Exchange.Windows.EventLogs.Hayabusa to execute the following commandline to create the hayabusa_results.jsonl: &amp;ldquo;hayabusa.exe json-timeline -d &lt;EVTX-DIR&gt; -L -o hayabusa_results.jsonl -w -p verbose&amp;rdquo;
Then, it will be launched Takajo with &amp;ldquo;automagic&amp;rdquo; option: which executes as many commands as possible and output results to a &amp;ldquo;case-0&amp;rdquo; folder and will upload all the content with the following commandline: &amp;ldquo;takajo.exe automagic -t hayabusa_tempdir/ -o case-0 &amp;quot;
All the output results will be uploaded.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Exchange.Windows.EventLogs.Hayabusa.Takajo
description: |
 [Takajo] (https://github.com/Yamato-Security/takajo) is a fast forensics analyzer
 for Hayabusa results written in Nim. Takajō means "Falconer" in Japanese
 and was chosen as it analyzes Hayabusa's "catches" (results).
 
 First, it will call Exchange.Windows.EventLogs.Hayabusa to execute the following commandline to create the hayabusa_results.jsonl: "hayabusa.exe json-timeline -d &amp;lt;EVTX-DIR&amp;gt; -L -o hayabusa_results.jsonl -w -p verbose"
 Then, it will be launched Takajo with "automagic" option: which executes as many commands as possible and output results to a "case-0" folder and will upload all the content with the following commandline: "takajo.exe automagic -t hayabusa_tempdir/ -o case-0 "
 All the output results will be uploaded.

author: Eric Capuano - @eric_capuano, Whitney Champion - @shortxstack, Zach Mathis - @yamatosecurity

tools:
 - name: Hayabusa-2.14.0
 url: https://github.com/Yamato-Security/hayabusa/releases/download/v2.14.0/hayabusa-2.14.0-win-x64.zip
 expected_hash: de8abff4f6ed35f28e1e2897659e4f7adcca13ef84d2764afa786ca3f60224ec
 - name: Takajo-2.5.0
 url: https://github.com/Yamato-Security/takajo/releases/download/v2.5.0/takajo-2.5.0-win.zip
 expected_hash: bba76ce84484c53145f7df368560cfeae267729df9c404e570ee7fb544c86b01


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

parameters:
 - name: EvtxDirectory
 description: "Directory of .evtx files"
 default: C:/Windows/System32/winevt/Logs

sources:
 - name: Upload
 query: |
 -- Fetch the binary
 LET ToolzipHB &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="Hayabusa-2.14.0", IsExecutable=FALSE)

 LET TmpDirHB &amp;lt;= tempdir()

 -- Unzip the binary
 LET _ &amp;lt;= SELECT *
 FROM unzip(filename=ToolzipHB.FullPath, output_directory=TmpDirHB)

 LET HayabusaExe &amp;lt;= TmpDirHB + '\\hayabusa-2.14.0-win-x64.exe'
 LET HayabusaCmd &amp;lt;= "json-timeline"
 LET ResultFileHB &amp;lt;= TmpDirHB + '\\hayabusa_results.jsonl'

 -- Build the command line considering all options
 -- If it does not match if(condition...), it returns Null, so remove Null with filter(....regex=".+")
 LET cmdlineHB &amp;lt;= filter(list=(
 HayabusaExe, HayabusaCmd,
 "-d", EvtxDirectory,
 "-L",
 "-o", ResultFileHB,
 "-w",
 "-p", "verbose",
 ), regex=".+")

 -- Run the tool and divert messages to logs.
 LET ExecHB &amp;lt;= SELECT *
 FROM execve(argv=cmdlineHB, sep="\n", length=9999999)
 WHERE log(message=Stdout)

 -- Fetch the binary
 LET ToolzipTK &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="Takajo-2.5.0", IsExecutable=FALSE)

 -- Unzip the binary
 LET _ &amp;lt;= SELECT *
 FROM unzip(filename=ToolzipTK.FullPath, output_directory=TmpDirHB)

 LET TakajoExe &amp;lt;= TmpDirHB + '\\takajo.exe'
 LET TakajoCmd &amp;lt;= "automagic"
 LET ResultFileTK &amp;lt;= TmpDirHB + '\\case-0\\'

 -- Build the command line considering all options
 -- If it does not match if(condition...), it returns Null, so remove Null with filter(....regex=".+")
 LET cmdlineTK &amp;lt;= filter(list=(
 TakajoExe, TakajoCmd,
 "-q",
 "-s",
 "-t", TmpDirHB, 
 "-o", ResultFileTK,
 ), regex=".+")

 -- Run the tool and divert messages to logs.
 LET ExecTK &amp;lt;= SELECT *
 FROM execve(argv=cmdlineTK, sep="\n", length=99999999)
 WHERE log(message=Stdout)

 -- Upload the results folder.
 SELECT upload(file=OSPath, accessor=directory) AS Uploads FROM glob(globs="*\**", root=ResultFileTK)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Exchange.Windows.System.PowerShell.DetectResponder</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.windows.system.powershell.detectresponder/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/exchange.windows.system.powershell.detectresponder/</guid><description>&lt;p&gt;This artifact allows to detect responder in the environment
&lt;a href="https://tcm-sec.com/llmnr-poisoning-and-how-to-prevent-it/" target="_blank" &gt;https://tcm-sec.com/llmnr-poisoning-and-how-to-prevent-it/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Exchange.Windows.System.PowerShell.DetectResponder
author: "Dhruv Majumdar, Jamie Bhoohe"
description: |
 This artifact allows to detect responder in the environment
 https://tcm-sec.com/llmnr-poisoning-and-how-to-prevent-it/
type: CLIENT_EVENT
required_permissions:
 - EXECVE

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

parameters:
 - name: PowerShellExe
 default: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
 - name: ReloadPeriod
 description: Checks for responder activity
 default: "600"
 type: int

sources:
 - query: |
 SELECT * FROM foreach(
 row={
 SELECT * FROM clock(period=ReloadPeriod)
 },
 query={
 SELECT * FROM execve(argv=[PowerShellExe,
 "-ExecutionPolicy", "Unrestricted", '''$llmnr = (Resolve-DnsName -LlmnrOnly evilname) 2&amp;gt; $NULL 
 if ($llmnr) { 
 $evil_IP = $llmnr.IPAddress -Join ", " 
 $msg = "Subject: HIGH SEV - Responder Detcted `nDomain: $env:USERDNSDOMAIN `nHostname: ${env:computername} `nRouge LLMNR Server: $evil_IP" 
 echo $msg 
 }'''])
 WHERE log(message="Responder Detection Running")
 })


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>FreeBSD.Sys.Utx</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/freebsd.sys.utx/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/freebsd.sys.utx/</guid><description>&lt;p&gt;Parse the utx file of the system (similar to wtmp on Linux). This covers user sessions, boots, shutdowns and system time changes.
Because FreeBSD discards fields for the entries of the utx file based on type (see &lt;code&gt;man getutxent&lt;/code&gt;), no direct parsing of the file using &amp;ldquo;vtypes&amp;rdquo; is done (too complicated for me to define a structure for parsing), but rather native tools are used for accessing the data.&lt;/p&gt;
&lt;p&gt;Using a value of &amp;ldquo;time&amp;rdquo; with the &amp;ldquo;userRegex&amp;rdquo; Parameter will give you all entries related to boots, shutdowns and system time changes.&lt;/p&gt;
&lt;p&gt;Beware: logout times are given in localtime! Furthermore, that column is not automatically parsed into timestamp values, because the tool output is not consistently a recognizable datetime.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: FreeBSD.Sys.Utx
author: Herbert Bärschneider
description: |
 Parse the utx file of the system (similar to wtmp on Linux). This covers user sessions, boots, shutdowns and system time changes.
 Because FreeBSD discards fields for the entries of the utx file based on type (see `man getutxent`), no direct parsing of the file using "vtypes" is done (too complicated for me to define a structure for parsing), but rather native tools are used for accessing the data.
 
 Using a value of "time" with the "userRegex" Parameter will give you all entries related to boots, shutdowns and system time changes.
 
 Beware: logout times are given in localtime! Furthermore, that column is not automatically parsed into timestamp values, because the tool output is not consistently a recognizable datetime.

type: CLIENT

parameters:
 - name: utxGlobs
 default: /var/log/utx.log*
 description: |
 glob for covering the files that should be parsed; default covers the usual location of the utx file on FreeBSD
 - name: userRegex
 type: regex
 default: "."
 description: |
 Regex for filtering the users, showing those you are interested in 
 - name: DateAfter
 type: timestamp
 description: |
 timestamp used for filtering the login time
 - name: DateBefore
 type: timestamp
 description: |
 timestamp used for filtering the login time

sources:
 - precondition:
 SELECT OS From info() where OS = 'freebsd'
 query: |
 -- timestamps given by the system command "last" are in local time, so we tell Velociraptor to handle them accordingly when converting with the VQL function "timestamp()"
 LET PARSE_TZ &amp;lt;= "local"
 
 -- time test function (taken from Windows.NTFS.MFT)
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))
 
 -- expand the glob and get all files that are matched by it
 LET Files = SELECT OSPath FROM glob(globs=split(string=utxGlobs, sep=","))
 
 -- for each targeted file, parse the data out of it using system built-in command 
 LET UtxParsing = SELECT * FROM foreach(row=Files,
 query={
 -- TODO: try the command while setting env variable "TZ" to UTC and check, if the timestamps are changed accordingly
 SELECT * 
 FROM execve(argv=["last", "-wy", "--libxo=json", "-f", OSPath])
 WHERE log(message="stderr: " + Stderr) 
 })
 
 -- parse the output from each file as json
 LET UtxContent = SELECT parse_json(data=Stdout) as Content FROM UtxParsing
 
 -- pull out the interesting information from the nested json content
 LET s = scope() -- a little helper to suppress "symbol not found error" for elements of the content that are sometimes missing
 LET FormatedContent = SELECT * FROM foreach(row=UtxContent,
 query={
 SELECT user, timestamp(string=`login-time`) AS login_time, s.`logout-time` AS logout_time, s.`session-length` AS session_length, s.tty AS tty, s.`from` AS remote, Content.`last-information`.utxdb AS utx_log FROM foreach(row=Content.`last-information`.last)
 })
 
 SELECT * FROM FormatedContent WHERE
 user =~ userRegex
 AND time_test(stamp=login_time)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Collection.UAC</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.collection.uac/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.collection.uac/</guid><description>&lt;p&gt;This artifact leverages UAC (Unix-like Artifacts Collector) to collect artifacts
from Unix-like systems, and then upload the output to the Velociraptor server.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Collection.UAC
author: Thiago Canozzo Lahr - @tclahr
description: |
 This artifact leverages UAC (Unix-like Artifacts Collector) to collect artifacts
 from Unix-like systems, and then upload the output to the Velociraptor server.

reference:
 - https://github.com/tclahr/uac

type: CLIENT

tools:
 - name: uac
 github_project: tclahr/uac
 github_asset_regex: uac-.+\.tar\.gz

precondition: SELECT OS FROM info() WHERE OS = "darwin" OR OS = "freebsd" OR OS = "linux"

parameters:
 - name: CommandLineOptions
 default: -p ir_triage
 type: string
 description: Command line options.

sources:
 - query: |
 // fetch uac .tar.gz package
 LET uac_package &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(ToolName="uac", IsExecutable=FALSE, TemporaryOnly=TRUE)
 // create temp dir
 LET temp_dir &amp;lt;= tempdir(remove_last=true)
 // uncompress the .tar.gz container
 LET uncompress_tar_gz &amp;lt;= SELECT * FROM execve(argv=['tar', 'zxf', uac_package.OSPath[0]], cwd=temp_dir)
 // search for the correct uac source directory name
 LET uac_source_directory &amp;lt;= SELECT OSPath FROM glob(globs=["uac-*"], root=temp_dir) WHERE IsDir = true
 // run uac
 LET run_uac &amp;lt;= SELECT * FROM execve(argv=[
 "/bin/sh",
 "-c",
 "./uac -u " + CommandLineOptions + " ."
 ],
 cwd=uac_source_directory.OSPath[0],
 sep="\n",
 length=2048
 )
 // upload output and log file
 LET upload_output_files &amp;lt;= SELECT OSPath, upload(accessor="file", file=OSPath, name=OSPath.Basename) AS Upload FROM glob(globs=["uac-*.log", "uac-*.tar.gz"], root=uac_source_directory.OSPath[0])
 SELECT * FROM chain(
 a=run_uac,
 b=upload_output_files
 )

# CHANGELOG:
# 2023-10-01: v3.0 released
# - FetchBinary now uses TemporaryOnly=TRUE to use a temporary directory to hold the binary and remove it afterward.
# - The FullPath column of the Glob plugin is deprecated so it was replaced by OSPath.
# 2023-03-01: v2.0 released
# - UAC tool needs to be either fetched via upstream URL or manually provided as a .tar.gz package.
# 2023-02-19: v1.0 released
# - Initial release.

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.CommonLogFormat.AccessLogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.commonlogformat.accesslogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.commonlogformat.accesslogs/</guid><description>&lt;p&gt;Parses Apache access logs to extract detailed request information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.CommonLogFormat.AccessLogs

description: |
 Parses Apache access logs to extract detailed request information.

aliases:
 - Generic.Apache.AccessLogs

author: Harsh Jaroli, Krishna Patel, Antonio Blescia (TheThMando)

reference:
 - https://httpd.apache.org/docs/2.4/logs.html
 - https://raw.githubusercontent.com/linuxacademy/content-elastic-log-samples/refs/heads/master/access.log
 - https://raw.githubusercontent.com/elastic/examples/refs/heads/master/Common%20Data%20Formats/nginx_logs/nginx_logs
 - https://datatracker.ietf.org/doc/html/rfc6872

type: CLIENT

parameters:
 - name: AccessLogPath
 default: /{/var/log/httpd,/var/log/apache2,/var/log/nginx,C:/Apache/logs}/{access.log,access_log}*

 - name: ApacheAccessLogGrok
 description: A Grok expression for parsing Apache access log lines.
 default: &amp;gt;-
 %{IPORHOST:client} %{DATA:identity_check} %{DATA:remote_user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:status} %{NUMBER:response_size}( %{QUOTEDSTRING:referer})?( %{QUOTEDSTRING:user_agent})?

sources:
 - query: |
 // accesslog parsing via GROK expressions.
 SELECT timestamp(string=Event.timestamp) AS Time,
 Event.client AS ClientIP,
 Event.method AS RequestMethod,
 Event.request AS RequestURL,
 Event.httpversion AS HTTPVersion,
 Event.status AS ResponseStatus,
 Event.response_size AS ResponseSize,
 Event.referer As Referer,
 Event.user_agent AS UserAgent,
 OSPath
 FROM foreach(
 row={
 SELECT OSPath FROM glob(globs=AccessLogPath)
 }, query={
 SELECT grok(grok=ApacheAccessLogGrok, data=Line) AS Event, OSPath
 FROM parse_lines(filename=OSPath)
 })


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.Confluence_CVE_2023_22527</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/confluence_cve_2023_22527/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/confluence_cve_2023_22527/</guid><description>&lt;p&gt;This artifact detects evidence of exploitation of Confluence RCE CVE-2023-22527.&lt;/p&gt;
&lt;p&gt;The artifact checks conf_access logs for a malicious POST request and should
return full line of any hit (IP address and http code).&lt;/p&gt;
&lt;p&gt;Note: the underlying artifact uses Generic.Detection.Yara.Glob().
Please run he notbook suggestion view hit strings for further analysis.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.Confluence_CVE_2023_22527
author: Matt Green - @mgreen27
description: |
 This artifact detects evidence of exploitation of Confluence RCE CVE-2023-22527.
 
 The artifact checks conf_access logs for a malicious POST request and should 
 return full line of any hit (IP address and http code).
 
 Note: the underlying artifact uses Generic.Detection.Yara.Glob(). 
 Please run he notbook suggestion view hit strings for further analysis.

reference:
 - https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/
 
type: CLIENT

parameters:
 - name: TargetGlob
 default: /**/atlassian/confluence/logs/conf_access*.log
 - name: YaraRule
 default: |
 rule LOG_CVE_2023_22527_Confluence_Jan23 {
 meta:
 description = "Detects exploitation attempts for Confluence RCE CVE-2023-22527"
 author = "Matt Green - @mgreen27"
 reference = "https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/"
 date = "2024-01-25"
 strings:
 $s1 = /\[.{,100} POST \/template\/aui\/text-inline\.vm [^\n]{10,500}/
 condition:
 any of them
 }
 - name: UploadHits
 type: bool
 description: upload any logs with hits.

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

 query: |
 SELECT * FROM Artifact.Generic.Detection.Yara.Glob(
 PathGlob=TargetGlob,
 YaraRule=YaraRule,
 NumberOfHits=999999,
 UploadHits=UploadHits )
 notebook:
 - type: vql_suggestion
 name: View hit strings
 template: | 
 /*
 ## Show all hit strings for post processing
 */
 LET m &amp;lt;= memoize(query={
 SELECT vfs_path.Base as Key, vfs_path
 FROM uploads()
 }, key='Key')
 
 
 SELECT Fqdn,OSPath,Mtime,Rule,HitOffset,
 read_file(accessor='fs',filename=get(item=m, field=str(str=HitContext.StoredName)).vfs_path) as HitContext
 FROM source()
 
column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.EffluenceWebshell</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/effluencewebshell/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/effluencewebshell/</guid><description>&lt;p&gt;This artifact detects Effluence Webshell observed deployed during exploitation
of Atlassian Confluence CVE-2023-22515.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.EffluenceWebshell
author: Matt Green - @mgreen27
description: |
 This artifact detects Effluence Webshell observed deployed during exploitation 
 of Atlassian Confluence CVE-2023-22515.

reference:
 - https://www.aon.com/cyber-solutions/aon_cyber_labs/detecting-effluence-an-unauthenticated-confluence-web-shell/
 
type: CLIENT

parameters:
 - name: ProcessRegex
 default: java
 type: regex
 - name: PidRegex
 default: .
 type: regex
 - name: YaraRule
 type: yara
 default: |
 rule ConfluencePageIndicator {
 meta:
 description = "Detects strings indicative of a web shell in Confluence page"
 author = "Stroz Friedberg"
 date = "2023-11-06"
 
 strings:
 $confluence_title = "&amp;lt;title&amp;gt; - Confluence&amp;lt;/title&amp;gt;" ascii wide
 $hide_plugin_function = "hidePlugin(" ascii wide
 $system_plugin_key = "ALWAYS_SYSTEM_PLUGIN_KEYS" ascii wide
 $dashes = " ----- " ascii wide
 
 condition:
 $confluence_title and $hide_plugin_function and $dashes and $system_plugin_key
 }
 - name: NumberOfHits
 description: THis artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int64


sources:
 - query: |
 LET linux = SELECT * FROM Artifact.Linux.Detection.Yara.Process(
 ProcessRegex=ProcessRegex,
 PidRegex=PidRegex,
 YaraRule=YaraRule,
 NumberOfHits=NumberOfHits,
 ContextBytes=ContextBytes )

 LET windows = SELECT * FROM Artifact.Windows.Detection.Yara.Process(
 ProcessRegex=ProcessRegex,
 PidRegex=PidRegex,
 YaraRule=YaraRule,
 NumberOfHits=NumberOfHits,
 ContextBytes=ContextBytes )
 
 LET system = SELECT OS From info() where OS
 
 SELECT * FROM if(condition= system[0].OS=windows,
 then= windows,
 else= linux )
 
column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.log4jRCE</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/log4jrce/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/log4jrce/</guid><description>&lt;p&gt;Detection for exploitation attempts against log4j RCE
vulnerability CVE-2021-44228.&lt;/p&gt;
&lt;p&gt;By default this artifact will search for linux path glob: /var/logs/**&lt;/p&gt;
&lt;p&gt;For Windows hosts please change the target path.
Some examples of path glob may include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specific binary: &lt;code&gt;/var/logs/log.gz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Wildcards: &lt;code&gt;/var/log/*.gz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;More wildcards: &lt;code&gt;/var/www/**/*.log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Multiple extentions: &lt;code&gt;/var/log/**/*\.{log,gz}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;C:/Logs/**/*.{gz,log}&lt;/code&gt; or &lt;code&gt;**/*.{gz,log}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: this artifact runs the glob plugin with the nosymlink switch
turned on. This will NOT follow any symlinks and may cause
unexpected results if unknowingly targeting a folder with symlinks.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.log4jRCE
author: Matt Green - @mgreen27
description: |
 Detection for exploitation attempts against log4j RCE
 vulnerability CVE-2021-44228.

 By default this artifact will search for linux path glob: /var/logs/**

 For Windows hosts please change the target path.
 Some examples of path glob may include:

 * Specific binary: `/var/logs/log.gz`
 * Wildcards: `/var/log/*.gz`
 * More wildcards: `/var/www/**/*.log`
 * Multiple extentions: `/var/log/**/*\.{log,gz}`
 * Windows: `C:/Logs/**/*.{gz,log}` or `**/*.{gz,log}`

 NOTE: this artifact runs the glob plugin with the nosymlink switch
 turned on. This will NOT follow any symlinks and may cause
 unexpected results if unknowingly targeting a folder with symlinks.

reference:
 - https://github.com/Neo23x0/signature-base/blob/master/yara/expl_log4j_cve_2021_44228.yar

type: CLIENT
parameters:
 - name: PathGlob
 description: Only file names that match this glob will be scanned.
 default: /var/log/**
 - name: SizeMax
 description: maximum size of target file.
 - name: SizeMin
 description: minimum size of target file.
 - name: UploadHits
 type: bool
 - 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: YaraUrl
 description: If configured will attempt to download Yara rules form Url
 default:
 - name: ShortHandYara
 description: Second option Yara choice is a Velociraptor shorthand Yara rule
 default:
 - name: YaraRule
 description: Final Yara option and the default if no other options provided.
 default: |
 rule EXPL_Log4j_CallBackDomain_IOCs_Dec21_1 {
 meta:
 description = "Detects IOCs found in Log4Shell incidents that indicate exploitation attempts of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://gist.github.com/superducktoes/9b742f7b44c71b4a0d19790228ce85d8"
 date = "2021-12-12"
 score = 60
 strings:
 $xr1 = /\b(ldap|rmi):\/\/([a-z0-9\.]{1,16}\.bingsearchlib\.com|[a-z0-9\.]{1,40}\.interact\.sh|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):[0-9]{2,5}\/([aZ]|ua|Exploit|callback|[0-9]{10}|http443useragent|http80useragent)\b/
 condition:
 1 of them
 }

 rule EXPL_JNDI_Exploit_Patterns_Dec21_1 {
 meta:
 description = "Detects JNDI Exploit Kit patterns in files"
 author = "Florian Roth"
 reference = "https://github.com/pimps/JNDI-Exploit-Kit"
 date = "2021-12-12"
 score = 60
 strings:
 $x01 = "/Basic/Command/Base64/"
 $x02 = "/Basic/ReverseShell/"
 $x03 = "/Basic/TomcatMemshell"
 $x04 = "/Basic/JettyMemshell"
 $x05 = "/Basic/WeblogicMemshell"
 $x06 = "/Basic/JBossMemshell"
 $x07 = "/Basic/WebsphereMemshell"
 $x08 = "/Basic/SpringMemshell"
 $x09 = "/Deserialization/URLDNS/"
 $x10 = "/Deserialization/CommonsCollections1/Dnslog/"
 $x11 = "/Deserialization/CommonsCollections2/Command/Base64/"
 $x12 = "/Deserialization/CommonsBeanutils1/ReverseShell/"
 $x13 = "/Deserialization/Jre8u20/TomcatMemshell"
 $x14 = "/TomcatBypass/Dnslog/"
 $x15 = "/TomcatBypass/Command/"
 $x16 = "/TomcatBypass/ReverseShell/"
 $x17 = "/TomcatBypass/TomcatMemshell"
 $x18 = "/TomcatBypass/SpringMemshell"
 $x19 = "/GroovyBypass/Command/"
 $x20 = "/WebsphereBypass/Upload/"

 $fp1 = "&amp;lt;html"
 condition:
 1 of ($x*) and not 1 of ($fp*)
 }

 rule EXPL_Log4j_CVE_2021_44228_JAVA_Exception_Dec21_1 {
 meta:
 description = "Detects exceptions found in server logs that indicate an exploitation attempt of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b"
 date = "2021-12-12"
 score = 60
 strings:
 $xa1 = "header with value of BadAttributeValueException: "

 $sa1 = ".log4j.core.net.JndiManager.lookup(JndiManager"
 $sa2 = "Error looking up JNDI resource"
 condition:
 $xa1 or all of ($sa*)
 }

 rule EXPL_Log4j_CVE_2021_44228_Dec21_Soft {
 meta:
 description = "Detects indicators in server logs that indicate an exploitation attempt of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://twitter.com/h113sdx/status/1469010902183661568?s=20"
 date = "2021-12-10"
 modified = "2021-12-13"
 score = 60
 strings:
 $x01 = "${jndi:ldap:/"
 $x02 = "${jndi:rmi:/"
 $x03 = "${jndi:ldaps:/"
 $x04 = "${jndi:dns:/"
 $x05 = "${jndi:iiop:/"
 $x06 = "${jndi:http:/"
 $x07 = "${jndi:nis:/"
 $x08 = "${jndi:nds:/"
 $x09 = "${jndi:corba:/"

 $fp1 = "&amp;lt;html"
 condition:
 1 of ($x*) and not 1 of ($fp*)
 }

 rule EXPL_Log4j_CVE_2021_44228_Dec21_OBFUSC {
 meta:
 description = "Detects obfuscated indicators in server logs that indicate an exploitation attempt of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://twitter.com/h113sdx/status/1469010902183661568?s=20"
 date = "2021-12-12"
 modified = "2021-12-13"
 score = 60
 strings:
 $x1 = "$%7Bjndi:"
 $x2 = "%2524%257Bjndi"
 $x3 = "%2F%252524%25257Bjndi%3A"
 $x4 = "${jndi:${lower:"
 $x5 = "${::-j}${"
 $x6 = "${${env:BARFOO:-j}"
 $x7 = "${::-l}${::-d}${::-a}${::-p}"
 $x8 = "${base64:JHtqbmRp"

 $fp1 = "&amp;lt;html"
 condition:
 1 of ($x*) and not 1 of ($fp*)
 }

 rule EXPL_Log4j_CVE_2021_44228_Dec21_Hard {
 meta:
 description = "Detects indicators in server logs that indicate the exploitation of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://twitter.com/h113sdx/status/1469010902183661568?s=20"
 date = "2021-12-10"
 modified = "2021-12-12"
 score = 80
 strings:
 $x1 = /\$\{jndi:(ldap|ldaps|rmi|dns|iiop|http|nis|nds|corba):\/[\/]?[a-z-\.0-9]{3,120}:[0-9]{2,5}\/[a-zA-Z\.]{1,32}\}/
 $x2 = "Reference Class Name: foo"
 $fp1r = /(ldap|rmi|ldaps|dns):\/[\/]?(127\.0\.0\.1|192\.168\.|172\.[1-3][0-9]\.|10\.)/
 condition:
 1 of ($x*) and not 1 of ($fp*)
 }

 rule SUSP_Base64_Encoded_Exploit_Indicators_Dec21 {
 meta:
 description = "Detects base64 encoded strings found in payloads of exploits against log4j CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://twitter.com/Reelix/status/1469327487243071493"
 date = "2021-12-10"
 modified = "2021-12-13"
 score = 70
 strings:
 /* curl -s */
 $sa1 = "Y3VybCAtcy"
 $sa2 = "N1cmwgLXMg"
 $sa3 = "jdXJsIC1zI"
 /* |wget -q -O- */
 $sb1 = "fHdnZXQgLXEgLU8tI"
 $sb2 = "x3Z2V0IC1xIC1PLS"
 $sb3 = "8d2dldCAtcSAtTy0g"

 $fp1 = "&amp;lt;html"
 condition:
 1 of ($sa*) and 1 of ($sb*)
 and not 1 of ($fp*)
 }

 rule SUSP_JDNIExploit_Indicators_Dec21 {
 meta:
 description = "Detects indicators of JDNI usage in log files and other payloads"
 author = "Florian Roth"
 reference = "https://github.com/flypig5211/JNDIExploit"
 date = "2021-12-10"
 modified = "2021-12-12"
 score = 70
 strings:
 $xr1 = /(ldap|ldaps|rmi|dns|iiop|http|nis|nds|corba):\/\/[a-zA-Z0-9\.]{7,80}:[0-9]{2,5}\/(Basic\/Command\/Base64|Basic\/ReverseShell|Basic\/TomcatMemshell|Basic\/JBossMemshell|Basic\/WebsphereMemshell|Basic\/SpringMemshell|Basic\/Command|Deserialization\/CommonsCollectionsK|Deserialization\/CommonsBeanutils|Deserialization\/Jre8u20\/TomcatMemshell|Deserialization\/CVE_2020_2555\/WeblogicMemshell|TomcatBypass|GroovyBypass|WebsphereBypass)\//
 condition:
 filesize &amp;lt; 100MB and $xr1
 }

 rule SUSP_EXPL_OBFUSC_Dec21_1{
 meta:
 description = "Detects obfuscation methods used to evade detection in log4j exploitation attempt of CVE-2021-44228"
 author = "Florian Roth"
 reference = "https://twitter.com/testanull/status/1469549425521348609"
 date = "2021-12-11"
 score = 60
 strings:
 /* ${lower:X} - single character match */
 $x1 = { 24 7B 6C 6F 77 65 72 3A ?? 7D }
 /* ${upper:X} - single character match */
 $x2 = { 24 7B 75 70 70 65 72 3A ?? 7D }
 /* URL encoded lower - obfuscation in URL */
 $x3 = "$%7blower:"
 $x4 = "$%7bupper:"
 $x5 = "%24%7bjndi:"
 $x6 = "$%7Blower:"
 $x7 = "$%7Bupper:"
 $x8 = "%24%7Bjndi:"

 $fp1 = "&amp;lt;html"
 condition:
 1 of ($x*) and not 1 of ($fp*)
 }

 rule SUSP_JDNIExploit_Error_Indicators_Dec21_1 {
 meta:
 description = "Detects error messages related to JDNI usage in log files that can indicate a Log4Shell / Log4j exploitation"
 author = "Florian Roth"
 reference = "https://twitter.com/marcioalm/status/1470361495405875200?s=20"
 date = "2021-12-10"
 modified = "2021-12-13"
 score = 70
 strings:
 $x1 = "FATAL log4j - Message: BadAttributeValueException: "
 condition:
 $x1
 }

sources:
 - query: |
 -- check which Yara to use
 LET yara = SELECT * FROM if(condition=YaraUrl,
 then= { SELECT Content FROM http_client( url=YaraUrl, method='GET') },
 else= if(condition=ShortHandYara,
 then= { SELECT ShortHandYara as Content FROM scope() },
 else= { SELECT YaraRule as Content FROM scope() }))

 -- time testing
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))

 -- first find all matching glob
 LET files = SELECT FullPath, Name, Size , Mtime, Atime, Ctime, Btime
 FROM glob(globs=PathGlob,nosymlink='True')
 WHERE
 NOT IsDir AND NOT IsLink
 AND if(condition=SizeMin,
 then= SizeMin &amp;lt; Size,
 else= True)
 AND if(condition=SizeMax,
 then=SizeMax &amp;gt; Size,
 else= True)
 AND
 ( time_test(stamp=Mtime)
 OR time_test(stamp=Atime)
 OR time_test(stamp=Ctime)
 OR time_test(stamp=Btime))

 LET hits = SELECT * FROM foreach(row=files,
 query={
 SELECT
 url(parse=FileName).Path as FullPath,
 Size,
 Mtime, Atime, Ctime, Btime,
 Rule, Tags, Meta,
 str(str=String.Data) AS HitContext,
 String.Offset AS HitOffset
 FROM yara(rules=yara.Content[0],files=url(path=FullPath, scheme="file"), accessor='gzip')
 LIMIT 1
 })

 -- upload files that have hit
 LET upload_hits=SELECT *,
 upload(file=FullPath) AS Upload
 FROM hits

 -- return rows
 SELECT * FROM if(condition=UploadHits,
 then=upload_hits,
 else=hits)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.LunasecLog4shell</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.detection.lunaseclog4shell/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.detection.lunaseclog4shell/</guid><description>&lt;p&gt;Uses the Log4Shell scanner of Lunasec to scan the file systems of
all drives of the host for any sign of vulnerabilities related to
Log4shell&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.LunasecLog4shell
author: "Marinus Boekelo &amp;amp; Noël Keijzer - Northwave CERT"
description: |
 Uses the Log4Shell scanner of Lunasec to scan the file systems of
 all drives of the host for any sign of vulnerabilities related to
 Log4shell

tools:
 - name: log4shell_linux_amd64
 github_project: lunasec-io/lunasec
 github_asset_regex: Linux_x86_64
 serve_locally: true

 - name: log4shell_linux_x86
 github_project: lunasec-io/lunasec
 github_asset_regex: Linux_i386
 serve_locally: true

 - name: log4shell_windows_amd64
 github_project: lunasec-io/lunasec
 github_asset_regex: Windows_x86_64
 serve_locally: true

 - name: log4shell_windows_x86
 github_project: lunasec-io/lunasec
 github_asset_regex: Windows_i386
 serve_locally: true

reference:
 - https://github.com/lunasec-io/lunasec/releases/

precondition: SELECT OS From info() where OS = "windows" or OS = "linux"

required_permissions:
 - EXECVE

parameters:
 - name: ToolInfo
 description: Override Tool information.

sources:
 - query: |
 LET os_info &amp;lt;= SELECT Architecture, OS FROM info()

 // Get the path to the binary.
 LET bin &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName= "log4shell_" + os_info[0].OS + "_" + os_info[0].Architecture,
 ToolInfo=ToolInfo)

 // Select the Disks to scan
 LET disks = if(condition=(os_info[0].OS="windows"),
 then= {
 SELECT Mountpoint + "\\\\" as Mountpoint
 FROM filesystems()
 },
 else={
 SELECT "/" as Mountpoint
 FROM scope()
 })

 // Scan every disk
 LET results = SELECT * FROM foreach(row=disks,
 query={
 SELECT parse_json(data=Stdout) AS record
 FROM execve(argv=[bin[0].FullPath,"scan","--json",Mountpoint], sep="\n")
 WHERE Stdout
 })

 // output rows
 SELECT * FROM foreach(row= results,
 query={ SELECT * FROM record })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.ManageEngineLog</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/manageenginelog/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/manageenginelog/</guid><description>&lt;p&gt;This artifact will enable discovery of logs associated with observed exploitation
of critical ManageEngine vulnerability: CVE-2022-47966.&lt;/p&gt;
&lt;p&gt;The artifact leverages Yara.Glob to scan ManageEngine logs and is cross
platform.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.ManageEngineLog
author: Matt Green - @mgreen27, Jason Frost - @jaysonfrost2
description: |
 This artifact will enable discovery of logs associated with observed exploitation 
 of critical ManageEngine vulnerability: CVE-2022-47966.
 
 The artifact leverages Yara.Glob to scan ManageEngine logs and is cross 
 platform.


type: CLIENT

parameters:
 - name: TargetLogGlob
 default: "**/{ServiceDesk/logs,logs3PM}/serverout*.txt"
 - name: YaraRule
 default: |
 rule LOG_EXPL_ManageEngine_CVE_2022_47966_Jan23 {
 meta:
 description = "Detects Exploitation of Critical ManageEngine Vulnerability: CVE-2022-47966"
 author = "Matt Green - @mgreen27"
 reference = "https://www.rapid7.com/blog/post/2023/01/19/etr-cve-2022-47966-rapid7-observed-exploitation-of-critical-manageengine-vulnerability/"
 date = "2023-01-20"
 strings:
 $s1 = "com.adventnet.authentication.saml.SamlException: Signature validation failed. SAML Response rejected" 

 $re1 = /invalid_response --&amp;gt; .{20,}/s //Logging typically contains this string followed by Base64 &amp;lt;samlp:Response Version=
 
 $ip1 = "111.68.7.122"
 $ip2 = "149.28.193.216"
 $ip3 = "172.93.193.64"
 
 condition:
 any of them
 }
 - name: Context
 default: 200
 description: Amount of ContextBytes to include on each hit.
 - name: NumberOfHits
 default: 9999
 description: Maximum number of hits to return
 - name: UploadHits
 type: bool
 description: Upload each file with a hit.
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows' OR OS = 'linux' OR OS = 'darwin'

 query: |
 SELECT * FROM Artifact.Generic.Detection.Yara.Glob(
 PathGlob=TargetLogGlob,
 YaraRule=YaraRule,
 ContextBytes=Context,
 NumberOfHits=9999,
 UploadHits=UploadHits)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.WebShells</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.detection.webshells/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.detection.webshells/</guid><description>&lt;p&gt;This artifact looks for evidence of a web shell being present on the system. It targets Windows and Linux hosts.
The artifact should be run on web servers, be it dedicated web servers or systems with integrated web servers.
For such machines, find the root directory of the web server and change the artifact parameters as needed.&lt;/p&gt;
&lt;p&gt;Multiple indicators for web shells are used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;files with suspicious strings commonly used in web shells&lt;/li&gt;
&lt;li&gt;suspicious processes being spawned by the webserver process (Windows only)&lt;/li&gt;
&lt;li&gt;recently created and changed files under the webroot directory
False-positives might arise from web sites with remote code execution functionality willingly built in as well as recent changes to the served web sites.
The artifact was envisioned for hunting after potential malicious activity, so noise should be expected with the output.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.WebShells
author: Herbert Bärschneider @SEC Defence
description: |
 This artifact looks for evidence of a web shell being present on the system. It targets Windows and Linux hosts.
 The artifact should be run on web servers, be it dedicated web servers or systems with integrated web servers. 
 For such machines, find the root directory of the web server and change the artifact parameters as needed.

 Multiple indicators for web shells are used: 
 * files with suspicious strings commonly used in web shells
 * suspicious processes being spawned by the webserver process (Windows only)
 * recently created and changed files under the webroot directory
 False-positives might arise from web sites with remote code execution functionality willingly built in as well as recent changes to the served web sites.
 The artifact was envisioned for hunting after potential malicious activity, so noise should be expected with the output.

reference:
 - https://attack.mitre.org/techniques/T1505/003/
 - https://github.com/nsacyber/Mitigating-Web-Shells/blob/master/extended.webshell_detection.yara
 - https://car.mitre.org/analytics/CAR-2021-02-001/

type: CLIENT

parameters:
 - name: WindowsWebRoot 
 description: glob used to identify all files belonging to the web root on Windows; if you want to target a directory structure, don't forget to append "**"
 default: "C:\\inetpub\\wwwroot\\**"
 - name: LinuxWebRoot
 description: glob used to identify all files belonging to the web root on Linux; if you want to target a directory structure, don't forget to append "**"
 default: "/var/www/**"
 - name: WebshellRegex
 description: regex for filtering the files in the webroot when looking at file creations and modifications
 type: regex
 default: '\.php|\.asp|\.aspx|\.jsp|\.jar|\.ps1|\.sh'
 - name: WebserverProcessRegex
 description: regex of processes which are considered as web servers when searching for suspicious process creations
 type: regex
 default: 'w3wp\.exe|httpd\.exe|tomcat*\.exe|nginx\.exe'
 - name: SpawnedProcessRegex
 description: regex of processes, which are to be considered suspicious when spawned from a web server process 
 type: regex
 default: 'cmd\.exe|powershell\.exe|pwsh\.exe|net\.exe|net1\.exe|whoami\.exe|hostname\.exe|systeminfo\.exe|ipconfig\.exe'
 - name: DateAfter
 type: timestamp
 - name: DateBefore
 type: timestamp
 - name: YaraRule
 type: yara
 description: yara rule used to search for web shells
 default: |
 private rule b374k
 {
 meta:
 author = "Blair Gillam (@blairgillam)"

 strings:
 $string = "b374k"
 $password_var = "$s_pass"
 $default_password = "0de664ecd2be02cdd54234a0d1229b43"

 condition:
 any of them
 }

 private rule pas_tool
 {
 meta:
 author = "US CERT"

 strings:
 $php = "&amp;lt;?php"
 $base64decode = /\='base'\.\(\d+\*\d+\)\.'_de'\.'code'/ 
 $strreplace = "(str_replace("
 $md5 = ".substr(md5(strrev("
 $gzinflate = "gzinflate"
 $cookie = "_COOKIE"
 $isset = "isset"

 condition:
 (filesize &amp;gt; 20KB and filesize &amp;lt; 22KB) and
 #cookie == 2 and
 #isset == 3 and
 all of them
 }

 private rule pbot
 {
 meta:
 author = "Jacob Baines (Tenable)"

 strings:
 $ = "class pBot" ascii
 $ = "function start(" ascii
 $ = "PING" ascii
 $ = "PONG" ascii

 condition:
 all of them
 }

 private rule passwordProtection
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $md5 = /md5\s*\(\s*\$_(GET|REQUEST|POST|COOKIE|SERVER)[^)]+\)\s*===?\s*['"][0-9a-f]{32}['"]/ nocase
 $sha1 = /sha1\s*\(\s*\$_(GET|REQUEST|POST|COOKIE|SERVER)[^)]+\)\s*===?\s*['"][0-9a-f]{40}['"]/ nocase
 condition:
 (any of them) 
 }

 private rule ObfuscatedPhp
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $eval = /(&amp;lt;\?php|[;{}])[ \t]*@?(eval|preg_replace|system|assert|passthru|(pcntl_)?exec|shell_exec|call_user_func(_array)?)\s*\(/ nocase // ;eval( &amp;lt;- this is dodgy
 $eval_comment = /(eval|preg_replace|system|assert|passthru|(pcntl_)?exec|shell_exec|call_user_func(_array)?)\/\*[^\*]*\*\/\(/ nocase // eval/*lol*/( &amp;lt;- this is dodgy
 $b374k = "'ev'.'al'"
 $align = /(\$\w+=[^;]*)*;\$\w+=@?\$\w+\(/ //b374k
 $weevely3 = /\$\w=\$[a-zA-Z]\('',\$\w\);\$\w\(\);/ // weevely3 launcher
 $c99_launcher = /;\$\w+\(\$\w+(,\s?\$\w+)+\);/ // http://bartblaze.blogspot.fr/2015/03/c99shell-not-dead.html
 $nano = /\$[a-z0-9-_]+\[[^]]+\]\(/ //https://github.com/UltimateHackers/nano
 $ninja = /base64_decode[^;]+getallheaders/ //https://github.com/UltimateHackers/nano
 $variable_variable = /\${\$[0-9a-zA-z]+}/
 $too_many_chr = /(chr\([\d]+\)\.){8}/ // concatenation of more than eight `chr()`
 $concat = /(\$[^\n\r]+\.){5}/ // concatenation of more than 5 words
 $concat_with_spaces = /(\$[^\n\r]+\. ){5}/ // concatenation of more than 5 words, with spaces
 $var_as_func = /\$_(GET|POST|COOKIE|REQUEST|SERVER)\s*\[[^\]]+\]\s*\(/
 $comment = /\/\*([^*]|\*[^\/])*\*\/\s*\(/ // eval /* comment */ (php_code)
 condition:
 (any of them)
 }

 private rule DodgyPhp
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $basedir_bypass = /curl_init\s*\(\s*["']file:\/\// nocase
 $basedir_bypass2 = "file:file:///" // https://www.intelligentexploit.com/view-details.html?id=8719
 $disable_magic_quotes = /set_magic_quotes_runtime\s*\(\s*0/ nocase

 $execution = /\b(eval|assert|passthru|exec|include|system|pcntl_exec|shell_exec|base64_decode|`|array_map|ob_start|call_user_func(_array)?)\s*\(\s*(base64_decode|php:\/\/input|str_rot13|gz(inflate|uncompress)|getenv|pack|\\?\$_(GET|REQUEST|POST|COOKIE|SERVER))/ nocase // function that takes a callback as 1st parameter
 $execution2 = /\b(array_filter|array_reduce|array_walk(_recursive)?|array_walk|assert_options|uasort|uksort|usort|preg_replace_callback|iterator_apply)\s*\(\s*[^,]+,\s*(base64_decode|php:\/\/input|str_rot13|gz(inflate|uncompress)|getenv|pack|\\?\$_(GET|REQUEST|POST|COOKIE|SERVER))/ nocase // functions that takes a callback as 2nd parameter
 $execution3 = /\b(array_(diff|intersect)_u(key|assoc)|array_udiff)\s*\(\s*([^,]+\s*,?)+\s*(base64_decode|php:\/\/input|str_rot13|gz(inflate|uncompress)|getenv|pack|\\?\$_(GET|REQUEST|POST|COOKIE|SERVER))\s*\[[^]]+\]\s*\)+\s*;/ nocase // functions that takes a callback as 2nd parameter

 $htaccess = "SetHandler application/x-httpd-php"
 $iis_com = /IIS:\/\/localhost\/w3svc/
 $include = /include\s*\(\s*[^\.]+\.(png|jpg|gif|bmp)/ // Clever includes
 $ini_get = /ini_(get|set|restore)\s*\(\s*['"](safe_mode|open_basedir|disable_(function|classe)s|safe_mode_exec_dir|safe_mode_include_dir|register_globals|allow_url_include)/ nocase
 $register_function = /register_[a-z]+_function\s*\(\s*['"]\s*(eval|assert|passthru|exec|include|system|shell_exec|`)/ // https://github.com/nbs-system/php-malware-finder/issues/41
 $safemode_bypass = /\x00\/\.\.\/|LD_PRELOAD/
 $shellshock = /\(\)\s*{\s*[a-z:]\s*;\s*}\s*;/
 $udp_dos = /fsockopen\s*\(\s*['"]udp:\/\// nocase
 $various = "&amp;lt;!--#exec cmd=" //http://www.w3.org/Jigsaw/Doc/User/SSI.html#exec
 $at_eval = /@eval\s*\(/ nocase
 $double_var = /\${\s*\${/
 $extract = /extract\s*\(\s*\$_(GET|POST|REQUEST|COOKIE|SERVER)/
 $reversed = /noitcnuf_etaerc|metsys|urhtssap|edulcni|etucexe_llehs/ nocase
 $silenced_include =/@\s*include\s*/ nocase

 condition:
 (any of them)
 }

 private rule DangerousPhp
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $system = "system" fullword nocase // localroot bruteforcers have a lot of this

 $ = "array_filter" fullword nocase
 $ = "assert" fullword nocase
 $ = "backticks" fullword nocase
 $ = "call_user_func" fullword nocase
 $ = "eval" fullword nocase
 $ = "exec" fullword nocase
 $ = "fpassthru" fullword nocase
 $ = "fsockopen" fullword nocase
 $ = "function_exists" fullword nocase
 $ = "getmygid" fullword nocase
 $ = "shmop_open" fullword nocase
 $ = "mb_ereg_replace_callback" fullword nocase
 $ = "passthru" fullword nocase
 $ = /pcntl_(exec|fork)/ fullword nocase
 $ = "php_uname" fullword nocase
 $ = "phpinfo" fullword nocase
 $ = "posix_geteuid" fullword nocase
 $ = "posix_getgid" fullword nocase
 $ = "posix_getpgid" fullword nocase
 $ = "posix_getppid" fullword nocase
 $ = "posix_getpwnam" fullword nocase
 $ = "posix_getpwuid" fullword nocase
 $ = "posix_getsid" fullword nocase
 $ = "posix_getuid" fullword nocase
 $ = "posix_kill" fullword nocase
 $ = "posix_setegid" fullword nocase
 $ = "posix_seteuid" fullword nocase
 $ = "posix_setgid" fullword nocase
 $ = "posix_setpgid" fullword nocase
 $ = "posix_setsid" fullword nocase
 $ = "posix_setsid" fullword nocase
 $ = "posix_setuid" fullword nocase
 $ = "preg_replace_callback" fullword
 $ = "proc_open" fullword nocase
 $ = "proc_close" fullword nocase
 $ = "popen" fullword nocase
 $ = "register_shutdown_function" fullword nocase
 $ = "register_tick_function" fullword nocase
 $ = "shell_exec" fullword nocase
 $ = "shm_open" fullword nocase
 $ = "show_source" fullword nocase
 $ = "socket_create(AF_INET, SOCK_STREAM, SOL_TCP)" nocase
 $ = "stream_socket_pair" nocase
 $ = "suhosin.executor.func.blacklist" nocase
 $ = "unregister_tick_function" fullword nocase
 $ = "win32_create_service" fullword nocase
 $ = "xmlrpc_decode" fullword nocase 
 $ = /ob_start\s*\(\s*[^\)]/ //ob_start('assert'); echo $_REQUEST['pass']; ob_end_flush();

 $whitelist = /escapeshellcmd|escapeshellarg/ nocase

 condition:
 (not $whitelist and (5 of them or #system &amp;gt; 250))
 }

 private rule IRC
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $ = "USER" fullword nocase
 $ = "PASS" fullword nocase
 $ = "PRIVMSG" fullword nocase
 $ = "MODE" fullword nocase
 $ = "PING" fullword nocase
 $ = "PONG" fullword nocase
 $ = "JOIN" fullword nocase
 $ = "PART" fullword nocase

 condition:
 5 of them
 }

 private rule base64_strings
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $user_agent = "SFRUUF9VU0VSX0FHRU5UCg"
 $eval = "ZXZhbCg"
 $system = "c3lzdGVt"
 $preg_replace = "cHJlZ19yZXBsYWNl"
 $exec = "ZXhlYyg"
 $base64_decode = "YmFzZTY0X2RlY29kZ"
 $perl_shebang = "IyEvdXNyL2Jpbi9wZXJsCg"
 $cmd_exe = "Y21kLmV4ZQ"
 $powershell = "cG93ZXJzaGVsbC5leGU"

 condition:
 any of them
 }

 private rule hex
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $globals = "\\x47\\x4c\\x4f\\x42\\x41\\x4c\\x53" nocase
 $eval = "\\x65\\x76\\x61\\x6C\\x28" nocase
 $exec = "\\x65\\x78\\x65\\x63" nocase
 $system = "\\x73\\x79\\x73\\x74\\x65\\x6d" nocase
 $preg_replace = "\\x70\\x72\\x65\\x67\\x5f\\x72\\x65\\x70\\x6c\\x61\\x63\\x65" nocase
 $http_user_agent = "\\x48\\124\\x54\\120\\x5f\\125\\x53\\105\\x52\\137\\x41\\107\\x45\\116\\x54" nocase
 $base64_decode = "\\x61\\x73\\x65\\x36\\x34\\x5f\\x64\\x65\\x63\\x6f\\x64\\x65\\x28\\x67\\x7a\\x69\\x6e\\x66\\x6c\\x61\\x74\\x65\\x28" nocase
 
 condition:
 any of them
 }

 private rule Hpack
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $globals = "474c4f42414c53" nocase
 $eval = "6576616C28" nocase
 $exec = "65786563" nocase
 $system = "73797374656d" nocase
 $preg_replace = "707265675f7265706c616365" nocase
 $base64_decode = "61736536345f6465636f646528677a696e666c61746528" nocase
 
 condition:
 any of them
 }

 private rule strrev
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $globals = "slabolg" nocase fullword
 $preg_replace = "ecalper_gerp" nocase fullword
 $base64_decode = "edoced_46esab" nocase fullword
 $gzinflate = "etalfnizg" nocase fullword
 
 condition:
 any of them
 }


 private rule SuspiciousEncoding
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 condition:
 (base64_strings or hex or strrev or Hpack)
 }

 private rule DodgyStrings
 {
 meta:
 source = "https://github.com/nbs-system/php-malware-finder"
 
 strings:
 $ = ".bash_history"
 $ = "404 not found" nocase
 $ = "file not found" nocase
 $ = "forbidden" nocase
 $ = /AddType\s+application\/x-httpd-(php|cgi)/ nocase
 $ = /php_value\s*auto_prepend_file/ nocase
 $ = /SecFilterEngine\s+Off/ nocase // disable modsec
 $ = /Add(Handler|Type|OutputFilter)\s+[^\s]+\s+\.htaccess/ nocase
 $ = ".mysql_history"
 $ = ".ssh/authorized_keys"
 $ = "/(.*)/e" // preg_replace code execution
 $ = "/../../../"
 $ = "/etc/passwd"
 $ = "/etc/proftpd.conf"
 $ = "/etc/resolv.conf"
 $ = "/etc/shadow"
 $ = "/etc/syslog.conf"
 $ = "/proc/cpuinfo" fullword
 $ = "/var/log/lastlog"
 $ = "/windows/system32/"
 $ = "LOAD DATA LOCAL INFILE" nocase
 $ = "WScript.Shell"
 $ = "WinExec"
 $ = "b374k" fullword nocase
 $ = "backdoor" fullword nocase
 $ = /(c99|r57|fx29)shell/
 $ = "cmd.exe" fullword nocase
 $ = "powershell.exe" fullword nocase
 $ = /defac(ed|er|ement|ing)/ fullword nocase
 $ = "evilc0ders" fullword nocase
 $ = "exploit" fullword nocase
 $ = "find . -type f" fullword
 $ = "hashcrack" nocase
 $ = "id_rsa" fullword
 $ = "ipconfig" fullword nocase
 $ = "kernel32.dll" fullword nocase
 $ = "kingdefacer" nocase
 $ = "Wireghoul" nocase fullword
 $ = "LD_PRELOAD" fullword
 $ = "libpcprofile" // CVE-2010-3856 local root
 $ = "locus7s" nocase
 $ = "ls -la" fullword
 $ = "meterpreter" fullword
 $ = "nc -l" fullword
 $ = "netstat -an" fullword
 $ = "php://"
 $ = "ps -aux" fullword
 $ = "rootkit" fullword nocase
 $ = "slowloris" fullword nocase
 $ = "suhosin" fullword
 $ = "sun-tzu" fullword nocase // quote from the Art of War
 $ = /trojan (payload)?/
 $ = "uname -a" fullword
 $ = "visbot" nocase fullword
 $ = "warez" fullword nocase
 $ = "whoami" fullword
 $ = /(r[e3]v[e3]rs[e3]|w[3e]b|cmd)\s*sh[e3]ll/ nocase
 $ = /-perm -0[24]000/ // find setuid files
 $ = /\/bin\/(ba)?sh/ fullword
 $ = /hack(ing|er|ed)/ nocase
 $ = /(safe_mode|open_basedir) bypass/ nocase
 $ = /xp_(execresultset|regenumkeys|cmdshell|filelist)/

 $vbs = /language\s*=\s*vbscript/ nocase
 $asp = "scripting.filesystemobject" nocase

 condition:
 (IRC or 2 of them)
 }

 private rule generic_jsp
 {
 meta:
 source= "https://www.tenable.com/blog/hunting-for-web-shells"

 strings:
 $ = /Runtime.getRuntime\(\).exec\(request.getParameter\(\"[a-zA-Z0-9]+\"\)\);/ ascii

 condition:
 all of them
 }

 private rule eval
 {
 meta:
 source = "https://www.tenable.com/blog/hunting-for-web-shells"

 strings:
 $ = /eval[\( \t]+((base64_decode[\( \t]+)|(str_rot13[\( \t]+)|(gzinflate[\( \t]+)|(gzuncompress[\( \t]+)|(strrev[\( \t]+)|(gzdecode[\( \t]+))+/

 condition:
 all of them
 }

 private rule fopo
 {
 meta:
 source = "https://github.com/tenable/yara-rules/blob/master/webshells/"

 strings:
 $ = /\$[a-zA-Z0-9]+=\"\\(142|x62)\\(141|x61)\\(163|x73)\\(145|x65)\\(66|x36)\\(64|x34)\\(137|x5f)\\(144|x64)\\(145|x65)\\(143|x63)\\(157|x6f)\\(144|x64)\\(145|x65)\";@eval\(/

 condition:
 all of them
 }

 private rule hardcoded_urldecode
 {
 meta:
 source = "https://github.com/tenable/yara-rules/blob/master/webshells/"

 strings:
 $ = /urldecode[\t ]*\([\t ]*'(%[0-9a-fA-F][0-9a-fA-F])+'[\t ]*\)/

 condition:
 all of them
 }

 private rule chr_obfuscation
 {
 meta:
 source = "https://github.com/tenable/yara-rules/blob/master/webshells/"

 strings:
 $ = /\$[^=]+=[\t ]*(chr\([0-9]+\)\.?){2,}/

 condition:
 all of them
 }

 private rule phpInImage
 {
 meta:
 source = "Vlad https://github.com/vlad-s"

 strings:
 $php_tag = "&amp;lt;?php"
 $gif = {47 49 46 38 ?? 61} // GIF8[version]a
 $jfif = { ff d8 ff e? 00 10 4a 46 49 46 }
 $png = { 89 50 4e 47 0d 0a 1a 0a }
 $jpeg = {FF D8 FF E0 ?? ?? 4A 46 49 46 } 

 condition:
 (($gif at 0) or ($jfif at 0) or ($png at 0) or ($jpeg at 0)) and $php_tag
 }

 rule hiddenFunctionality
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Hidden functionality allows malware to masquerade as another filetype"

 condition:
 phpInImage
 }

 rule webshellArtifact 
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Artifacts common to web shells and rare in benign files"

 condition:
 b374k or pas_tool or pbot or generic_jsp
 }

 rule suspiciousFunctionality
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Artifacts common to web shells and somewhat rare in benign files"

 condition:
 passwordProtection or hardcoded_urldecode or fopo or eval
 }

 rule obfuscatedFunctionality
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Obfuscation sometimes hides malicious functionality"

 condition:
 ObfuscatedPhp or chr_obfuscation or SuspiciousEncoding
 }

 rule possibleIndicator
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Artifacts common to web shells and less common in benign files"

 condition:
 DodgyPhp or DangerousPhp or DodgyStrings
 }


 private rule APT_Backdoor_MSIL_SUNBURST_1
 {
 meta:
 author = "FireEye"
 description = "This rule is looking for portions of the SUNBURST backdoor that are vital to how it functions. The first signature fnv_xor matches a magic byte xor that the sample performs on process, service, and driver names/paths. SUNBURST is a backdoor that has the ability to spawn and kill processes, write and delete files, set and create registry keys, gather system information, and disable a set of forensic analysis tools and services."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/yara/APT_Backdoor_MSIL_SUNBURST_1.yar"
 
 strings:
 $cmd_regex_encoded = "U4qpjjbQtUzUTdONrTY2q42pVapRgooABYxQuIZmtUoA" wide
 $cmd_regex_plain = { 5C 7B 5B 30 2D 39 61 2D 66 2D 5D 7B 33 36 7D 5C 7D 22 7C 22 5B 30 2D 39 61 2D 66 5D 7B 33 32 7D 22 7C 22 5B 30 2D 39 61 2D 66 5D 7B 31 36 7D }
 $fake_orion_event_encoded = "U3ItS80rCaksSFWyUvIvyszPU9IBAA==" wide
 $fake_orion_event_plain = { 22 45 76 65 6E 74 54 79 70 65 22 3A 22 4F 72 69 6F 6E 22 2C }
 $fake_orion_eventmanager_encoded = "U3ItS80r8UvMTVWyUgKzfRPzEtNTi5R0AA==" wide
 $fake_orion_eventmanager_plain = { 22 45 76 65 6E 74 4E 61 6D 65 22 3A 22 45 76 65 6E 74 4D 61 6E 61 67 65 72 22 2C }
 $fake_orion_message_encoded = "U/JNLS5OTE9VslKqNqhVAgA=" wide
 $fake_orion_message_plain = { 22 4D 65 73 73 61 67 65 22 3A 22 7B 30 7D 22 }
 $fnv_xor = { 67 19 D8 A7 3B 90 AC 5B }
 condition:
 $fnv_xor and ($cmd_regex_encoded or $cmd_regex_plain) or ( ($fake_orion_event_encoded or $fake_orion_event_plain) and ($fake_orion_eventmanager_encoded or $fake_orion_eventmanager_plain) and ($fake_orion_message_encoded and $fake_orion_message_plain) )
 }

 private rule APT_Backdoor_MSIL_SUNBURST_2
 {
 meta:
 author = "FireEye"
 description = "The SUNBURST backdoor uses a domain generation algorithm (DGA) as part of C2 communications. This rule is looking for each branch of the code that checks for which HTTP method is being used. This is in one large conjunction, and all branches are then tied together via disjunction. The grouping is intentionally designed so that if any part of the DGA is re-used in another sample, this signature should match that re-used portion. SUNBURST is a backdoor that has the ability to spawn and kill processes, write and delete files, set and create registry keys, gather system information, and disable a set of forensic analysis tools and services."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/yara/APT_Backdoor_MSIL_SUNBURST_2.yar"
 
 strings:
 $a = "0y3Kzy8BAA==" wide
 $aa = "S8vPKynWL89PS9OvNqjVrTYEYqNa3fLUpDSgTLVxrR5IzggA" wide
 $ab = "S8vPKynWL89PS9OvNqjVrTYEYqPaauNaPZCYEQA=" wide
 $ac = "C88sSs1JLS4GAA==" wide
 $ad = "C/UEAA==" wide
 $ae = "C89MSU8tKQYA" wide
 $af = "8wvwBQA=" wide
 $ag = "cyzIz8nJBwA=" wide
 $ah = "c87JL03xzc/LLMkvysxLBwA=" wide
 $ai = "88tPSS0GAA==" wide
 $aj = "C8vPKc1NLQYA" wide
 $ak = "88wrSS1KS0xOLQYA" wide
 $al = "c87PLcjPS80rKQYA" wide
 $am = "Ky7PLNAvLUjRBwA=" wide
 $an = "06vIzQEA" wide
 $b = "0y3NyyxLLSpOzIlPTgQA" wide
 $c = "001OBAA=" wide
 $d = "0y0oysxNLKqMT04EAA==" wide
 $e = "0y3JzE0tLknMLQAA" wide
 $f = "003PyU9KzAEA" wide
 $h = "0y1OTS4tSk1OBAA=" wide
 $i = "K8jO1E8uytGvNqitNqytNqrVA/IA" wide
 $j = "c8rPSQEA" wide
 $k = "c8rPSfEsSczJTAYA" wide
 $l = "c60oKUp0ys9JAQA=" wide
 $m = "c60oKUp0ys9J8SxJzMlMBgA=" wide
 $n = "8yxJzMlMBgA=" wide
 $o = "88lMzygBAA==" wide
 $p = "88lMzyjxLEnMyUwGAA==" wide
 $q = "C0pNL81JLAIA" wide
 $r = "C07NzXTKz0kBAA==" wide
 $s = "C07NzXTKz0nxLEnMyUwGAA==" wide
 $t = "yy9IzStOzCsGAA==" wide
 $u = "y8svyQcA" wide
 $v = "SytKTU3LzysBAA==" wide
 $w = "C84vLUpOdc5PSQ0oygcA" wide
 $x = "C84vLUpODU4tykwLKMoHAA==" wide
 $y = "C84vLUpO9UjMC07MKwYA" wide
 $z = "C84vLUpO9UjMC04tykwDAA==" wide
 condition:
 ($a and $b and $c and $d and $e and $f and $h and $i) or ($j and $k and $l and $m and $n and $o and $p and $q and $r and $s and ($aa or $ab)) or ($t and $u and $v and $w and $x and $y and $z and ($aa or $ab)) or ($ac and $ad and $ae and $af and $ag and $ah and ($am or $an)) or ($ai and $aj and $ak and $al and ($am or $an))
 }

 private rule APT_Backdoor_MSIL_SUNBURST_3
 {
 meta:
 author = "FireEye"
 description = "This rule is looking for certain portions of the SUNBURST backdoor that deal with C2 communications. SUNBURST is a backdoor that has the ability to spawn and kill processes, write and delete files, set and create registry keys, gather system information, and disable a set of forensic analysis tools and services."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/yara/APT_Backdoor_MSIL_SUNBURST_3.yar"
 
 strings:
 $sb1 = { 05 14 51 1? 0A 04 28 [2] 00 06 0? [0-16] 03 1F ?? 2E ?? 03 1F ?? 2E ?? 03 1F ?? 2E ?? 03 1F [1-32] 03 0? 05 28 [2] 00 06 0? [0-32] 03 [0-16] 59 45 06 }
 $sb2 = { FE 16 [2] 00 01 6F [2] 00 0A 1? 8D [2] 00 01 [0-32] 1? 1? 7B 9? [0-16] 1? 1? 7D 9? [0-16] 6F [2] 00 0A 28 [2] 00 0A 28 [2] 00 0A [0-32] 02 7B [2] 00 04 1? 6F [2] 00 0A [2-32] 02 7B [2] 00 04 20 [4] 6F [2] 00 0A [0-32] 13 ?? 11 ?? 11 ?? 6E 58 13 ?? 11 ?? 11 ?? 9? 1? [0-32] 60 13 ?? 0? 11 ?? 28 [4] 11 ?? 11 ?? 9? 28 [4] 28 [4-32] 9? 58 [0-32] 6? 5F 13 ?? 02 7B [2] 00 04 1? ?? 1? ?? 6F [2] 00 0A 8D [2] 00 01 }
 $ss1 = "\x00set_UseShellExecute\x00"
 $ss2 = "\x00ProcessStartInfo\x00"
 $ss3 = "\x00GetResponseStream\x00"
 $ss4 = "\x00HttpWebResponse\x00"
 
 condition:
 (uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) and all of them
 }

 private rule APT_Backdoor_MSIL_SUNBURST_4
 {
 meta:
 author = "FireEye"
 description = "This rule is looking for specific methods used by the SUNBURST backdoor. SUNBURST is a backdoor that has the ability to spawn and kill processes, write and delete files, set and create registry keys, gather system information, and disable a set of forensic analysis tools and services."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/yara/APT_Backdoor_MSIL_SUNBURST_4.yar"
 
 strings:
 $ss1 = "\x00set_UseShellExecute\x00"
 $ss2 = "\x00ProcessStartInfo\x00"
 $ss3 = "\x00GetResponseStream\x00"
 $ss4 = "\x00HttpWebResponse\x00"
 $ss5 = "\x00ExecuteEngine\x00"
 $ss6 = "\x00ParseServiceResponse\x00"
 $ss7 = "\x00RunTask\x00"
 $ss8 = "\x00CreateUploadRequest\x00"
 
 condition:
 (uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) and all of them
 }

 private rule APT_Dropper_Raw64_TEARDROP_1
 {
 meta:
 author = "FireEye"
 description = "This rule looks for portions of the TEARDROP backdoor that are vital to how it functions. TEARDROP is a memory only dropper that can read files and registry keys, XOR decode an embedded payload, and load the payload into memory. TEARDROP persists as a Windows service and has been observed dropping Cobalt Strike BEACON into memory."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/TEARDROP/yara/APT_Dropper_Raw64_TEARDROP_1.yar"
 
 strings:
 $sb1 = { C7 44 24 ?? 80 00 00 00 [0-64] BA 00 00 00 80 [0-32] 48 8D 0D [4-32] FF 15 [4] 48 83 F8 FF [2-64] 41 B8 40 00 00 00 [0-64] FF 15 [4-5] 85 C0 7? ?? 80 3D [4] FF }
 $sb2 = { 80 3D [4] D8 [2-32] 41 B8 04 00 00 00 [0-32] C7 44 24 ?? 4A 46 49 46 [0-32] E8 [4-5] 85 C0 [2-32] C6 05 [4] 6A C6 05 [4] 70 C6 05 [4] 65 C6 05 [4] 67 }
 $sb3 = { BA [4] 48 89 ?? E8 [4] 41 B8 [4] 48 89 ?? 48 89 ?? E8 [4] 85 C0 7? [1-32] 8B 44 24 ?? 48 8B ?? 24 [1-16] 48 01 C8 [0-32] FF D0 }
 
 condition:
 all of them
 }

 private rule APT_Dropper_Win64_TEARDROP_2
 {
 meta:
 author = "FireEye"
 description = "This rule is intended match specific sequences of opcode found within TEARDROP, including those that decode the embedded payload. TEARDROP is a memory only dropper that can read files and registry keys, XOR decode an embedded payload, and load the payload into memory. TEARDROP persists as a Windows service and has been observed dropping Cobalt Strike BEACON into memory."
 source = "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/TEARDROP/yara/APT_Dropper_Win64_TEARDROP_2.yar"
 
 strings:
 $loc_4218FE24A5 = { 48 89 C8 45 0F B6 4C 0A 30 }
 $loc_4218FE36CA = { 48 C1 E0 04 83 C3 01 48 01 E8 8B 48 28 8B 50 30 44 8B 40 2C 48 01 F1 4C 01 FA }
 $loc_4218FE2747 = { C6 05 ?? ?? ?? ?? 6A C6 05 ?? ?? ?? ?? 70 C6 05 ?? ?? ?? ?? 65 C6 05 ?? ?? ?? ?? 67 }
 $loc_5551D725A0 = { 48 89 C8 45 0F B6 4C 0A 30 48 89 CE 44 89 CF 48 F7 E3 48 C1 EA 05 48 8D 04 92 48 8D 04 42 48 C1 E0 04 48 29 C6 }
 $loc_5551D726F6 = { 53 4F 46 54 57 41 52 45 ?? ?? ?? ?? 66 74 5C 43 ?? ?? ?? ?? 00 }
 
 condition:
 (uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) and any of them
 }

 import "pe"
 private rule SentinelLabs_SUPERNOVA
 {
 meta:
 description = "Identifies potential versions of App_Web_logoimagehandler.ashx.b6031896.dll weaponized with SUPERNOVA"
 date = "2020-12-22"
 author = "SentinelLabs"
 source = "https://labs.sentinelone.com/solarwinds-understanding-detecting-the-supernova-webshell-trojan/"
 
 strings:
 $ = "clazz"
 $ = "codes"
 $ = "args"
 $ = "ProcessRequest"
 $ = "DynamicRun"
 $ = "get_IsReusable"
 $ = "logoimagehandler.ashx" wide
 $ = "SiteNoclogoImage" wide
 $ = "SitelogoImage" wide

 condition:
 (uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and pe.imports("mscoree.dll")) and all of them
 }

 rule SolarWindsArtifacts
 {
 meta:
 author = "NSA Cybersecurity"
 description = "Artifacts common to the SolarWinds compromise."

 condition:
 APT_Backdoor_MSIL_SUNBURST_1 
 or APT_Backdoor_MSIL_SUNBURST_2 
 or APT_Backdoor_MSIL_SUNBURST_3 
 or APT_Backdoor_MSIL_SUNBURST_4 
 or APT_Dropper_Raw64_TEARDROP_1 
 or APT_Dropper_Win64_TEARDROP_2
 or SentinelLabs_SUPERNOVA
 }

 rule reGeorg_Variant_Web_shell {
 meta:
 description = "Matches the reGeorg variant web shell used by the actors."
 date = "2021-07-01"
 author = "National Security Agency"
 source = "https://media.defense.gov/2021/Jul/01/2002753896/-1/-1/1/CSA_GRU_GLOBAL_BRUTE_FORCE_CAMPAIGN_UOO158036-21.PDF"
 
 strings:
 $pageLanguage = "&amp;lt;%@ Page Language=\"C#\""
 $obfuscationFunction = "StrTr"
 $target = "target_str"
 $IPcomms = "System.Net.IPEndPoint"
 $addHeader = "Response.AddHeader"
 $socket = "Socket"
 
 condition:
 5 of them
 }

sources:
 - name: YaraHits
 query: |
 LET webroot = SELECT * FROM switch(
 windows={SELECT WindowsWebRoot AS Dir FROM info() WHERE OS = "windows"},
 linux={SELECT LinuxWebRoot AS Dir FROM info() WHERE OS = "linux"}
 ) 
 LET webroot_dir &amp;lt;= webroot[0].Dir
 Select * FROM Artifact.Generic.Detection.Yara.Glob(PathGlob=webroot_dir, YaraRule=YaraRule, DateAfter=DateAfter)
 - name: WindowsProcessCreation
 precondition:
 SELECT OS From info() where OS = 'windows'
 query: |
 SELECT * FROM Artifact.Windows.EventLogs.Evtx(EvtxGlob='%SystemRoot%\\System32\\winevt\\Logs\\{*Sysmon*,Security}\.evtx', IDRegex="1|4688")
 WHERE ( Channel =~ 'sysmon' AND EventID = 1 AND EventData.ParentImage =~ WebserverProcessRegex AND EventData.Image =~ SpawnedProcessRegex )
 OR ( Channel =~ 'Security' AND EventID = 4688 AND EventData.ParentProcessName =~ WebserverProcessRegex AND EventData.NewProcessName =~ SpawnedProcessRegex )
 - name: FileSystemChanges
 query: |
 -- time test function (taken from Windows.NTFS.MFT)
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))
 
 LET webroot = SELECT * FROM switch(
 windows={SELECT WindowsWebRoot AS Dir FROM info() WHERE OS = "windows"},
 linux={SELECT LinuxWebRoot AS Dir FROM info() WHERE OS = "linux"}
 ) 
 LET webroot_dir &amp;lt;= webroot[0].Dir
 SELECT * FROM glob(globs=webroot_dir, accessor="auto")
 WHERE 
 NOT IsDir 
 AND (time_test(stamp=Btime) OR time_test(stamp=Mtime))
 AND Name =~ WebshellRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Detection.Yara.SSH</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sshyara/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sshyara/</guid><description>&lt;p&gt;This is a server artifact that enables running Generic.Detection.Yara.Glob
over ssh.&lt;/p&gt;
&lt;p&gt;This artifact can be used to run against a single server or against a list of
servers via notebook foreach.&lt;/p&gt;
&lt;p&gt;Keys are passed as path on disk to preserve potential key leakage. You can also
modify the artifact to allow server_metadata to be passed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Detection.Yara.SSH
author: Matt Green - @mgreen27
description: |
 This is a server artifact that enables running Generic.Detection.Yara.Glob 
 over ssh.
 
 This artifact can be used to run against a single server or against a list of 
 servers via notebook foreach.
 
 Keys are passed as path on disk to preserve potential key leakage. You can also 
 modify the artifact to allow server_metadata to be passed.


type: SERVER
parameters:
 - name: TargetHost
 description: Target SSH host in the format &amp;lt;hostname or IP&amp;gt;:&amp;lt;port&amp;gt;
 - name: TargetUsername
 description: SSH Username to connect - e.g ubuntu
 - name: TargetKey
 description: SSH key path as Velociraptor server metadata or path on disk.
 - name: PathGlob
 description: Only file names that match this glob will be scanned.
 default: /usr/bin/ls
 - name: SizeMax
 description: maximum size of target file.
 type: int64
 - name: SizeMin
 description: minimum size of target file.
 type: int64
 - name: UploadHits
 type: bool
 - 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: YaraRule
 type: yara
 description: Final Yara option and the default if no other options provided.
 default: |
 rule IsELF:TestRule {
 meta:
 author = "the internet"
 date = "2021-05-03"
 description = "A simple ELF rule to test yara features"
 condition:
 uint32(0) == 0x464c457f
 }
 - name: NumberOfHits
 description: This artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int

sources:
 - query: |
 LET SSH_CONFIG &amp;lt;= dict(
 hostname= TargetHost,
 username= TargetUsername,
 private_key= read_file(filename=TargetKey)
 )

 LET _ &amp;lt;= remap(config='''
 remappings:
 - type: mount
 from:
 accessor: ssh
 on:
 accessor: auto
 ''')

 SELECT * FROM Artifact.Generic.Detection.Yara.Glob(
 PathGlob=PathGlob,
 YaraRule=YaraRule,
 NumberOfHits=NumberOfHits,
 ContextBytes=ContextBytes,
 SizeMax=SizeMax,
 SizeMin=SizeMin,
 UploadHits=UploadHits,
 DateAfter=DateAfter,
 DateBefore=DateBefore
 )

column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Events.TrackNetworkConnections</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.events.tracknetworkconnections/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.events.tracknetworkconnections/</guid><description>&lt;p&gt;This artifact is meant for monitoring network connections on clients.
It periodically queries the existing network connections and emits lines for differences (new connections and missing/removed ones).
Network connections are tracked and compared based on following elements: process id, layer 3 protocol, layer 4 protocol, local address used, local port used, remote address used, remote port used.&lt;/p&gt;
&lt;p&gt;The network connection information is enriched with process information to make it easier to analyze emited lines.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Events.TrackNetworkConnections
author: Herbert Bärschneider @SEC Consult
description: |
 This artifact is meant for monitoring network connections on clients.
 It periodically queries the existing network connections and emits lines for differences (new connections and missing/removed ones).
 Network connections are tracked and compared based on following elements: process id, layer 3 protocol, layer 4 protocol, local address used, local port used, remote address used, remote port used.
 
 The network connection information is enriched with process information to make it easier to analyze emited lines.

type: CLIENT_EVENT

parameters:
 - name: Period
 default: 2
 type: int
 description: how many seconds the artifact waits between checking network connections for changes

sources:
 - query: |
 LET NetworkConnections = SELECT *, format(format="%v %v %v %v %v %v %v", args=[Pid, Family, Type, Laddr.IP, Laddr.Port, Raddr.IP, Raddr.Port]) AS DiffKey FROM netstat()
 
 LET EventQuery = SELECT * FROM diff(query=NetworkConnections, period=Period, key="DiffKey")
 
 SELECT *, process_tracker_get(id=Pid) AS ProcInfo FROM EventQuery

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.File.LineScan.RegexHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.file.linescan.regexhunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.file.linescan.regexhunter/</guid><description>&lt;p&gt;A versatile artifact that scans the contents of text files line by line and reports
any line that matches a user-supplied regular expression.
This artifact is designed for flexible content inspection across any operating system—
Linux, Windows. It can be used to detect indicators of compromise, identify
suspicious commands in configuration files, or validate specific text patterns.&lt;/p&gt;
&lt;p&gt;The user can supply one or more glob paths and a custom regex pattern.
Matching lines are returned with their file names, and—if enabled—the corresponding
files can be uploaded for further analysis.&lt;/p&gt;
&lt;p&gt;Includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SkipPathRegex&lt;/strong&gt; → exclude specific files from scanning in the paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WhitelistLineRegex&lt;/strong&gt; → ignore specific line matches even if they match the main detection regex.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.File.LineScan.RegexHunter
author: Kaizar Lehri
description: |
 A versatile artifact that scans the contents of text files line by line and reports 
 any line that matches a user-supplied regular expression.
 This artifact is designed for flexible content inspection across any operating system—
 Linux, Windows. It can be used to detect indicators of compromise, identify 
 suspicious commands in configuration files, or validate specific text patterns.

 The user can supply one or more glob paths and a custom regex pattern. 
 Matching lines are returned with their file names, and—if enabled—the corresponding 
 files can be uploaded for further analysis.

 Includes:
 - **SkipPathRegex** → exclude specific files from scanning in the paths.
 - **WhitelistLineRegex** → ignore specific line matches even if they match the main detection regex.

type: CLIENT

parameters:
 - name: PathGlobs
 type: csv
 description: "List of glob paths to search."
 default: |
 Glob
 /etc/crontab
 /etc/cron.d/*
 /etc/cron.daily/*
 /etc/cron.hourly/*
 /etc/cron.weekly/*
 /etc/cron.monthly/*
 /var/spool/cron/*
 /var/spool/cron/crontabs/*

 - name: SuspiciousRegex
 type: regex
 description: "Regex pattern to detect potentially suspicious commands or payloads."
 default: "(curl|wget|bash|/tmp/|/var/tmp/|/dev/shm|base64|eval|python|perl|crontab -e|@reboot)"

 - name: SkipPathRegex
 type: regex
 description: |
 Exclude specific files in the paths or just the paths from Scanning.
 default: "/etc/cron.daily/apt-compat"

 - name: WhitelistLineRegex
 type: regex
 description: |
 Regex pattern to exclude specific lines (known benign content).
 Matching lines will be ignored even if they match SuspiciousRegex.
 default: "^$"

 - name: UploadMatches
 type: bool
 description: "If true, upload files that contain regex matches."
 default: false

sources:
 - query: |
 -- Step 1: Gather all candidate files
 LET found_files = SELECT OSPath, Name, Size
 FROM glob(globs=PathGlobs.Glob, nosymlink=true)
 WHERE NOT IsDir AND NOT IsLink

 -- Step 2: Skip files whose paths match SkipPathRegex
 LET filtered_files = SELECT OSPath, Name, Size
 FROM found_files
 WHERE NOT OSPath =~ SkipPathRegex

 -- Step 3: Scan each remaining file line-by-line for suspicious regex matches
 LET regex_hits = SELECT *
 FROM foreach(
 row={ SELECT OSPath FROM filtered_files },
 query={
 SELECT
 OSPath AS FileName,
 Line AS LineMatch
 FROM parse_lines(filename=OSPath)
 WHERE Line =~ SuspiciousRegex
 }
 )

 -- Step 4: Remove benign line matches
 LET filtered_hits = SELECT *
 FROM regex_hits
 WHERE NOT LineMatch =~ WhitelistLineRegex

 -- Step 5: Optionally upload matching files
 LET upload_hits = SELECT
 FileName,
 LineMatch,
 upload(file=FileName, name=FileName) AS UploadedFile
 FROM filtered_hits

 -- Step 6: Return results with or without upload
 SELECT *
 FROM if(
 condition=UploadMatches,
 then=upload_hits,
 else=filtered_hits
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Forensics.CyLR</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.forensics.cylr/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.forensics.cylr/</guid><description>&lt;p&gt;Uses CyLR tool to do live forensic on the host.&lt;/p&gt;
&lt;p&gt;Note this requires syncing the CyLR binary from the host.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Forensics.CyLR
description: |
 Uses CyLR tool to do live forensic on the host.

 Note this requires syncing the CyLR binary from the host.

tools:
 - name: Cylr_amd64
 serve_locally: true

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

parameters:
 - name: TargetDir
 type: string
 default: "%SystemDrive%\\"
 - name: ZipPassword
 type: string
 default: ""
 - name: ToolInfo
 type: hidden
 description: Override Tool information.

sources:
 - query: |
 LET os_info &amp;lt;= SELECT Architecture,Hostname FROM info()

 // Get the path to the binary.
 LET bin &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName= "Cylr_" + os_info[0].Architecture,
 ToolInfo=ToolInfo)
 
 // Set necessary variables
 LET hostname = os_info[0].Hostname
 LET outputDir &amp;lt;= expand(path=TargetDir)
 LET outputFile = upcase(string=hostname)+".zip"
 LET logFile &amp;lt;= outputDir + "\\" + "CylR.log"
 LET fullOutputFile &amp;lt;= outputDir + "\\" + outputFile
 
 // Call the binary and return all its output in a single row.
 LET output &amp;lt;= SELECT * FROM execve(argv=[bin[0].FullPath, '-od', outputDir, ], cwd=outputDir, length=10000000)

 // Upload the forensic file and report additional data.
 SELECT upload(file=logFile) AS LogFile, upload(file=fullOutputFile) AS ForensicFile FROM scope()

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generic.Forensics.VMWareInventory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/generic.forensics.vmwareinventory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/generic.forensics.vmwareinventory/</guid><description>&lt;p&gt;Finds and parses VMware VM configuration files (.vmx) on Mac and Windows.
It turns text into an organized list (dictionary) so you can easily
search for settings like RAM size, Guest OS, or network modes.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Generic.Forensics.VMWareInventory
author: Kaizar Lehri
description: |
 Finds and parses VMware VM configuration files (.vmx) on Mac and Windows. 
 It turns text into an organized list (dictionary) so you can easily 
 search for settings like RAM size, Guest OS, or network modes.

parameters:
 - name: path_list
 type: csv
 default: |
 globs
 /Users/*/Virtual Machines*/**/*.vmwarevm/*.vmx
 C:/Users/*/Documents/Virtual Machines/**/*.vmx

sources:
 - name: VMWare_Config_Audit
 query: |
 LET vmx_files = SELECT OSPath, Mtime FROM glob(globs=path_list.globs)
 
 SELECT 
 OSPath,
 Mtime AS LastModified,
 to_dict(item={
 SELECT _key, _value FROM foreach(
 row={
 SELECT parse_string_with_regex(
 string=Line,
 regex='^(?P&amp;lt;_key&amp;gt;[^\\s=]+)\\s*=\\s*"(?P&amp;lt;_value&amp;gt;[^"]*)"') AS Record
 FROM parse_lines(filename=OSPath)
 },
 column="Record"
 ) WHERE _key
 }) AS Config
 FROM vmx_files

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>HashRunKeys</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/hash_run_keys/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/hash_run_keys/</guid><description>&lt;p&gt;Iterate over all the run keys and locate their binary then hash it.&lt;/p&gt;
&lt;p&gt;Tags: #windows #registry #detection&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: HashRunKeys
description: |
 Iterate over all the run keys and locate their binary then hash it.

 Tags: #windows #registry #detection

parameters:
 - name: runKeys
 default: |
 HKEY_USERS\*\Software\Microsoft\Windows\CurrentVersion\Run\*

 - name: pathRegex
 type: hidden

 # Pick the first part - either quoted or not.
 default: &amp;gt;-
 (^"(?P&amp;lt;quoted_path&amp;gt;[^"]+)"|(?P&amp;lt;unquoted_path&amp;gt;^[^ ]+))

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 query: |
 LET paths = SELECT FullPath,Name, Data.value AS Value,
 parse_string_with_regex(string=Data.value,
 regex=pathRegex) as regData
 FROM glob(globs=split(string=runKeys, sep="[, \\n]+"),
 accessor="reg")
 WHERE Data.value

 -- Handle some variations we see in the value:
 -- system32\drivers\XXX.sys -&amp;gt; %systemRoot%\System32\
 -- \SystemRoot\ -&amp;gt; %SystemRoot%\
 LET normalized = SELECT *,
 expand(path=
 regex_replace(re='(?i)^system32\\\\',
 replace="%SystemRoot%\\system32\\",
 source=regex_replace(
 source=regData.quoted_path + regData.unquoted_path,
 re="^\\\\SystemRoot\\\\",
 replace="%SystemRoot%\\"))) AS RealPath
 FROM paths

 SELECT FullPath, Name, Value, RealPath,
 hash(path=expand(path=RealPath)).SHA256 AS Hash
 FROM normalized

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>IPCheck.Virustotal</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ipcheck.virustotal/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ipcheck.virustotal/</guid><description>&lt;p&gt;Submit a IP to Virustotal. Default Public API restriction is 4 requests/min (Inspired on Virustotal file Check created by Wes Lambert &amp;ndash; @therealwlambert).&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.IPCheck.Virustotal(DestIP=$IP)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;EX 2&lt;/p&gt;
&lt;p&gt;Check ip into a netstat:
Call the artifact -&amp;gt; Windows.Network.NetstatEnriched&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`SELECT * FROM source() WHERE DestIP != &amp;quot;127.0.0.1&amp;quot; AND Pid = 14604 (malicious connection)`
VT Notebook analysis.

`LET VTKey &amp;lt;= &amp;quot;Your key&amp;quot;`
`Let Results = SELECT * from source() WHERE DestIP != &amp;quot;127.0.0.1&amp;quot; AND DestIP`
`GROUP BY DestIP`
`SELECT *, {SELECT VTRating FROM Artifact.IPCheck.Virustotal(VirustotalKey=VTKey, ip=DestIP) } AS VTResults FROM foreach(row=Results)`
`ORDER BY VTResults DESC`
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: IPCheck.Virustotal
author: Adrian Lopez Moreno @AdrianX21
description: |
 Submit a IP to Virustotal. Default Public API restriction is 4 requests/min (Inspired on Virustotal file Check created by Wes Lambert -- @therealwlambert).

 This artifact can be called from within another artifact 

 Ex.

 `SELECT * from Artifact.IPCheck.Virustotal(DestIP=$IP)`

 EX 2
 
 Check ip into a netstat: 
 Call the artifact -&amp;gt; Windows.Network.NetstatEnriched
 
 `SELECT * FROM source() WHERE DestIP != "127.0.0.1" AND Pid = 14604 (malicious connection)`
 VT Notebook analysis.
 
 `LET VTKey &amp;lt;= "Your key"`
 `Let Results = SELECT * from source() WHERE DestIP != "127.0.0.1" AND DestIP`
 `GROUP BY DestIP`
 `SELECT *, {SELECT VTRating FROM Artifact.IPCheck.Virustotal(VirustotalKey=VTKey, ip=DestIP) } AS VTResults FROM foreach(row=Results)`
 `ORDER BY VTResults DESC`

type: SERVER

parameters:
 - name: ip
 type: string
 description: IP to check on Virustotal.
 default:

 - name: VirustotalKey
 type: string
 description: API key for Virustotal.
 default:

sources:
 - query: |
 LET Creds = if(
 condition=VirustotalKey,
 then=VirustotalKey,
 else=server_metadata().VirustotalKey)

 LET URL &amp;lt;= 'https://www.virustotal.com/api/v3/ip_addresses/' + ip

 LET Data = SELECT parse_json(data=Content) AS VTData
 FROM http_client(url=URL, headers=dict(`x-apikey`=Creds))

 SELECT format(format='%v/%v',
 args=[VTData.data.attributes.last_analysis_stats.malicious,
 VTData.data.attributes.last_analysis_stats.malicious +
 VTData.data.attributes.last_analysis_stats.undetected]) As VTRating,
 timestamp(epoch=VTData.data.attributes.first_seen_itw_date) AS FirstSeen,
 timestamp(epoch=VTData.data.attributes.first_submission_date) AS FirstSubmitted,
 timestamp(epoch=VTData.data.attributes.last_analysis_date) AS LastAnalysis,
 VTData.data.attributes.crowdsourced_yara_results AS YARAResults,
 VTData AS _Data
 FROM Data

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>IRIS.Sync.Asset</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/iris.sync.asset/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/iris.sync.asset/</guid><description>&lt;p&gt;Synchronizes client information from Velociraptor to &lt;a href="https://dfir-iris.org/" target="_blank" &gt;DFIR-IRIS&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Parses available information from clients such as network interfaces, IP addresses, asset type and applied labels.
Once it has been added, the asset ID from DFIR-IRIS will be added as client metadata and &lt;code&gt;IRIS&lt;/code&gt; will be added as label.&lt;/p&gt;
&lt;p&gt;If this artifact is applied on a client that has the asset ID set in its metadata, it won&amp;rsquo;t be readded but rather
updated: Labels and the compromised status will by synchronized.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tested with Dfir-Iris API v2.0.4 (IRIS v2.4.7)&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="hints"&gt;Hints:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;If it fails to add the client to IRIS, it will assign the &lt;code&gt;IRIS-ERROR&lt;/code&gt; label to it. A successful run afterwards will remove it.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;recommended&lt;/strong&gt; to add the parameters with &amp;lsquo;Iris&amp;rsquo; prefix to the &lt;a href="#/host/server"&gt;Server Metadata&lt;/a&gt; to ease the usage of the artifact. The metadata can alternatively be set from a notebook using VQL similar to this example:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;SELECT server_set_metadata(IrisURL=&amp;quot;https://dfir-iris.local:4433&amp;quot;,
 IrisKey=&amp;quot;This-is-an_API_KEY&amp;quot;,
 IrisCaseId=&amp;quot;1&amp;quot;,
 IrisRootCA='''-----BEGIN CERTIFICATE-----
 &amp;lt;...&amp;gt;
 -----END CERTIFICATE-----'''),server_metadata() FROM scope()
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;You can define the compromise status of a system when creating and when updating the information. &lt;strong&gt;However, if an asset is categorized as &lt;em&gt;compromised&lt;/em&gt;, you cannot change the status using this artifact.&lt;/strong&gt; This is a safety measure to mitigate a potential high impact error. Beside that, you can freely change the status between &lt;em&gt;No&lt;/em&gt;, &lt;em&gt;Unknown&lt;/em&gt; and &lt;em&gt;To be determined&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The true power of this artifact lies in the ability to quickly add many clients to DFIR-IRIS. As it is usually not needed to add all clients that are enrolled in Velociraptor to IRIS but rather an excerpt of important, suspicious, or compromised systems, you will &lt;em&gt;most likely use this artifact from within a notebook&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="example"&gt;Example:&lt;/h4&gt;
&lt;p&gt;to add just a few systems and have the results of the operation as JSON:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-VQL"&gt;SELECT client_id,{SELECT * FROM Artifact.Exchange.IRIS.Sync.Asset(clientId=client_id,isCompromised=&amp;quot;Y&amp;quot;)} FROM clients(search=&amp;quot;label:compromised&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; to add many systems in a performant way and have the results in well-structured columns.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-VQL"&gt;SELECT * FROM foreach(row={SELECT * FROM clients(search=&amp;quot;label:suspicious&amp;quot;)},query={SELECT * FROM Artifact.Exchange.IRIS.Sync.Asset(clientId=client_id,isCompromised=&amp;quot;UNK&amp;quot;)},async=true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ATTENTION: ALWAYS USE ASYNC=FALSE IF CLIENTS ARE PRESENT IN THE TABLE MULTIPLE TIMES! OTHERWISE THESE ASSETS MIGHT BE DUPLICATED IN IRIS!!!&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: IRIS.Sync.Asset

author: Stephan Mikiss @stephmikiss (SEC Defence @SEC Consult) | Updated 2024-08 - [10root Cyber Security] (https://10root.com)

description: |
 Synchronizes client information from Velociraptor to [DFIR-IRIS](https://dfir-iris.org/).

 Parses available information from clients such as network interfaces, IP addresses, asset type and applied labels.
 Once it has been added, the asset ID from DFIR-IRIS will be added as client metadata and `IRIS` will be added as label.

 If this artifact is applied on a client that has the asset ID set in its metadata, it won't be readded but rather
 updated: Labels and the compromised status will by synchronized.

 *Tested with Dfir-Iris API v2.0.4 (IRIS v2.4.7)*

 #### Hints:

 - If it fails to add the client to IRIS, it will assign the `IRIS-ERROR` label to it. A successful run afterwards will remove it.
 - It is **recommended** to add the parameters with 'Iris' prefix to the &amp;lt;a href="#/host/server"&amp;gt;Server Metadata&amp;lt;/a&amp;gt; to ease the usage of the artifact. The metadata can alternatively be set from a notebook using VQL similar to this example:

 ```
 SELECT server_set_metadata(IrisURL="https://dfir-iris.local:4433",
 IrisKey="This-is-an_API_KEY",
 IrisCaseId="1",
 IrisRootCA='''-----BEGIN CERTIFICATE-----
 &amp;lt;...&amp;gt;
 -----END CERTIFICATE-----'''),server_metadata() FROM scope()
 ```

 - You can define the compromise status of a system when creating and when updating the information. **However, if an asset is categorized as *compromised*, you cannot change the status using this artifact.** This is a safety measure to mitigate a potential high impact error. Beside that, you can freely change the status between *No*, *Unknown* and *To be determined*.
 - The true power of this artifact lies in the ability to quickly add many clients to DFIR-IRIS. As it is usually not needed to add all clients that are enrolled in Velociraptor to IRIS but rather an excerpt of important, suspicious, or compromised systems, you will *most likely use this artifact from within a notebook*.

 #### Example:

 to add just a few systems and have the results of the operation as JSON:

 ```VQL
 SELECT client_id,{SELECT * FROM Artifact.Exchange.IRIS.Sync.Asset(clientId=client_id,isCompromised="Y")} FROM clients(search="label:compromised")
 ```

 **Example** to add many systems in a performant way and have the results in well-structured columns.

 ```VQL
 SELECT * FROM foreach(row={SELECT * FROM clients(search="label:suspicious")},query={SELECT * FROM Artifact.Exchange.IRIS.Sync.Asset(clientId=client_id,isCompromised="UNK")},async=true)
 ```
 **ATTENTION: ALWAYS USE ASYNC=FALSE IF CLIENTS ARE PRESENT IN THE TABLE MULTIPLE TIMES! OTHERWISE THESE ASSETS MIGHT BE DUPLICATED IN IRIS!!!**

type: SERVER

parameters:
 - name: clientId
 description: Client Id of the client that should be synced to DFIR-IRIS
 - name: isCompromised
 default: TBD
 description: Specify whether this asset should be marked as compromised in IRIS using "Y" (compromised), "N" (not compromised), "TBD" (to be determined), or "UNK" (unknown).
 type: choices
 choices:
 - Y
 - N
 - TBD
 - UNK
 - name: labelIgnoreListRegex
 default: "IRIS|^Workstation$|^Server$|^Domain Controller$|^Linux$"
 description: Labels that should be ignored and not added to IRIS
 - name: IrisURL
 type: server_metadata
 description: URL of DFIR-IRIS. Preferred method is to use the server metadata
 - name: IrisKey
 type: server_metadata
 description: API Key of DFIR-IRIS. Preferred method is to use the server metadata
 - name: IrisCaseId
 type: server_metadata
 description: Case ID of the current case. Preferred method is to use the server metadata
 - name: IrisRootCA
 type: server_metadata
 description: RootCA of DFIR-IRIS for self-signed or internal certificates of DFIR-IRIS. Preferred over completely skipping SSL verification.
 - name: DisableSSLVerify
 type: bool
 default: false
 description: Disable TLS verification for HTTPS request to DFIR-IRIS.

sources:
 - query: |

 LET AssetType = SELECT * FROM switch(
 a = {SELECT {
 SELECT if(condition = `Computer Info`.DomainRole =~ "Workstation",
 then = 9,
 else = if(condition= `Computer Info`.DomainRole =~ "Server",
 then = 10,
 else = if(condition= `Computer Info`.DomainRole =~ "Domain Controller",
 then = 11
 )))
 FROM flow_results(client_id=clientId,flow_id=last_interrogate_flow_id,artifact="Generic.Client.Info/WindowsInfo")
 } as AssetTypeId
 FROM clients(client_id=clientId)
 WHERE os_info.system =~ "windows"
 },
 b = {SELECT 3 as AssetTypeId
 FROM clients(client_id=clientId)
 WHERE os_info.system =~ "linux"})

 LET resolveIPs =
 SELECT
 {SELECT `Network Info` FROM flow_results(client_id=client_id,flow_id=last_interrogate_flow_id,artifact="Generic.Client.Info/WindowsInfo")} as NetworkInfo
 FROM clients(client_id=clientId)

 LET primaryIP =
 SELECT parse_string_with_regex(string=if(condition=NetworkInfo[0],then=NetworkInfo[0].IPAddresses,else=NetworkInfo.IPAddresses),regex="(?P&amp;lt;IP&amp;gt;[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})").IP as PrimaryIPv4Address
 FROM resolveIPs

 LET networkInterfaces =
 SELECT parse_string_with_regex(string=NetworkInfo.Caption,regex="^\\[.*\\] (?P&amp;lt;IF&amp;gt;.*)").IF as NetworkInterface,
 NetworkInfo.IPAddresses as IPAddresses, NetworkInfo.MACAddress as MACAddress
 FROM flatten(query=resolveIPs)

 LET NetInfo =
 SELECT format(format="%v (%v): %v",args=[NetworkInterface,MACAddress,IPAddresses]) AS fmt FROM networkInterfaces

 LET networkInterfacesDescription =
 SELECT join(array=NetInfo.fmt, sep="\n") as NetworkInfo
 FROM NetInfo

 LET labelToTags =
 join(array=filter(list=labels, condition="x=&amp;gt;NOT x =~ labelIgnoreListRegex"),sep=",")

 LET metadata_preparation =
 SELECT client_metadata(client_id=clientId) as metadata FROM scope() WHERE metadata.IRIS_AssetId

 LET assetId =
 SELECT metadata_preparation.metadata[0].IRIS_AssetId as assetId FROM scope()

 LET addMetadata(assetIdValue) =
 SELECT client_set_metadata(client_id=clientId,metadata=client_metadata(client_id=clientId) + dict(IRIS_AssetId=assetIdValue)), client_metadata(client_id=clientId)
 FROM scope()

 LET assetProperties =
 serialize(item=dict(
 asset_name=format(format="%v",args=[os_info.hostname]),
 asset_type_id=AssetType.AssetTypeId[0],
 analysis_status_id=1,
 asset_compromise_status_id=if(condition=isCompromised=~"^Y$",then=1,else=if(condition=isCompromised=~"^N$",then=2,else=if(condition=isCompromised=~"^UNK$",then=3,else=0))),
 asset_domain=format(format="%v",args=[join(array=slice(list=split(sep_string=".",string=os_info.fqdn),start=1,end=-1),sep=".")]),
 asset_ip=format(format="%v",args=[primaryIP.PrimaryIPv4Address]),
 asset_tags=if(condition=labelToTags,then=format(format="Velo,%v",args=[labelToTags]),else="Velo"),
 asset_description=format(format="Velo ClientId: %v\nVelo Agent First seen: %v\nAsset added to IRIS by Velo: %v\nNetwork Info:\n%v", args=[client_id,timestamp(epoch=first_seen_at),timestamp(epoch=now()),networkInterfacesDescription.NetworkInfo[0]])
 ), format="json" )

 LET apiRequestIrisAdd =
 SELECT *, if(condition=parse_json(data=Content).data.asset_id,
 then={ SELECT addMetadata(assetIdValue=format(format="%v",
 args=parse_json(data=Content).data.asset_id)),
 label(client_id=clientId,op="set",labels="IRIS"),
 label(client_id=clientId,op="remove",labels="IRIS-ERROR")
 FROM scope()},
 else={ SELECT label(client_id=clientId,op="set",labels="IRIS-ERROR")
 FROM scope()}) as applyLabels
 FROM http_client(
 data=assetProperties,
 headers=dict(
 `Content-Type`="application/json", `Authorization`=format(format="Bearer %v",
 args=[IrisKey])),
 skip_verify=DisableSSLVerify,
 root_ca=IrisRootCA,
 method="POST",
 url=format(format="%v/case/assets/add?cid=%v", args=[IrisURL,IrisCaseId]))

 LET apiRequestIrisGet(assetId) =
 SELECT parse_json(data=Content),
 parse_json(data=Content).data.asset_name as asset_name,
 parse_json(data=Content).data.asset_type_id as asset_type_id,
 parse_json(data=Content).data.analysis_status_id as analysis_status_id,
 parse_json(data=Content).data.asset_tags as asset_tags,
 parse_json(data=Content).data.linked_ioc as linked_ioc,
 parse_json(data=Content).data.custom_attributes as custom_attributes,
 parse_json(data=Content).data.asset_compromise_status_id as asset_compromise_status_id
 FROM http_client(
 headers=dict(
 `Content-Type`="application/json", `Authorization`=format(format="Bearer %v",
 args=[IrisKey])),
 skip_verify=DisableSSLVerify,
 root_ca=IrisRootCA,
 method="GET",
 url=format(format="%v/case/assets/%v?cid=%v", args=[IrisURL,assetId,IrisCaseId]))

 LET assetPropertiesUpdate = serialize(
 item=dict(
 asset_name=currentAsset.asset_name[0],
 asset_type_id=currentAsset.asset_type_id[0],
 analysis_status_id=currentAsset.analysis_status_id[0],
 asset_compromise_status_id=if(
 condition=isCompromised =~ "^Y$",
 then=1,
 else=if(
 condition=currentAsset.asset_compromise_status_id[0] = 1,
 then=1,
 else=if(
 condition=isCompromised =~ "^N$",
 then=2,
 else=if(
 condition=isCompromised =~ "^UNK$",
 then=3,
 else=if(
 condition=isCompromised =~ "^TBD$",
 then=0,
 else=currentAsset.asset_compromise_status_id[0]))))),
 asset_tags=if(
 condition=labelToTags,
 then=format(format="Velo,%v", args=[labelToTags]),
 else="Velo")),
 format="json")

 LET apiRequestIrisUpdate(currentAsset,assetId) =
 SELECT *,
 if(condition= Response=200,
 then={ SELECT addMetadata(assetIdValue=format(format="%v",args=parse_json(data=Content).data.asset_id)),
 label(client_id=clientId,op="set",labels="IRIS"),
 label(client_id=clientId,op="remove",labels="IRIS-ERROR")
 FROM scope()},
 else={ SELECT label(client_id=clientId,op="set",labels="IRIS-ERROR") FROM scope()}) as applyLabels
 FROM http_client(data=assetPropertiesUpdate,
 headers=dict(
 `Content-Type`="application/json", `Authorization`=format(format="Bearer %v",
 args=[IrisKey])),
 skip_verify=DisableSSLVerify,
 root_ca=IrisRootCA,
 method="POST",
 url=format(format="%v/case/assets/update/%v?cid=%v",
 args=[IrisURL,assetId,IrisCaseId]))

 LET addAsset =
 SELECT { SELECT * FROM apiRequestIrisAdd } as apiRequestIrisAdd FROM clients(client_id=clientId)

 LET updateAsset =
 SELECT { SELECT * FROM apiRequestIrisUpdate(currentAsset=apiRequestIrisGet(assetId=client_metadata(client_id=clientId).IRIS_AssetId),assetId=client_metadata(client_id=clientId).IRIS_AssetId) } as apiRequestIrisUpdate
 FROM clients(client_id=clientId)


 SELECT * FROM if(condition= metadata_preparation,
 then={ SELECT
 "Already Added -&amp;gt; Update labels and compromise status in IRIS" AS Action,
 if(
 condition=apiRequestIrisUpdate.Response = 200,
 then="SUCCESS",
 else="ERROR") AS Result,
 parse_json(
 data=apiRequestIrisUpdate.Content).data AS AssetProperties,
 apiRequestIrisUpdate.applyLabels[0].`addMetadata(assetIdValue=format(format="%v", args=parse_json(data=Content).data.asset_id))`[0].`client_metadata(client_id=clientId)`.IRIS_AssetId AS IRIS_AssetId,
 apiRequestIrisUpdate AS _rawEvent
 FROM updateAsset
 },
 else={ SELECT
 "Needs to be added" AS Action,
 if(
 condition=apiRequestIrisAdd.Response = 200,
 then="SUCCESS",
 else="ERROR") AS Result,
 parse_json(
 data=apiRequestIrisAdd.Content).data AS AssetProperties,
 apiRequestIrisAdd.applyLabels[0].`addMetadata(assetIdValue=format(format="%v", args=parse_json(data=Content).data.asset_id))`[0].`client_metadata(client_id=clientId)`.IRIS_AssetId AS IRIS_AssetId,
 apiRequestIrisAdd AS _rawEvent
 FROM addAsset
 }
 )


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>IRIS.Timeline.Add</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/iris.timeline.add/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/iris.timeline.add/</guid><description>&lt;p&gt;Adds Velociraptor rows as timeline entries to &lt;a href="https://dfir-iris.org/" target="_blank" &gt;DFIR-IRIS&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Links the assets and IOCs as specified in the parameters. Additionally, if the client does not yet exist in Iris, this artifact will leverage the &lt;strong&gt;IRIS.Sync.Asset&lt;/strong&gt; artifact to add the asset to Iris first and link it in the event.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tested with Dfir-Iris API v2.0.4 (IRIS v2.4.7)&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="notes"&gt;Notes:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The following parameters are &lt;em&gt;mandatory&lt;/em&gt;:
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Timestamp&lt;/strong&gt;: This specifies the name of the field in the source containing the event timestamp. For this artifact to parse it correctly the field should contain a parsed timestamp object. If you are using this artifact from a global notebook then the field is probably already parsed. If not then you should ensure that it is parsed in your source using the &lt;code&gt;timestamp&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Title&lt;/strong&gt;: This specifies the name of the field in the source containing the event title which will be used on the Iris timeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="hints"&gt;Hints:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;It is &lt;strong&gt;recommended&lt;/strong&gt; to add the parameters with &amp;lsquo;Iris&amp;rsquo; prefix to the &lt;a href="#/host/server"&gt;Server Metadata&lt;/a&gt; to ease the usage of the artifact. The metadata can alternatively be set from a notebook using VQL similar to this example:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;SELECT server_set_metadata(IrisURL=&amp;quot;https://dfir-iris.local:4433&amp;quot;,IrisKey=&amp;quot;This-is-an_API_KEY&amp;quot;,IrisCaseId=&amp;quot;1&amp;quot;,IrisRootCA='''-----BEGIN CERTIFICATE-----
&amp;lt;...&amp;gt;
-----END CERTIFICATE-----'''),server_metadata() FROM scope()
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The true power of this artifact lies in the ability to quickly add many entries to DFIR-IRIS. You will &lt;em&gt;most likely use this artifact from within a notebook&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There is a basic mechanism established to stop duplicates from being added. An event is compared to existing entries based on asset name, flow id, timestamp and the description. You can add multiple events happening at the same time for the same asset originating from the same flow as long as the description varies, e.g. by including dynamic details of the activity that differentiates between the events at the same time like a process name.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="notebook-usage-example"&gt;Notebook usage example:&lt;/h4&gt;
&lt;pre&gt;&lt;code class="language-VQL"&gt;LET ClientId &amp;lt;= '''C.daa3bab35a125058'''
LET FlowId &amp;lt;= '''F.CPTTPTRO63LF6'''
LET ArtifactName &amp;lt;= '''Windows.Timeline.MFT'''

-- This is the query that should return the events you want to add to Iris.
-- You might want to add a WHERE clause to filter out unwanted events or
-- select only specific fields. In this example we limit it to 10 records.
LET eventsToAdd = SELECT * FROM source(artifact=ArtifactName)
 LIMIT 10

SELECT * FROM foreach(
 row={
 SELECT to_dict(item=_value) AS event,
 serialize(format=&amp;quot;json&amp;quot;, item=_value) AS raw_event
 FROM items(item={ SELECT * FROM eventsToAdd })
 },
 query={
 SELECT *
 FROM Artifact.IRIS.Timeline.Add(
 AdditionalAssetId=&amp;quot;1,2,3&amp;quot;,
 AddToGraph=true,
 AddToSummary=false,
 IocId=&amp;quot;8,9,10&amp;quot;,
 Category=&amp;quot;pers&amp;quot;,
 clientId=ClientId,
 Description=format(
 format=&amp;quot;Malicious file dropped to the system to establish persistence.\nFile path: %v\nActivity: %v&amp;quot;,
 args=[event.path, event.message]),
 RawEvent=raw_event,
 DisableSSLVerify=true,
 FlowId=FlowId,
 Timestamp=event.event_time,
 Title=&amp;quot;Persistence established via Autostart Location&amp;quot;)
 },
 async=false)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ATTENTION: ALWAYS USE ASYNC=FALSE OTHERWISE ANY ASSETS THAT NEED TO BE CREATED MIGHT BE DUPLICATED!!!&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: IRIS.Timeline.Add

author: Stephan Mikiss @stephmikiss (SEC Defence @SEC Consult) | Updated 2024-08 - [10root Cyber Security] (https://10root.com)

description: |
 Adds Velociraptor rows as timeline entries to [DFIR-IRIS](https://dfir-iris.org/).

 Links the assets and IOCs as specified in the parameters. Additionally, if the client does not yet exist in Iris, this artifact will leverage the **IRIS.Sync.Asset** artifact to add the asset to Iris first and link it in the event.

 *Tested with Dfir-Iris API v2.0.4 (IRIS v2.4.7)*

 #### Notes:

 - The following parameters are *mandatory*:
 1. **Timestamp**: This specifies the name of the field in the source containing the event timestamp. For this artifact to parse it correctly the field should contain a parsed timestamp object. If you are using this artifact from a global notebook then the field is probably already parsed. If not then you should ensure that it is parsed in your source using the `timestamp` function.
 2. **Title**: This specifies the name of the field in the source containing the event title which will be used on the Iris timeline.

 #### Hints:

 - It is **recommended** to add the parameters with 'Iris' prefix to the &amp;lt;a href="#/host/server"&amp;gt;Server Metadata&amp;lt;/a&amp;gt; to ease the usage of the artifact. The metadata can alternatively be set from a notebook using VQL similar to this example:

 ```
 SELECT server_set_metadata(IrisURL="https://dfir-iris.local:4433",IrisKey="This-is-an_API_KEY",IrisCaseId="1",IrisRootCA='''-----BEGIN CERTIFICATE-----
 &amp;lt;...&amp;gt;
 -----END CERTIFICATE-----'''),server_metadata() FROM scope()
 ```

 - The true power of this artifact lies in the ability to quickly add many entries to DFIR-IRIS. You will *most likely use this artifact from within a notebook*.
 - There is a basic mechanism established to stop duplicates from being added. An event is compared to existing entries based on asset name, flow id, timestamp and the description. You can add multiple events happening at the same time for the same asset originating from the same flow as long as the description varies, e.g. by including dynamic details of the activity that differentiates between the events at the same time like a process name.

 #### Notebook usage example:

 ```VQL
 LET ClientId &amp;lt;= '''C.daa3bab35a125058'''
 LET FlowId &amp;lt;= '''F.CPTTPTRO63LF6'''
 LET ArtifactName &amp;lt;= '''Windows.Timeline.MFT'''

 -- This is the query that should return the events you want to add to Iris.
 -- You might want to add a WHERE clause to filter out unwanted events or
 -- select only specific fields. In this example we limit it to 10 records.
 LET eventsToAdd = SELECT * FROM source(artifact=ArtifactName)
 LIMIT 10

 SELECT * FROM foreach(
 row={
 SELECT to_dict(item=_value) AS event,
 serialize(format="json", item=_value) AS raw_event
 FROM items(item={ SELECT * FROM eventsToAdd })
 },
 query={
 SELECT *
 FROM Artifact.IRIS.Timeline.Add(
 AdditionalAssetId="1,2,3",
 AddToGraph=true,
 AddToSummary=false,
 IocId="8,9,10",
 Category="pers",
 clientId=ClientId,
 Description=format(
 format="Malicious file dropped to the system to establish persistence.\nFile path: %v\nActivity: %v",
 args=[event.path, event.message]),
 RawEvent=raw_event,
 DisableSSLVerify=true,
 FlowId=FlowId,
 Timestamp=event.event_time,
 Title="Persistence established via Autostart Location")
 },
 async=false)
 ```
 **ATTENTION: ALWAYS USE ASYNC=FALSE OTHERWISE ANY ASSETS THAT NEED TO BE CREATED MIGHT BE DUPLICATED!!!**

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: SERVER

parameters:
 - name: clientId
 description: Client Id of the client that should be synced to DFIR-IRIS
 - name: AdditionalAssetId
 description: Comma seperated list of IRIS AssetIds of additional assets beside the client to link in this event.
 - name: IocId
 description: Comma seperated list of IRIS IocIds to link IOCs in this event.
 - name: Timestamp
 description: Timestamp of the event as a time.Time object. This can be a field in the source data containing a timestamp object.
 - name: Title
 description: Title of the event.
 - name: FlowId
 description: FlowId or HuntId of the event source. This is needed to allow detection of duplicates!
 - name: Tags
 description: List of comma seperated tags to be added to the event.
 - name: Description
 description: Description of the event. Very important to actually understand what this entry is all about :)
 - name: AddToSummary
 description: Add it to timeline summary?
 type: bool
 - name: AddToGraph
 description: Add it to attack graph?
 type: bool
 - name: Category
 description: "Category of the action, mostly MITRE Enterprise Tactics. Allowed options are abbreviations and their MITRE ID: tbd,legit,rem,ini,exec,pers,priv,def,creds,disc,lat,coll,c2,exfil,imp"
 type: choices
 choices:
 - tbd
 - legit
 - rem
 - ini
 - exec
 - pers
 - priv
 - def
 - creds
 - disc
 - lat
 - coll
 - c2
 - exfil
 - imp
 - name: Color
 description: Specify the color for this event in Iris. Green by default for obvious reasons.
 type: choices
 choices:
 - green
 - white
 - blue
 - lightblue
 - purple
 - red
 - orange
 - name: RawEvent
 description: Add the raw event, message or the entire row as additional information.
 - name: IrisURL
 type: server_metadata
 description: URL of DFIR-IRIS. Preferred method is to use the server metadata
 - name: IrisKey
 type: server_metadata
 description: API Key of DFIR-IRIS. Preferred method is to use the server metadata
 - name: IrisCaseId
 type: server_metadata
 description: Case ID of the current case. Preferred method is to use the server metadata
 - name: IrisRootCA
 type: server_metadata
 description: RootCA of DFIR-IRIS for self-signed or internal certificates of DFIR-IRIS. Preferred over completely skipping SSL verification.
 - name: DisableSSLVerify
 type: bool
 default: false
 description: Disable TLS verification for HTTPS request to DFIR-IRIS.

sources:

 - query: |

 LET metadata_preparation = SELECT client_metadata(client_id=clientId) as metadata
 FROM scope() WHERE metadata.IRIS_AssetId

 LET syncAsset = SELECT * FROM Artifact.IRIS.Sync.Asset(
 clientId=clientId,
 IrisURL=IrisURL,
 IrisCaseId=IrisCaseId,
 IrisKey=IrisKey,
 IrisRootCA=IrisRootCA,
 DisableSSLVerify=DisableSSLVerify)

 LET eventAsset1 = if(
 condition=metadata_preparation,
 then=array(a=metadata_preparation.metadata[0].IRIS_AssetId),
 else=if(condition=syncAsset.Result[0]="SUCCESS",
 then=array(a=metadata_preparation.metadata[0].IRIS_AssetId),else=[]))

 LET eventAsset2 = if(condition=AdditionalAssetId,then=split(string=AdditionalAssetId,sep=",|;"),else=[])

 LET eventCategory = if(condition=Category=~"^legit",then=2,
 else= if(condition=Category=~"^rem",then=3,
 else= if(condition=Category=~"^ini|^ta0001$",then=4,
 else= if(condition=Category=~"^exec|^ta0002$",then=5,
 else= if(condition=Category=~"^pers|^ta0003$",then=6,
 else= if(condition=Category=~"^priv|^ta0004$",then=7,
 else= if(condition=Category=~"^def|^ta0005$",then=8,
 else= if(condition=Category=~"^cred|^ta0006$",then=9,
 else= if(condition=Category=~"^disc|^ta0007$",then=10,
 else= if(condition=Category=~"^lat|^ta0008$",then=11,
 else= if(condition=Category=~"^coll|^ta0009$",then=12,
 else= if(condition=Category=~"^c2|^com|^ta0011$",then=13,
 else= if(condition=Category=~"^exf|^ta0010$",then=14,
 else= if(condition=Category=~"^imp|^ta0040$",then=15,
 else= 1))))))))))))))

 LET eventColor = if(condition=Color =~ "^white",then="#fff",
 else = if(condition=Color =~ "^blue",then="#1572E899",
 else = if(condition=Color =~ "^purple",then="#6861CE99",
 else = if(condition=Color =~ "^lightblue",then="#48ABF799",
 else = if(condition=Color =~ "^red",then="#F2596199",
 else = if(condition=Color =~ "^orange",then="#FFAD4699",
 else = "#31CE3699"))))))

 LET eventDate = format(format="%d-%02d-%02dT%02d:%02d:%02d.%03.f", args=[
 Timestamp.Year, Timestamp.Month, Timestamp.Day,
 Timestamp.Hour, Timestamp.Minute, Timestamp.Second,
 Timestamp.Nanosecond / 1000000
 ])

 LET eventProperties = serialize(
 item=dict(
 event_title=Title,
 event_source=if(condition=FlowId,then=format(format="Velo: %v",args=[FlowId]),else="Velo"),
 event_assets=if(condition=eventAsset1 OR eventAsset2,then=eventAsset1 + eventAsset2,else=[]),
 event_iocs=if(condition=IocId,then=split(string=IocId,sep=",|;"),else=[]),
 event_tags=if(condition=Tags,then=format(format="Velo,%v",args=[Tags]),else="Velo"),
 event_category_id=eventCategory,
 event_in_summary=AddToSummary,
 event_in_graph=AddToGraph,
 event_color=eventColor,
 event_date=eventDate,
 event_tz="+00:00",
 event_content=Description,
 event_raw=RawEvent
 )
 ,format="json"
 )

 LET apiRequestIrisAddEvent =
 SELECT *
 FROM http_client(
 data=eventProperties,
 headers=dict(`Content-Type`="application/json", `Authorization`=format(format="Bearer %v", args=[IrisKey])),
 skip_verify=DisableSSLVerify,
 root_ca=IrisRootCA,
 method="POST",
 url=format(format="%v/case/timeline/events/add?cid=%v", args=[IrisURL,IrisCaseId]))

 LET resolveHostname = SELECT os_info.hostname as hostname from clients(client_id=clientId)

 LET filterParams = dict(cid=IrisCaseId,q=format(format='{"asset":["%v"],"source":["%v"],"startDate":["%v"],"endDate":["%v"]}',args=[resolveHostname.hostname[0],FlowId,eventDate,eventDate]))

 LET checkExistingEntries =
 SELECT * FROM flatten(query={ SELECT parse_json(data=Content).data.timeline as Timeline
 FROM http_client(
 headers=dict(`Content-Type`="application/json", `Authorization`=format(format="Bearer %v", args=[IrisKey])),
 method="GET",
 root_ca=IrisRootCA,
 skip_verify=DisableSSLVerify,
 params=filterParams,
 url=format(format="%v/case/timeline/advanced-filter", args=[IrisURL])) GROUP BY Timeline })
 WHERE base64encode(string=Timeline.event_content) = base64encode(string=Description)

 SELECT * FROM if(condition=checkExistingEntries,
 then={SELECT "Already Added -&amp;gt; Skipping the event. Check for existing entries manually!" as Action FROM scope()},
 else={SELECT "Needs to be added" as Action, if(condition= Response=200,then="SUCCESS",else="ERROR") as Result,
 parse_json(data=eventProperties) AS _RequestData, parse_json(data=Content).data as _ResponseData
 FROM apiRequestIrisAddEvent})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Label.DomainController</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/label.domaincontroller/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/label.domaincontroller/</guid><description>&lt;p&gt;This artifact watches for completion of the &lt;code&gt;watchArtifact&lt;/code&gt;
and assigns the given &lt;code&gt;setLabel&lt;/code&gt; if the &lt;code&gt;WHERE&lt;/code&gt; condition is matched.&lt;/p&gt;
&lt;p&gt;Anytime the &lt;code&gt;Windows.System.Services&lt;/code&gt; hunt is run across the environment,
results will be interpreted by this server-side artifact.&lt;/p&gt;
&lt;p&gt;In this configuration, it will match on all systems running
&amp;ldquo;Active Directory Domain Services&amp;rdquo; which likely indicates the system
is a Domain Controller and will label it as such.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Label.DomainController
author: Eric Capuano - @eric_capuano
description: |
 This artifact watches for completion of the `watchArtifact`
 and assigns the given `setLabel` if the `WHERE` condition is matched.
 
 Anytime the `Windows.System.Services` hunt is run across the environment,
 results will be interpreted by this server-side artifact.
 
 In this configuration, it will match on all systems running 
 "Active Directory Domain Services" which likely indicates the system
 is a Domain Controller and will label it as such.

type: SERVER_EVENT

parameters:
 - name: setLabel
 default: dc
 - name: watchArtifact
 default: Windows.System.Services

sources:
 - query: |
 
 LET completions = SELECT *
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ watchArtifact

 LET matches = SELECT *, 
 label(client_id=ClientId, labels=setLabel, op="set")
 FROM source(artifact=watchArtifact,
 client_id=ClientId, flow_id=FlowId)
 WHERE Name = "NTDS" AND DisplayName = "Active Directory Domain Services"
 

 SELECT * FROM foreach(row=completions, query=matches)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Applications.Docker.Ps</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.applications.docker.ps/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.applications.docker.ps/</guid><description>&lt;p&gt;Get Docker containers by connecting to the docker.socket. Same as running &lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Applications.Docker.Ps
author: Ján Trenčanský - j91321@infosec.exchange
description: Get Docker containers by connecting to the docker.socket. Same as running `docker ps`
reference:
 - https://docs.docker.com/engine/api/v1.45/#tag/Container/operation/ContainerList

parameters:
 - name: dockerSocket
 description: |
 Docker server socket. You will normally need to be root to connect.
 default: /var/run/docker.sock
 - name: all
 description: |
 Show non-running containers. Equals to `docker ps -a`.
 type: bool
 default: N
sources:
 - precondition: |
 SELECT OS From info() where OS = 'linux'
 query: |
 LET running_containers = SELECT parse_json_array(data=Content) as JSON FROM http_client(url=dockerSocket + ":unix/containers/json")
 LET all_containers = SELECT parse_json_array(data=Content) as JSON FROM http_client(url=dockerSocket + ":unix/containers/json", params=dict(all=True))
 SELECT * FROM foreach(
 row={
 SELECT * FROM if(
 condition=all,
 then=all_containers,
 else=running_containers
 )
 },
 query={
 SELECT * FROM JSON
 }
 )
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Applications.WgetHSTS</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.applications.wgethsts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.applications.wgethsts/</guid><description>&lt;p&gt;Wget creates a HSTS log file in a user&amp;rsquo;s home directory. This can
contain forensically relevant information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Applications.WgetHSTS
description: |
 Wget creates a HSTS log file in a user's home directory. This can
 contain forensically relevant information.

reference:
- https://firexfly.com/wget-hsts/

parameters:
 - name: HSTSGlob
 default: "/home/*/.wget-hsts"

sources:
 - query: |
 SELECT Parsed.g1 AS Domain ,
 int(int=Parsed.g2) || 443 AS Port,
 Parsed.g3 AS IncSubdomains,
 timestamp(epoch=Parsed.g4) AS Created,
 int(int=Parsed.g5) AS MaxAge
 FROM foreach(row={
 SELECT FullPath FROM glob(globs="/home/*/.wget-hsts")
 }, query={
 SELECT Line, parse_string_with_regex(string=Line,
 regex='''^([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)'''
 ) AS Parsed
 FROM parse_lines(filename=FullPath)
 WHERE NOT Line =~ "^#"
 })

column_types:
 - name: Created
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Carving.SSHLogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.carving.sshlogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.carving.sshlogs/</guid><description>&lt;p&gt;Linux systems typically store audit events in syslog. In particular successful
ssh logins are especially important for some investigations.&lt;/p&gt;
&lt;p&gt;Unfortunately they are sometimes deleted by attackers or rotated out. If you
are desperate it might be worth trying to carve for ssh login events.&lt;/p&gt;
&lt;h3 id="notes"&gt;NOTES&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Syslog does not typically store the year in the date - since carving can
recover very old records it might be difficult to pinpoint the time.&lt;/li&gt;
&lt;li&gt;This artifact will take a long time! You probably will have to increase
the timeout.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Carving.SSHLogs
description: |
 Linux systems typically store audit events in syslog. In particular successful 
 ssh logins are especially important for some investigations.
 
 Unfortunately they are sometimes deleted by attackers or rotated out. If you 
 are desperate it might be worth trying to carve for ssh login events.
 
 ### NOTES
 
 1. Syslog does not typically store the year in the date - since carving can 
 recover very old records it might be difficult to pinpoint the time.
 2. This artifact will take a long time! You probably will have to increase 
 the timeout. 
 
parameters:
 - name: Device
 default: /dev/root

sources:
 - query: |
 LET GrokRule = '''%{SYSLOGTIMESTAMP:Timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: %{DATA:event} %{DATA:method} for (invalid user )?%{DATA:user} from %{IPORHOST:ip} port %{NUMBER:port} ssh2(: %{GREEDYDATA:system.auth.ssh.signature})?'''
 LET YaraRule = '''
 rule X {
 strings:
 $a = /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{1,2} [0-9]{2}:[0-9]{2}[^\n]+/s
 condition:
 any of them
 }
 '''
 
 LET Hits = SELECT str(str=String.Data) AS Hit, String.Offset AS Offset
 FROM yara(
 files=Device, accessor="raw_file", end=1024*1024*1024*56,
 rules=YaraRule, number=100000000000)
 WHERE Hit =~ "Accept|Failed"
 
 SELECT * FROM foreach(row={
 SELECT grok(data=Hit, grok=GrokRule) AS Event, Offset
 FROM Hits
 WHERE Event
 }, query={
 SELECT Offset, timestamp(string=Event.Timestamp) AS Time,
 Event.ip AS IP,
 Event.logsource AS logsource,
 Event.event AS Result,
 Event.method AS Method,
 Event.user AS AttemptedUser
 FROM scope()
 })


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.Autoruns</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.autoruns/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.autoruns/</guid><description>&lt;p&gt;This artifact collects various autorun files for upload.
Based on TriagePersistence from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.Autoruns
author: alternate
description: |
 This artifact collects various autorun files for upload.
 Based on TriagePersistence from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: AnacronFiles
 default: |
 ["/etc/anacrontab,/etc/cron.daily/*","/etc/cron.hourly/*","/etc/cron.monthly/*",
 "/etc/cron.weekly/*","/var/spool/anacron/cron.daily","/var/spool/anacron/cron.hourly", 
 "/var/spool/anacron/cron.monthly","/var/spool/anacron/cron.weekly"]

- name: LinuxAtJobs
 default: /var/spool/at/*

- name: LinuxCronTabs
 default: |
 ["/etc/crontab","/etc/cron.d/*","/var/spool/cron"]

- name: LinuxSystemdServices
 default: |
 ["/etc/systemd/system.control/*.service","/etc/systemd/systemd.attached/*.service",
 "/etc/systemd/system/*.service","/etc/systemd/user/*.service",
 "/lib/systemd/system/*.service","/lib/systemd/user/*.service",
 "/run/systemd/generator.early/*.service","/run/systemd/generator.late/*.service",
 "/run/systemd/generator/*.service","/run/systemd/system.control/*.service",
 "/run/systemd/systemd.attached/*.service","/run/systemd/system/*.service",
 "/run/systemd/transient/*.service","/run/systemd/user/*.service",
 "/run/user/*/systemd/generator.early/*.service","/run/user/*/systemd/generator.late/*.service",
 "/run/user/*/systemd/generator/*.service","/run/user/*/systemd/transient/*.service",
 "/run/user/*/systemd/user.control/*.service","/run/user/*/systemd/user/*.service",
 "/usr/lib/systemd/system/*.service","/usr/lib/systemd/user/*.service",
 "/{root,home/*}/.config/systemd/user.control/*.service","/{root,home/*}/.config/systemd/user/*.service",
 "/{root,home/*}/.local/share/systemd/user/*.service"]

- name: LinuxSystemdTimers
 default: |
 ["/etc/systemd/system.control/*.timer","/etc/systemd/systemd.attached/*.timer",
 "/etc/systemd/system/*.timer","/etc/systemd/user/*.timer","/lib/systemd/system/*.timer",
 "/lib/systemd/user/*.timer","/run/systemd/generator.early/*.timer",
 "/run/systemd/generator.late/*.timer","/run/systemd/generator/*.timer",
 "/run/systemd/system.control/*.timer","/run/systemd/systemd.attached/*.timer",
 "/run/systemd/system/*.timer,/run/systemd/transient/*.timer","/run/systemd/user/*.timer",
 "/run/user/*/systemd/generator.early/*.timer","/run/user/*/systemd/generator.late/*.timer",
 "/run/user/*/systemd/generator/*.timer","/run/user/*/systemd/transient/*.timer",
 "/run/user/*/systemd/user.control/*.timer","/run/user/*/systemd/user/*.timer",
 "/usr/lib/systemd/system/*.timer","/usr/lib/systemd/user/*.timer",
 "/{root,home/*}/.config/systemd/user.control/*.timer",
 "/{root,home/*}/.config/systemd/user/*.timer",
 "/{root,home/*}/.local/share/systemd/user/*.timer"]

- name: LinuxSysVInit
 default: |
 ["/etc/rc.local","/etc/rc*.d","/etc/rc*.d/*","/etc/rc.d/rc*.d/*","/etc/rc.d/init.d/*"] 

- name: XDGAutostartEntries
 default: |
 ["/etc/rc.local","/etc/rc*.d","/etc/rc*.d/*","/etc/rc.d/rc*.d/*","/etc/rc.d/init.d/*"]

sources:
- name: uploadAnacronFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=AnacronFiles))

- name: uploadLinuxAtJobs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxAtJobs)

- name: uploadLinuxSystemdServices
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSystemdServices))

- name: uploadLinuxSystemdTimers
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSystemdTimers))

- name: uploadLinuxSysVInit
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSysVInit))

- name: uploadXDGAutostartEntries
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=XDGAutostartEntries))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.BrowserExtensions</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.browserextensions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.browserextensions/</guid><description>&lt;p&gt;Collect Browser Extensions and upload them.
Based on TriageWebBrowserExtensions from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.BrowserExtensions
author: alternate
description: |
 Collect Browser Extensions and upload them.
 Based on TriageWebBrowserExtensions from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: ChromiumBasedBrowsersExtensions
 default: |
 ["/{root,home/*}/.config/google-chrome/*/Extensions/**10",
 "/{root,home/*}/.config/yandex-browser-beta/*/Extensions/**10",
 "/{root,home/*}/.config/chromium/*/Extensions/**10",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Extensions/**10",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/Extensions/**10",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Extensions/**10",
 "/{root,home/*}/.config/opera/*/Extensions/**10",
 "/{root,home/*}/.config/google-chrome-beta/*/Extensions/**10",
 "/{root,home/*}/snap/chromium/common/chromium/*/Extensions/**10"]

- name: ChromiumBasedBrowsersExtensionActivitySQLiteDatabaseFile
 default: |
 ["/{root,home/*}/.config/google-chrome-beta/*/Extension Activity",
 "/{root,home/*}/.config/google-chrome/*/Extension Activity",
 "/{root,home/*}/.config/yandex-browser-beta/*/Extension Activity",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/Extension Activity",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Extension Activity",
 "/{root,home/*}/.config/opera/*/Extension Activity",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Extension Activity",
 "/{root,home/*}/.config/chromium/*/Extension Activity",
 "/{root,home/*}/snap/chromium/common/chromium/*/Extension Activity"]

- name: ChromePreferences
 default: |
 ["/{root,home/*}/.config/chromium/*/Secure Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Secure Preferences",
 "/{root,home/*}/.config/google-chrome/*/Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Secure Preferences",
 "/{root,home/*}/.config/google-chrome/*/Secure Preferences",
 "/{root,home/*}/.config/chromium/*/Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Preferences"]

- name: FirefoxAddOns
 default: |
 ["/{root,home/*}/.mozilla/firefox/*/webapps/webapps.json",
 "/{root,home/*}/.mozilla/firefox/*/addons.json",
 "/{root,home/*}/.mozilla/firefox/*/extensions.json"]

sources:
- name: uploadChromiumBasedBrowsersExtensions
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ChromiumBasedBrowsersExtensions))


- name: uploadChromiumBasedBrowsersExtensionActivitySQLiteDatabaseFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ChromiumBasedBrowsersExtensionActivitySQLiteDatabaseFile))

- name: uploadChromePreferences
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ChromePreferences))

- name: uploadFirefoxAddOns
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=FirefoxAddOns))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.BrowserHistory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.browserhistory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.browserhistory/</guid><description>&lt;p&gt;Collect Browser History and upload them.
Based on TriageWebBrowserHistory from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.BrowserHistory
author: alternate
description: |
 Collect Browser History and upload them.
 Based on TriageWebBrowserHistory from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml
 
precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: ChromiumBasedBrowsersHistory
 default: |
 ["/{root,home/*}/.config/chromium/*/Archived History", 
 "/{root,home/*}/snap/chromium/common/chromium/*/History-journal", 
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/History",
 "/{root,home/*}/snap/chromium/common/chromium/*/Archived History",
 "/{root,home/*}/.config/opera/*/Archived History",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/Archived History-journal",
 "/{root,home/*}/.config/chromium/*/Archived History-journal",
 "/{root,home/*}/snap/chromium/common/chromium/*/Archived History-journal",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Archived History",
 "/{root,home/*}/.config/opera/*/Archived History-journal",
 "/{root,home/*}/.config/yandex-browser-beta/*/Archived History",
 "/{root,home/*}/snap/chromium/common/chromium/*/History", 
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/History-journal",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/History",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/Archived History",
 "/{root,home/*}/.config/opera/*/History",
 "/{root,home/*}/.config/opera/*/History-journal",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Archived History-journal",
 "/{root,home/*}/.config/google-chrome-beta/*/Archived History",
 "/{root,home/*}/.config/google-chrome-beta/*/History",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Archived History",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/History",
 "/{root,home/*}/.config/google-chrome/*/Archived History-journal",
 "/{root,home/*}/.config/google-chrome/*/History",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/History-journal",
 "/{root,home/*}/.config/google-chrome/*/History-journal",
 "/{root,home/*}/.config/yandex-browser-beta/*/Archived History-journal",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Archived History-journal",
 "/{root,home/*}/.config/google-chrome/*/Archived History",
 "/{root,home/*}/.config/google-chrome-beta/*/History-journal",
 "/{root,home/*}/.config/google-chrome-beta/*/Archived History-journal",
 "/{root,home/*}/.config/yandex-browser-beta/*/History",
 "/{root,home/*}/.config/chromium/*/History",
 "/{root,home/*}/.config/yandex-browser-beta/*/History-journal",
 "/{root,home/*}/.config/BraveSoftware/Brave-Browser/*/History-journal",
 "/{root,home/*}/.config/chromium/*/History-journal"]

- name: FirefoxHistory
 default: |
 ["/{root,home/*}/.mozilla/firefox/*/places.sqlite-wal",
 "/{root,home/*}/.mozilla/firefox/*/places.sqlite"]

- name: OperaHistoryFile
 default: |
 ["/{root,home/*}/.opera/global_history.dat"]

sources:
- name: uploadChromiumBasedBrowsersHistory
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ChromiumBasedBrowsersHistory))

- name: uploadFirefoxHistory
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=FirefoxHistory))

- name: uploadOperaHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=OperaHistoryFile))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.CatScale</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.catscale/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.catscale/</guid><description>&lt;p&gt;This is a simple artifact that leverages Cat-Scale to collect many
different artifacts from a Linux host, then uploads the results to
the Velociraptor server.&lt;/p&gt;
&lt;p&gt;From the project&amp;rsquo;s description:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Linux CatScale is a bash script that uses live of the land tools
to collect extensive data from Linux based hosts. The data aims to
help DFIR professionals triage and scope incidents. An Elk Stack
instance also is configured to consume the output and assist the
analysis process.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FSecureLABS/LinuxCatScale" target="_blank" &gt;https://github.com/FSecureLABS/LinuxCatScale&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://labs.f-secure.com/tools/cat-scale-linux-incident-response-collection/" target="_blank" &gt;https://labs.f-secure.com/tools/cat-scale-linux-incident-response-collection/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.CatScale
author: Wes Lambert -- @therealwlambert
description: |
 This is a simple artifact that leverages Cat-Scale to collect many
 different artifacts from a Linux host, then uploads the results to
 the Velociraptor server.

 From the project's description:

 "Linux CatScale is a bash script that uses live of the land tools
 to collect extensive data from Linux based hosts. The data aims to
 help DFIR professionals triage and scope incidents. An Elk Stack
 instance also is configured to consume the output and assist the
 analysis process."

 https://github.com/FSecureLABS/LinuxCatScale

 https://labs.f-secure.com/tools/cat-scale-linux-incident-response-collection/

tools:
 - name: CatScale
 url: https://raw.githubusercontent.com/FSecureLABS/LinuxCatScale/master/Cat-Scale.sh
 serve_locally: true
parameters:
 - name: Outfile
 default: collection
 type: string
 description: Name of resultant collection file (will have `.tar.gz` appended)
 - name: OutfilePrefix
 default: catscale_
 type: string
 description: Prefix of collection file (Ex. catscale_ -- useful for parsing the filename later or other identification purposes)
 - name: OutDir
 default: catscale_out
 type: string
 description: Staging directory (modification likely not needed in most cases)
precondition: SELECT OS From info() where OS = 'linux'
sources:
 - query: |
 LET CS &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="CatScale", IsExecutable=TRUE)
 LET TmpDir &amp;lt;= tempdir(remove_last=TRUE)
 Let RunIt = SELECT *, TmpDir + '/' + OutfilePrefix + Outfile + '.tar.gz' AS TarFile
 FROM execve(argv=[
 CS.FullPath[0],
 "-d", OutDir,
 "-o", TmpDir,
 "-f", Outfile,
 "-p", OutfilePrefix
 ])
 SELECT upload(accessor="file", file=TarFile) AS Upload FROM RunIt

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.DBConfig</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.dbconfig/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.dbconfig/</guid><description>&lt;p&gt;Collect database configurations and upload them.
Based on TriageDatabaseConfigsAndLogs from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.DBConfig
author: alternate
description: |
 Collect database configurations and upload them.
 Based on TriageDatabaseConfigsAndLogs from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = "linux"

parameters:
- name: MongoDBConfigurationFile
 default: |
 ["/usr/local/etc/mongod.conf", "/opt/homebrew/etc/mongod.conf", "/etc/mongod.conf"]

- name: MongoDBLogFiles
 default: /var/log/mongodb/mongod.log*

- name: MySQLConfigurationFiles
 default: |
 ["/etc/my.cnf", "/etc/mysql/mysql.conf.d/mysqld.cnf"]

- name: MySQLLogFiles
 default: |
 ["/var/log/mysql.log*", "/var/log/mysql/error.log*"]

- name: OpenSearchLogFiles
 default: |
 ["/var/log/opensearch/*.json", "/var/log/opensearch/*.log"]

- name: PostgreSQLConfigurationFiles
 default: |
 ["/etc/postgresql/*/*/pg_ident.conf", "/var/lib/pgsql/pg_hba.conf", "/var/lib/pgsql/data/pg_ident.conf", 
 "/etc/postgresql/*/*/postgresql.conf", "/var/lib/pgsql/pg_ident.conf", "/var/lib/pgsql/data/postgresql.conf", 
 "/etc/postgresql/*/*/pg_hba.conf", "/var/lib/pgsql/data/pg_hba.conf", "/var/lib/pgsql/postgresql.conf"]

- name: PostgreSQLLogFiles
 default: |
 ["/var/log/postgresql/postgresql-*.log*", "/var/lib/pgsql/data/log/postgresql.csv*",
 "/var/log/postgresql/postgresql.csv*", "/var/log/postgresql/postgresql-*-*.csv*",
 "/var/log/postgresql/postgresql-*-*.log*", "/var/lib/pgsql/data/log/postgresql-*-*.csv*",
 "/var/log/postgresql/postgresql-*.csv*", "/var/lib/pgsql/data/log/postgresql-*-*.log*",
 "/var/lib/pgsql/data/log/postgresql-*.csv*", "/var/log/postgresql/postgresql.log*",
 "/var/lib/pgsql/data/log/postgresql.log*", "/var/lib/pgsql/data/log/postgresql-*.log*"]

- name: RedisConfigFile
 default: |
 ["/etc/redis/redis.conf", "/private/etc/redis/redis.conf"]

- name: RedisConfigurationFile
 default: |
 ["/etc/init.d/redis_*", "/etc/redis/*"]

- name: RedisLogFiles
 default: |
 ["/var/log/redis/redis*.log*", "/var/log/redis*.log*"]

sources:
- name: uploadMongoDBConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=MongoDBConfigurationFile))

- name: uploadMongoDBLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=MongoDBLogFiles)

- name: uploadMySQLConfigurationFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=MySQLConfigurationFiles))

- name: uploadMySQLLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=MySQLLogFiles))

- name: uploadOpenSearchLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=OpenSearchLogFiles))

- name: uploadPostgreSQLConfigurationFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=PostgreSQLConfigurationFiles))

- name: uploadPostgreSQLLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=PostgreSQLLogFiles))

- name: uploadRedisConfigFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=RedisConfigFile))

- name: uploadRedisConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=RedisConfigurationFile))

- name: uploadRedisLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=RedisLogFiles))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.History</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.historyfiles/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.historyfiles/</guid><description>&lt;p&gt;Collect history files from unix/linux utilities and upload them.
Based on TriageHistory from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.History
author: alternate
description: |
 Collect history files from unix/linux utilities and upload them.
 Based on TriageHistory from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: BashShellHistoryFile
 default: |
 ["/{root,home/*}/.bash_logout","/{root,home/*}/.bash_profile",
 "/{root,home/*}/.bashrc","/etc/bash.bashrc","/etc/bashrc"]

- name: BourneShellHistoryFile
 default: /{root,home/*}/.sh_history

- name: FishShellHistoryFile
 default: /{root,home/*}/.local/share/fish/fish_history

- name: MySQLHistoryFile
 default: /{root,home/*}/.mysql_history

- name: PostgreSQLHistoryFile
 default: |
 ["/var/lib/postgresql/.psql_history","/var/lib/pgsql/.psql_history","/{root,home/*}/.psql_history"]

- name: PythonHistoryFile
 default: /{root,home/*}/.python_history

- name: SQLiteHistoryFile 
 default: /{root,home/*}/.sqlite_history

- name: ZShellHistoryFile
 default: |
 ["/{root,home/*}/.zhistory","/{root,home/*}/.zsh_history"]

- name: LessHistoryFile
 default: /{root,home/*}/.lesshst

- name: NanoHistoryFile
 default: /{root,home/*}/.nano_history

sources:
- name: uploadBashShellHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=BashShellHistoryFile))

- name: uploadBourneShellHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=BourneShellHistoryFile)

- name: uploadFishShellHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=FishShellHistoryFile)

- name: uploadMySQLHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=MySQLHistoryFile)

- name: uploadPostgreSQLHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=PostgreSQLHistoryFile))

- name: uploadPythonHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=PythonHistoryFile)

- name: uploadSQLiteHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=SQLiteHistoryFile)

- name: uploadZShellHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ZShellHistoryFile))

- name: uploadLessHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LessHistoryFile)

- name: uploadNanoHistoryFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=NanoHistoryFile)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.NetworkConfig</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.networkconfig/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.networkconfig/</guid><description>&lt;p&gt;Collect network config files and upload them.
Based on TriageNetwork from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.NetworkConfig
author: alternate
description: |
 Collect network config files and upload them.
 Based on TriageNetwork from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: DNSResolvConfFile
 default: /etc/resolv.conf

- name: HostAccessPolicyConfiguration
 default: |
 ["/etc/hosts.allow","/etc/hosts.deny"]

- name: LinuxHostnameFile
 default: /etc/hostname

- name: LinuxIgnoreICMPBroadcasts
 default: /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

- name: LinuxNetworkIpForwardingState
 default: |
 ["/proc/sys/net/ipv*/conf/*/forwarding","/proc/sys/net/ipv4/conf/*/mc_forwarding",
 "/proc/sys/net/ipv4/ip_forward"]

- name: LinuxNetworkPathFilteringSettings
 default: |
 ["/proc/sys/net/ipv*/conf/*/accept_source_route","/proc/sys/net/ipv4/conf/*/rp_filter",
 "/proc/sys/net/ipv4/conf/*/log_martians"]

- name: LinuxNetworkRedirectState 
 default: |
 ["/proc/sys/net/ipv*/conf/*/accept_redirects","/proc/sys/net/ipv4/conf/*/secure_redirects",
 "/proc/sys/net/ipv4/conf/*/send_redirects"]

- name: LinuxProcArp
 default: /proc/net/arp

- name: LinuxSyncookieState
 default: /proc/sys/net/ipv4/tcp_syncookies

- name: UFWConfigFiles
 default: |
 ["/etc/default/ufw","/etc/ufw/sysctl.conf","/etc/ufw/*.rules","/etc/ufw/applications.d/*"]

- name: IPTablesConfigFiles
 default: |
 ["/etc/sysconfig/iptables*","/etc/sysconfig/ip6tables*"]

- name: UnixHostsFile
 default: /etc/hosts

sources:
- name: uploadDNSResolvConfFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=DNSResolvConfFile)

- name: uploadHostAccessPolicyConfiguration
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=HostAccessPolicyConfiguration))

- name: uploadLinuxHostnameFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxHostnameFile)
 
- name: uploadLinuxIgnoreICMPBroadcasts
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxIgnoreICMPBroadcasts)

- name: uploadLinuxNetworkIpForwardingState
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxNetworkIpForwardingState))

- name: uploadLinuxNetworkPathFilteringSettings
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxNetworkPathFilteringSettings))

- name: uploadLinuxNetworkRedirectState
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxNetworkRedirectState))

- name: uploadLinuxProcArp
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxProcArp)

- name: uploadLinuxSyncookieState
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxSyncookieState)

- name: uploadUFWConfigFiles
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UFWConfigFiles))

- name: uploadIPTablesConfigFiles
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=IPTablesConfigFiles))

- name: uploadUnixHostsFile
 query: | 
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=UnixHostsFile)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.SysConfig</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.sysconfig/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.sysconfig/</guid><description>&lt;p&gt;Collect system configurations and upload them.
Based on TriageSystemConfiguration from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.SysConfig 
author: alternate
description: |
 Collect system configurations and upload them.
 Based on TriageSystemConfiguration from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = "linux"

parameters:
- name: APTSources
 default: |
 ["/etc/apt/sources.list", "/etc/apt/sources.list.d/*.list"]

- name: APTTrustKeys
 default: |
 ["/etc/apt/trusted.gpg.d/*.gpg", "/etc/apt/trustdb.gpg", "/usr/share/keyrings/*.gpg", "/etc/apt/trusted.gpg"]

- name: CronAtAllowDenyFiles
 default: |
 ["/etc/at.allow", "/etc/cron.allow", "/etc/cron.deny", "/etc/at.deny"]

- name: DebianPackagesStatus
 default: /var/lib/dpkg/status

- name: DebianVersion
 default: /etc/debian_version

- name: KernelModules
 default: |
 ["/etc/modules.conf", "/etc/modprobe.d/*"]

- name: LinuxCACertificates
 default: |
 ["/usr/local/share/ca-certificates/*", "/etc/ssl/certs/ca-certificates.crt", "/usr/share/ca-certificates/*"]

- name: LinuxASLREnabled
 default: /proc/sys/kernel/randomize_va_space

- name: LinuxDSDTTable
 default: /sys/firmware/acpi/tables/DSDT

- name: LinuxDHCPConfigurationFile
 default: /etc/dhcp/dhcp.conf

- name: LinuxFstab
 default: /etc/fstab

- name: LinuxGrubConfiguration
 default: |
 ["/boot/grub/grub.cfg", "/boot/grub2/grub.cfg"]

- name: LinuxInitrdFiles
 default: |
 ["/boot/initramfs*", "/boot/initrd*"]

- name: LinuxIssueFile
 default: |
 ["/etc/issue.net", "/etc/issue"]

- name: LinuxKernelBootloader
 default: |
 ["/proc/sys/kernel/bootloader_type", "/proc/sys/kernel/bootloader_version"]

- name: LinuxKernelModuleRestrictions
 default: |
 ["/proc/sys/kernel/modules_disabled", "/proc/sys/kernel/kexec_load_disabled"]

- name: LinuxKernelModuleTaintStatus
 default: /proc/sys/kernel/tainted

- name: LinuxLoaderSystemPreloadFile
 default: /etc/ld.so.preload

- name: LinuxLocalTime
 default: /etc/localtime

- name: LinuxLSBInit
 default: |
 ["/etc/init.d/*", "/etc/insserv.conf.d/**", "/etc/insserv.conf"]

- name: LinuxLSBRelease
 default: /etc/lsb-release

- name: LinuxNetworkManager
 default: |
 ["/usr/lib/NetworkManager/conf.d/name.conf", "/run/NetworkManager/conf.d/name.conf", 
 "/var/lib/NetworkManager/*", "/var/lib/NetworkManager/NetworkManager-intern.conf", 
 "/etc/NetworkManager/conf.d/name.conf", "/etc/NetworkManager/NetworkManager.conf"]

- name: LinuxPamConfigs
 default: |
 ["/etc/pam.d/common-password", "/etc/pam.conf", "/etc/pam.d/*"]

- name: LinuxPasswdFile
 default: /etc/passwd

- name: LinuxProcMounts
 default: /proc/mounts

- name: LinuxRelease
 default: |
 ["/etc/enterprise-release", "/etc/system-release", "/etc/oracle-release", "/etc/lsb-release", "/etc/redhat-release"]

- name: LinuxRestrictedDmesgReadPrivileges
 default: /proc/sys/kernel/dmesg_restrict

- name: LinuxRestrictedKernelPointerReadPrivileges
 default: /proc/sys/kernel/kptr_restrict

- name: LinuxRsyslogConfigs
 default: |
 ["/etc/rsyslog.d", "/etc/rsyslog.d/*", "/etc/rsyslog.conf"]

- name: LinuxSecureFsLinks
 default: |
 ["/proc/sys/fs/protected_symlinks", "/proc/sys/fs/protected_hardlinks"]

- name: LinuxSecureSuidCoreDumps
 default: /proc/sys/fs/suid_dumpable

- name: LinuxSSDTTables
 default: /sys/firmware/acpi/tables/SSDT*

- name: LinuxSysctlConfigurationFiles
 default: |
 ["/etc/sysctl.d/*.conf", "/etc/sysctl.con", "/usr/lib/sysctl.d/*.conf", 
 "/run/sysctl.d/*.conf", "/lib/sysctl.d/*.conf", "/usr/local/lib/sysctl.d/*.conf"]

- name: LinuxSyslogNgConfigs
 default: |
 ["/etc/syslog-ng/conf-d/*.conf", "/etc/syslog-ng/syslog-ng.conf"]

- name: LinuxSystemdJournalConfig
 default: /etc/systemd/journald.conf

- name: LinuxSystemdOSRelease
 default: |
 ["/usr/lib/os-release", "/etc/os-release"]

- name: LinuxTimezoneFile
 default: /etc/timezone

- name: LinuxXinetd
 default: |
 ["/etc/xinetd.d/**", "/etc/xinetd.conf"]

- name: LocateDatabase
 default: |
 ["/etc/updatedb.conf", "/var/lib/mlocate/mlocate.db"]

- name: LoginPolicyConfiguration
 default: |
 ["/etc/passwd", "/etc/shadow", "/root/.k5login", "/etc/netgroup", "/etc/nsswitch.conf", "/etc/security/access.conf"]

- name: NetgroupConfiguration
 default: /etc/netgroup

- name: NfsExportsFile
 default: |
 ["/private/etc/exports", "/etc/exports"]

- name: NtpConfFile
 default: /etc/ntp.conf

- name: PCIDevicesInfoFiles
 default: |
 ["/sys/bus/pci/devices/*/config", "/sys/bus/pci/devices/*/vendor", 
 "/sys/bus/pci/devices/*/device", "/sys/bus/pci/devices/*/class"]

- name: SambaConfigFile
 default: /etc/samba/smb.conf

- name: SecretsServiceDatabaseFile
 default: |
 ["/var/lib/sss/secrets/.secrets.mkey", "/var/lib/sss/secrets/secrets.ldb"]

- name: SshdConfigFile
 default: |
 ["/etc/ssh/sshd_config", "/private/etc/ssh/sshd_config"]

- name: SSHHostPubKeys
 default: /etc/ssh/ssh_host_*_key.pub

- name: UnixGroupsFile
 default: |
 ["/etc/group", "/private/etc/group"]

- name: UnixLocalTimeConfigurationFile
 default: |
 ["/private/etc/localtime", "/etc/localtime"]

- name: UnixPasswdFile
 default: |
 ["/private/etc/passwd", "/etc/passwd"]

- name: UnixShadowFile
 default: |
 ["/private/etc/shadow", "/etc/shadow"]

- name: UnixSudoersConfigurationFile
 default: |
 ["/etc/sudoers", "/private/etc/sudoers"]

- name: YumSources
 default: |
 ["/etc/yum.conf", "/etc/yum.repos.d/*.repo"]

sources:
- name: uploadAPTSources
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=APTSources))

- name: uploadAPTTrustKeys
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=APTTrustKeys))

- name: uploadCronAtAllowDenyFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=CronAtAllowDenyFiles))

- name: uploadDebianPackagesStatus
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=DebianPackagesStatus)

- name: uploadDebianVersion
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=DebianVersion)

- name: uploadKernelModules
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=KernelModules))

- name: uploadLinuxASLREnabled
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxASLREnabled)

- name: uploadLinuxCACertificates
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxCACertificates))

- name: uploadLinuxDHCPConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxDHCPConfigurationFile)

- name: uploadLinuxDSDTTable
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxDSDTTable)

- name: uploadLinuxFstab
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxFstab)

- name: uploadLinuxGrubConfiguration
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxGrubConfiguration))

- name: uploadLinuxInitrdFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxInitrdFiles))

- name: uploadLinuxIssueFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxIssueFile))

- name: uploadLinuxKernelBootloader
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxKernelBootloader))

- name: uploadLinuxKernelModuleRestrictions
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxKernelModuleRestrictions))

- name: uploadLinuxKernelModuleTaintStatus
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxKernelModuleTaintStatus)

- name: uploadLinuxLoaderSystemPreloadFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxLoaderSystemPreloadFile)

- name: uploadLinuxLocalTime
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxLocalTime)

- name: uploadLinuxLSBInit
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxLSBInit))

- name: uploadLinuxLSBRelease
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxLSBRelease)

- name: uploadLinuxNetworkManager
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxNetworkManager))

- name: uploadLinuxPamConfigs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxPamConfigs))

- name: uploadLinuxPasswdFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxPasswdFile)

- name: uploadLinuxProcMounts
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxProcMounts)

- name: uploadLinuxRelease
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxRelease))

- name: uploadLinuxRestrictedDmesgReadPrivileges
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxRestrictedDmesgReadPrivileges)

- name: uploadLinuxRestrictedKernelPointerReadPrivileges
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxRestrictedKernelPointerReadPrivileges)

- name: uploadLinuxRsyslogConfigs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxRsyslogConfigs))

- name: uploadLinuxSecureFsLinks
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSecureFsLinks))

- name: uploadLinuxSecureSuidCoreDumps
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxSecureSuidCoreDumps)

- name: uploadLinuxSSDTTables
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxSSDTTables)

- name: uploadLinuxSysctlConfigurationFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSysctlConfigurationFiles))

- name: uploadLinuxSyslogNgConfigs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSyslogNgConfigs))

- name: uploadLinuxSystemdJournalConfig
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxSystemdJournalConfig)

- name: uploadLinuxSystemdOSRelease
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSystemdOSRelease))

- name: uploadLinuxTimezoneFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxTimezoneFile)

- name: uploadLinuxXinetd
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxXinetd))

- name: uploadLocateDatabase
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LocateDatabase))

- name: uploadLoginPolicyConfiguration
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LoginPolicyConfiguration))

- name: uploadNetgroupConfiguration
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=NetgroupConfiguration)

- name: uploadNfsExportsFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=NfsExportsFile))

- name: uploadNtpConfFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=NtpConfFile)

- name: uploadPCIDevicesInfoFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=PCIDevicesInfoFiles))

- name: uploadSambaConfigFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=SambaConfigFile)

- name: uploadSecretsServiceDatabaseFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=SecretsServiceDatabaseFile))

- name: uploadSshdConfigFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=SshdConfigFile))

- name: uploadSSHHostPubKeys
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=SSHHostPubKeys)

- name: uploadUnixGroupsFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixGroupsFile))

- name: uploadUnixLocalTimeConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixLocalTimeConfigurationFile))

- name: uploadUnixPasswdFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixPasswdFile))

- name: uploadUnixShadowFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixShadowFile))

- name: uploadUnixSudoersConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixSudoersConfigurationFile))

- name: uploadYumSources
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=YumSources))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.SysLogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.syslogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.syslogs/</guid><description>&lt;p&gt;Collect system logs and upload them.
Based on TriageSystemLogs from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.SysLogs
author: alternate
description: |
 Collect system logs and upload them.
 Based on TriageSystemLogs from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: DebianPackagesLogFiles
 default: |
 ["/var/log/dpkg.log*","/var/log/apt/history.log*","/var/log/apt/term.log"]

- name: LinuxAuditLogs
 default: /var/log/audit/*

- name: LinuxAuthLogs
 default: |
 ["/var/log/auth.log*","/var/log/secure.log*"]

- name: LinuxCronLogs
 default: /var/log/cron.log*

- name: LinuxDaemonLogFiles
 default: /var/log/daemon.log* 

- name: LinuxKernelLogFiles
 default: /var/log/kern.log*

- name: LinuxLatlogFiles
 default: /var/log/lastlog

- name: LinuxMessagesLogFiles
 default: /var/log/messages*

- name: LinuxSudoReplayLogs
 default: /var/log/sudo-io/**

- name: LinuxSysLogFiles
 default: /var/log/syslog.log* 

- name: LinuxSystemdJournalLogs
 default: |
 ["/var/log/journal/*/*.journal","/var/log/journal/*/*.journal~"]

- name: LinuxUtmpFiles
 default: |
 ["/var/log/btmp","/var/log/wtmp","/var/run/utmp"]

- name: LinuxWtmp
 default: /var/log/wtmp

- name: SambaLogFiles
 default: /var/log/samba/*.log

- name: UFWLogFile
 default: /var/log/ufw.log

- name: UnixUtmpFile
 default: |
 ["/var/log/btmp","/var/log/wtmp","/var/run/utmp"]

sources:
- name: uploadDebianPackagesLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=DebianPackagesLogFiles))

- name: uploadLinuxAuditLogs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxAuditLogs)

- name: uploadLinuxAuthLogs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxAuthLogs))

- name: uploadLinuxCronLogs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxCronLogs)

- name: uploadLinuxDaemonLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxDaemonLogFiles)

- name: uploadLinuxKernelLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxKernelLogFiles)

- name: uploadLinuxLatlogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxLatlogFiles)

- name: uploadLinuxMessagesLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxMessagesLogFiles)

- name: uploadLinuxSudoReplayLogs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxSudoReplayLogs)

- name: uploadLinuxSysLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=LinuxSysLogFiles)

- name: uploadLinuxSystemdJournalLogs
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxSystemdJournalLogs))

- name: uploadLinuxUtmpFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=LinuxUtmpFiles))

- name: uploadLinuxWtmp
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=LinuxWtmp)

- name: uploadSambaLogFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=SambaLogFiles)

- name: uploadUFWLogFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM stat(filename=UFWLogFile)

- name: uploadUnixUtmpFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=UnixUtmpFile))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Collection.UserConfig</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.userconfig/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.userconfig/</guid><description>&lt;p&gt;Collect user configurations and upload them.
Based on TriageUserConfiguration from forensicartifacts.com&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Collection.UserConfig
author: alternate
description: |
 Collect user configurations and upload them.
 Based on TriageUserConfiguration from forensicartifacts.com

reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/data/triage.yaml

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
- name: BashShellConfigurationFile
 default: |
 ["/{root,home/*}/.bash_logout","/{root,home/*}/.bash_profile","/{root,home/*}/.bashrc",
 "/etc/bash.bashrc","/etc/bashrc"]

- name: ChromePreferences
 default: |
 ["/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-config/google-chrome/*/Secure Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Preferences",
 "/{root,home/*}/.config/chrome-remote-desktop/chrome-profile/*/Secure Preferences",
 "/{root,home/*}/.config/chromium/*/Preferences",
 "/{root,home/*}/.config/chromium/*/Secure Preferences",
 "/{root,home/*}/.config/google-chrome/*/Preferences",
 "/{root,home/*}/.config/google-chrome/*/Secure Preferences"]

- name: CShellConfigurationFile
 default: |
 ["/{root,home/*}/.cshrc","/etc/csh.cshrc","/etc/csh.login","/etc/csh.logout"]

- name: FishShellConfigurationFile
 default: |
 ["/{root,home/*}/.local/share/fish/fish_history",
 "/{root,home/*}/.config/fish/conf.d/config.fish",
 "/{root,home/*}/.config/fish/config.fish",
 "/etc/fish/config.fish,/etc/fish/conf.d/*.fish"]

- name: JupyterConfigFile
 default: /{root,home/*}/.jupyter/jupyter_notebook_config.py

- name: KornShellConfigurationFile
 default: |
 ["/{root,home/*}/.ksh","/etc/kshrc"]

- name: RHostsFile
 default: /{root,home/*}/.rhosts

- name: ShellLogoutFile
 default: /{root,home/*}/.logout

- name: ShellProfileFile
 default: | 
 ["/{root,home/*}/.profile","/etc/profile"]

- name: SignalApplicationContent
 default: |
 ["/{root,home/*}/.var/app/org.signal.Signal/*/attachments.noindex/*",
 "/{root,home/*}/.var/app/org.signal.Signal/*/Cache/*",
 "/{root,home/*}/.var/app/org.signal.Signal/*/logs/*",
 "/{root,home/*}/.var/app/org.signal.Signal/config.json"]

- name: SSHAuthorizedKeysFiles
 default: |
 ["/{root,home/*}/.ssh/authorized_keys","/{root,home/*}/.ssh/authorized_keys2"]

- name: SSHKnownHostsFiles
 default: | 
 ["/{root,home/*}/.ssh/known_hosts","/etc/ssh/known_hosts"]

- name: SSHUserConfigFile
 default: /{root,home/*}/.ssh/config

- name: TeeShellConfigurationFile
 default: /{root,home/*}/.tcsh

- name: ZShellConfigurationFile
 default: |
 ["/{root,home/*}/.zlogin","/{root,home/*}/.zlogout","/{root,home/*}/.zprofile",
 "/etc/zshenv,/etc/zshrc","/etc/zsh/zlogin","/etc/zsh/zlogout","/etc/zsh/zprofile",
 "/etc/zsh/zshenv","/etc/zsh/zshrc"]

sources:
- name: uploadBashShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=BashShellConfigurationFile))

- name: uploadChromePreferences
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ChromePreferences))

- name: uploadCShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=CShellConfigurationFile))

- name: uploadFishShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=FishShellConfigurationFile))

- name: uploadJupyterConfigFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=JupyterConfigFile)

- name: uploadKornShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=KornShellConfigurationFile))

- name: uploadRHostsFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=RHostsFile)

- name: uploadShellLogoutFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=ShellLogoutFile)

- name: uploadShellProfileFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ShellProfileFile))

- name: uploadSignalApplicationContent
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=SignalApplicationContent))

- name: uploadSSHAuthorizedKeysFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=SSHAuthorizedKeysFiles))

- name: uploadSSHKnownHostsFiles
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=SSHKnownHostsFiles))

- name: uploadSSHUserConfigFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=SSHUserConfigFile)

- name: uploadTeeShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=TeeShellConfigurationFile)

- name: uploadZShellConfigurationFile
 query: |
 SELECT OSPath,
 Mtime,
 upload(file=OSPath) AS Upload
 FROM glob(globs=parse_json_array(data=ZShellConfigurationFile))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Debian.GPGKeys</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.debian.gpgkeys/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.debian.gpgkeys/</guid><description>&lt;p&gt;Extract keys, fingerprints and identities from GPG keys.&lt;/p&gt;
&lt;p&gt;This artifact runs the tool &amp;ldquo;gpg&amp;rdquo; (must be installed on the system) on the
files found matching the globs in KeyringFiles. The files need not be keyrings.&lt;/p&gt;
&lt;p&gt;Every entry consists of a public or secret key, optional subkeys and optional
identities. This artifact may be useful in other artifacts to inspect GPG
files or GPG data in order to correlate keys by their IDs, or look at connected
user IDs.&lt;/p&gt;
&lt;p&gt;This artifact doesn&amp;rsquo;t provide any information about whether a key is
&amp;ldquo;trustworthy&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Note that some keyring files contain a lot of subkeys and identities.&lt;/p&gt;
&lt;p&gt;The following columns are returned by this artifact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSPath: Path to the key file&lt;/li&gt;
&lt;li&gt;KeyInfo: dict with the following entries:
&lt;ul&gt;
&lt;li&gt;Type: pub|sub&lt;/li&gt;
&lt;li&gt;ID&lt;/li&gt;
&lt;li&gt;Fingerprint&lt;/li&gt;
&lt;li&gt;Algorithm&lt;/li&gt;
&lt;li&gt;Validity&lt;/li&gt;
&lt;li&gt;Created&lt;/li&gt;
&lt;li&gt;Expiry&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SubKeys: array of dicts with the same structure as KeyInfo&lt;/li&gt;
&lt;li&gt;UserIDs: array of strings (name and e-mail)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Debian.GPGKeys
description: |
 Extract keys, fingerprints and identities from GPG keys.

 This artifact runs the tool "gpg" (must be installed on the system) on the
 files found matching the globs in KeyringFiles. The files need not be keyrings.

 Every entry consists of a public or secret key, optional subkeys and optional
 identities. This artifact may be useful in other artifacts to inspect GPG
 files or GPG data in order to correlate keys by their IDs, or look at connected
 user IDs.

 This artifact doesn't provide any information about whether a key is
 "trustworthy".

 Note that some keyring files contain a lot of subkeys and identities.

 The following columns are returned by this artifact:

 - OSPath: Path to the key file
 - KeyInfo: dict with the following entries:
 - Type: pub|sub
 - ID
 - Fingerprint
 - Algorithm
 - Validity
 - Created
 - Expiry
 - SubKeys: array of dicts with the same structure as KeyInfo
 - UserIDs: array of strings (name and e-mail)

reference:
 - https://manpages.debian.org/bookworm/apt/apt-key.8.en.html
 - https://github.com/CSNW/gnupg/blob/master/doc/DETAILS
 - https://www.mailpile.is/blog/2014-10-07_Some_Thoughts_on_GnuPG.html
 - https://www.ietf.org/rfc/rfc4880.txt

export: |
 /* Extract machine-"readable" data from the GPG keys found in the file.
 The format is documented in the reference above. However, as the blog
 post mentions, detailed knowledge about GPG is needed in order to
 decipher the output. See ParseKeyInfo_(). */
 LET InspectGPGFile(filename) = SELECT Stdout AS Info
 FROM execve(argv=['gpg', '--with-colons', filename])

 /* Pipe data to the same command as in InspectGPGFile(): */

 LET InspectGPGData(data) = SELECT *
 FROM InspectGPGFile(filename=tempfile(data=data))
 /* Convert the validity code to a more human-readable string (see
 reference for details): */
 LET GPGValidityString(validity) = regex_transform(source=validity, map=dict(
 `^o$`='Unknown',
 `^i$`='Invalid',
 `^d$`='Disabled',
 `^r$`='Revoked',
 `^e$`='Expired',
 `^-$`='Unknown',
 `^q$`='Unknown',
 `^n$`='Invalid',
 `^m$`='Marginally valid',
 `^f$`='Fully valid',
 `^u$`='Ultimately valid',
 `^w$`='Well-known',
 `^s$`='Special'
 ))

 /* Convert timestamp, but only if it is non-null: */
 LET MaybeTimestamp(epoch) = if(
 condition=epoch, then=timestamp(epoch=epoch), else=null)

 LET ParseKeyInfo_(data) = SELECT * FROM foreach(
 /* A file may contain several "keys" (i.e. sections of either a
 public or private key, followed by a fingerprint, subkeys and
 identities). In order to parse these sections, the contents of
 the file are split (an arbitraray binary blob is used): */
 row={SELECT split(sep_string='\x01\x02\0x03',
 string=regex_replace(source=data, re='(?m)^(pub|sec):',replace='\x01\x02\x03$1')) AS KeyInfo
 FROM scope()},
 query={
 /* There is only one key (public or private) followed by an
 optional fingerprint: */
 SELECT parse_string_with_regex(string=KeyInfo, regex=(
 '''(?m)(?P&amp;lt;Type&amp;gt;pub|sec):(?P&amp;lt;Validity&amp;gt;[^:]*):(?P&amp;lt;Length&amp;gt;[^:]*):(?P&amp;lt;Algorithm&amp;gt;[^:]*):(?P&amp;lt;ID&amp;gt;[^:]*):(?P&amp;lt;Created&amp;gt;[^:]*):(?P&amp;lt;Expiry&amp;gt;[^:]*):[^:]*:(?P&amp;lt;Trust&amp;gt;[^:]*)''',
 '''fpr:::::::::(?P&amp;lt;Fingerprint&amp;gt;[^:]*)'''
 )) AS KeyInfo,
 /* There may be none or several subkeys (following the same
 format as public/private keys): */
 {SELECT Type,
 ID,
 Fingerprint,
 atoi(string=Algorithm) AS Algorithm,
 GPGValidityString(validity=Validity) AS Validity,
 MaybeTimestamp(epoch=Created) AS Created,
 MaybeTimestamp(epoch=Expiry) AS Expiry
 FROM parse_records_with_regex(
 file=KeyInfo,
 accessor='data',
 regex=(
 '''(?m)(?P&amp;lt;Type&amp;gt;sub):(?P&amp;lt;Validity&amp;gt;[^:]*):(?P&amp;lt;Length&amp;gt;[^:]*):(?P&amp;lt;Algorithm&amp;gt;[^:]*):(?P&amp;lt;ID&amp;gt;[^:]*):(?P&amp;lt;Created&amp;gt;[^:]*):(?P&amp;lt;Expiry&amp;gt;[^:]*):[^:]*:(?P&amp;lt;Trust&amp;gt;[^:]*)''',
 '''fpr:::::::::(?P&amp;lt;Fingerprint&amp;gt;[^:]*)'''
 ))
 } AS SubKeys,
 /* There may be none or several identities: */
 array(uids={SELECT UserID FROM parse_records_with_regex(
 file=KeyInfo,
 accessor='data',
 regex='''uid:::::::::(?P&amp;lt;UserID&amp;gt;[^:]*)''')}) AS UserIDs
 FROM scope()
 WHERE KeyInfo
 })

 LET ParseKeyInfo(data) = SELECT dict(
 Type=KeyInfo.Type,
 ID=KeyInfo.ID,
 Fingerprint=get(item=KeyInfo, field='Fingerprint', default=''),
 Algorithm=atoi(string=KeyInfo.Algorithm),
 Validity=GPGValidityString(validity=KeyInfo.Validity),
 Created=MaybeTimestamp(epoch=KeyInfo.Created),
 Expiry=MaybeTimestamp(epoch=KeyInfo.Expiry)
 ) AS KeyInfo,
 SubKeys,
 UserIDs
 FROM ParseKeyInfo_(data=data)

 LET ParseGPG(data) = SELECT *
 FROM ParseKeyInfo(data=InspectGPGData(data=data))

 LET ParseGPGFile(filename) = SELECT *
 FROM ParseKeyInfo(data=InspectGPGFile(filename=filename))

parameters:
 - name: KeyringFiles
 description: Globs to find GPG keyrings
 type: csv
 default: |
 KeyringGlobs
 /etc/apt/trusted.gpg
 /etc/apt/trusted.gpg.d/*.gpg
 /etc/apt/keyrings/*.gpg
 /usr/share/keyrings/*.gpg

precondition:
 SELECT OS From info() where OS = 'linux'

sources:
 - name: KeyringKeys
 query: |
 LET GPGKeys = SELECT * FROM foreach(
 row={SELECT OSPath FROM glob(globs=KeyringFiles.KeyringGlobs)},
 query={SELECT OSPath, * FROM ParseGPGFile(filename=OSPath)}
 )

 SELECT * FROM GPGKeys

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.BruteForce</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.bruteforce/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.bruteforce/</guid><description>&lt;p&gt;Linux detection brute force module.
This code is based on &lt;a href="https://github.com/RCarras/linforce/blob/main/linforce.sh" target="_blank" &gt;https://github.com/RCarras/linforce/blob/main/linforce.sh&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This module uses btmp/wtmp files to search for possible brute force attacks comparing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wtmp (successful attempts) and btmp (failed attempts) Logs.&lt;/li&gt;
&lt;li&gt;Time interval between failed login attempts, and against successful logins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Type of attacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic Brute Force Attack: multiple consecutive attempts from an IP.&lt;/li&gt;
&lt;li&gt;Password Spraying: multiple consecutive attempts from different users with the same password.&lt;/li&gt;
&lt;li&gt;Dynamic IP Attack: multiple consecutive attempts from different IPs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Creators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rafael Carrasco: &lt;a href="https://www.linkedin.com/in/rafael-carrasco-vilaplana-3199a492" target="_blank" &gt;https://www.linkedin.com/in/rafael-carrasco-vilaplana-3199a492&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;David Rosado: &lt;a href="https://www.linkedin.com/in/david-rosado-soria-4416b8230" target="_blank" &gt;https://www.linkedin.com/in/david-rosado-soria-4416b8230&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.BruteForce
description: | 

 Linux detection brute force module.
 This code is based on https://github.com/RCarras/linforce/blob/main/linforce.sh
 
 This module uses btmp/wtmp files to search for possible brute force attacks comparing:
 
 * Wtmp (successful attempts) and btmp (failed attempts) Logs.
 * Time interval between failed login attempts, and against successful logins.
 
 Type of attacks:
 
 * Basic Brute Force Attack: multiple consecutive attempts from an IP.
 * Password Spraying: multiple consecutive attempts from different users with the same password. 
 * Dynamic IP Attack: multiple consecutive attempts from different IPs.

 Creators:
 
 * Rafael Carrasco: https://www.linkedin.com/in/rafael-carrasco-vilaplana-3199a492
 * David Rosado: https://www.linkedin.com/in/david-rosado-soria-4416b8230

type: client

parameters: 
 - name: "brutevar"
 description: "Number of attempts to consider as brute force"
 default: "80"
 - name: "intervalvar"
 description: "Time interval between attempts to be considered as consecutive"
 default: "45"
 - name: "min_timestamp"
 description: "Initial timestamp for the analysis in the format YYYYmmddHHMMSS"
 default: "20220901000000" 
 - name: "max_timestamp"
 description: "Maximum timestamp for the analysis in the format YYYYmmddHHMMSS"
 default: "20301231000000"
 


tools:
 - name: linforce
 url: https://raw.githubusercontent.com/RCarras/linforce/main/linforce.sh
 expected_hash: 998f65cc9f9eef746c38a165e86317e502a0915161df824ad935613e0ad74b0d
 
sources:
 - name: btmp.logs
 query: |
 -- Download tool
 LET LinforceTool &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="linforce", IsExecutable=TRUE)
 
 -- Delete output after the module end
 LET outputPath &amp;lt;= tempdir(remove_last=TRUE)
 
 -- Execute the script as root and capture the output
 LET _ &amp;lt;= SELECT * FROM execve(argv=["sudo", "/bin/bash", LinforceTool.FullPath[0], "-b", brutevar, "-t", intervalvar, "-i", min_timestamp, "-m", max_timestamp, "-o", outputPath])

 -- Parse output 
 SELECT * 
 FROM split_records(filenames=outputPath+"/btmp.logs", first_row_is_headers=true)
 
 - name: wtmp.logs
 query: |
 SELECT *
 FROM split_records(filenames=outputPath+"/wtmp.logs", first_row_is_headers=true)
 
 - name: hits_login
 query: |
 SELECT * 
 FROM parse_lines(filename=outputPath+"/hits_login")
 
 - name: brute_force_attempts.log
 query: |
 SELECT * 
 FROM parse_lines(filename=outputPath+"/brute_force_attempts.log")
 
 - name: red_zone_attempts.log
 query: |
 SELECT * 
 FROM parse_lines(filename=outputPath+"/red_zone_attempts.log")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.ConfluenceLogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/confluencelogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/confluencelogs/</guid><description>&lt;p&gt;This artifact enables grep of Linux logs and targets strings observed in
exploitation of CVE-2022-26134.&lt;/p&gt;
&lt;p&gt;CVE-2022-26134, a critical unauthenticated remote code execution vulnerability
in Confluence Server and Confluence Data Center.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.ConfluenceLogs
author: "Matt Green - @mgreen27"
description: |
 This artifact enables grep of Linux logs and targets strings observed in 
 exploitation of CVE-2022-26134.
 
 CVE-2022-26134, a critical unauthenticated remote code execution vulnerability 
 in Confluence Server and Confluence Data Center. 
 
reference:
 - https://www.rapid7.com/blog/post/2022/06/02/active-exploitation-of-confluence-cve-2022-26134/

parameters:
 - name: TargetFiles
 default: '/{/var/log/**,/opt/atlassian/confluence*/**/logs/*}'
 - name: SearchRegex
 description: "Regex of strings to search in log line."
 default: '%24%7B|(GET|POST).{0,20}\$\{|154\.146\.34\.145|154\.16\.105\.147|156\.146\.34\.46|156\.146\.34\.52|156\.146\.34\.9|156\.146\.56\.136|198\.147\.22\.148|221\.178\.126\.244|45\.43\.19\.91|59\.163\.248\.170|64\.64\.228\.239|66\.115\.182\.102|66\.115\.182\.111|67\.149\.61\.16|98\.32\.230\.38'
 type: regex
 - name: FilterRegex
 description: "Regex of strings to leave out of output."
 default:
 type: regex
 - name: ExcludeDirectoryRegex
 type: regex
 description: "Does not descend into directories that match this Regex."
 default: "^/(shared|proc|snap)"
 - name: ExcludePathRegex
 description: "Regex of paths to exclude from scanning."
 default: '\.journal$'
 type: regex
 
sources:
 - query: |
 LET RecursionCB &amp;lt;= if(condition= ExcludeDirectoryRegex,
 then="x =&amp;gt; NOT x.OSPath =~ ExcludeDirectoryRegex",
 else="x =&amp;gt; NOT x.OSPath =~ '^/proc' ")
 
 LET files = SELECT OSPath 
 FROM glob(globs=TargetFiles,
 nosymlink=TRUE,
 recursion_callback=RecursionCB)
 WHERE NOT IsDir AND NOT OSPath =~ ExcludePathRegex
 AND log(message="Scanning %v", args=OSPath)
 LET hits = SELECT * FROM foreach(row=files,
 query={
 SELECT OSPath, Line FROM parse_lines(filename=OSPath)
 WHERE Line =~ SearchRegex
 })
 
 SELECT * FROM if(condition=FilterRegex,
 then={ 
 SELECT * FROM hits
 WHERE NOT Line =~ FilterRegex
 },
 else={ 
 SELECT * FROM hits 
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.CVE20214034</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.cve20214034/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.cve20214034/</guid><description>&lt;p&gt;This artifact lists processes running as root that were spawns by processes that are not
running as root. This kind of behavior is normal for things like sudo or su but for other
processes (especially /bin/bash) it could represent a process launched via CVE-2021-4034.&lt;/p&gt;
&lt;p&gt;The artifact looks for running processes with this property as well as search the auth
log files for evidence of past execution of this exploit.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.CVE20214034
description: |
 This artifact lists processes running as root that were spawns by processes that are not
 running as root. This kind of behavior is normal for things like sudo or su but for other
 processes (especially /bin/bash) it could represent a process launched via CVE-2021-4034.

 The artifact looks for running processes with this property as well as search the auth
 log files for evidence of past execution of this exploit.

type: CLIENT

parameters:
 - name: AcceptableParentExeRegex
 description: A list of acceptable parent processes that are OK (unset to see all parents)
 type: regex
 default: ^(/usr/bin/sudo)
 - name: AuthLogsGlob
 default: /var/log/auth.log*

precondition:
 SELECT OS From info() where OS = 'linux'

sources:
 - query: |
 SELECT Pid, Ppid, Cmdline, Exe, Uids, Username, {
 SELECT Pid, Cmdline, Exe, Uids, Username
 FROM pslist(pid=Ppid)
 } AS Parent
 FROM pslist()
 WHERE Ppid 
 AND Username =~ "root"
 AND Parent.Username != Username
 AND if(condition=AcceptableParentExeRegex,
 then=NOT Parent.Exe =~ AcceptableParentExeRegex,
 else=TRUE)
 - name: AuthLogs
 query: |
 SELECT * FROM foreach(row={
 SELECT * FROM glob(globs=AuthLogsGlob)
 }, query={
 SELECT * FROM parse_lines(filename=FullPath)
 WHERE Line =~ "pkexec.+The value for environment variable XAUTHORITY contains suscipious content"
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.CVE202514847.MongoBleed</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.cve202514847.mongobleed/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.cve202514847.mongobleed/</guid><description>&lt;p&gt;Hunts for evidence of CVE-2025-14847 (MongoBleed) exploitation on MongoDB servers.&lt;/p&gt;
&lt;p&gt;MongoBleed is a memory disclosure vulnerability in MongoDB&amp;rsquo;s zlib decompression
that allows attackers to extract sensitive data (credentials, session tokens, PII)
from server memory by establishing many rapid connections without authentication.&lt;/p&gt;
&lt;h2 id="affected-versions"&gt;Affected Versions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;MongoDB 8.2.0 - 8.2.2 (fixed in 8.2.3)&lt;/li&gt;
&lt;li&gt;MongoDB 8.0.0 - 8.0.16 (fixed in 8.0.17)&lt;/li&gt;
&lt;li&gt;MongoDB 7.0.0 - 7.0.27 (fixed in 7.0.28)&lt;/li&gt;
&lt;li&gt;MongoDB 6.0.0 - 6.0.26 (fixed in 6.0.27)&lt;/li&gt;
&lt;li&gt;MongoDB 5.0.0 - 5.0.31 (fixed in 5.0.32)&lt;/li&gt;
&lt;li&gt;MongoDB 4.4.0 - 4.4.29 (fixed in 4.4.30)&lt;/li&gt;
&lt;li&gt;All MongoDB 4.2.x versions (EOL)&lt;/li&gt;
&lt;li&gt;All MongoDB 4.0.x versions (EOL)&lt;/li&gt;
&lt;li&gt;All MongoDB 3.6.x versions (EOL)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="detection-logic"&gt;Detection Logic&lt;/h2&gt;
&lt;p&gt;The exploit creates thousands of connections to probe for memory leaks but never
sends client metadata like legitimate MongoDB drivers do. This artifact detects
the attack by analyzing connection patterns in MongoDB JSON logs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse MongoDB logs for connection events (id:22943) and metadata (id:51800)&lt;/li&gt;
&lt;li&gt;Aggregate connections per source IP within the time window&lt;/li&gt;
&lt;li&gt;Calculate metadata rate (legitimate drivers: ~90-100%, exploit: 0%)&lt;/li&gt;
&lt;li&gt;Calculate connection velocity (exploit: ~100,000+ connections/min)&lt;/li&gt;
&lt;li&gt;Flag IPs matching attack characteristics&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="risk-levels"&gt;Risk Levels&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Level&lt;/th&gt;
 &lt;th&gt;Criteria&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;HIGH&lt;/td&gt;
 &lt;td&gt;≥100 connections AND &amp;lt;10% metadata rate AND ≥500 conn/min&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;MEDIUM&lt;/td&gt;
 &lt;td&gt;≥100 connections AND &amp;lt;10% metadata rate (low velocity)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LOW&lt;/td&gt;
 &lt;td&gt;≥100 connections (normal metadata rate)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;INFO&lt;/td&gt;
 &lt;td&gt;&amp;lt;100 connections&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Velocity-based detection reduces false positives from long-running low-activity
scenarios while ensuring real attacks (100,000+ conn/min) are always flagged HIGH.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MongoDBLogAnalysis&lt;/strong&gt;: Parse log files from disk&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DockerMongoDBLogs&lt;/strong&gt;: Parse logs from Docker containers (requires Docker daemon)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RawConnectionEvents&lt;/strong&gt;: Detailed view of individual connection events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sources are skipped when preconditions aren&amp;rsquo;t met (no Docker, empty container pattern).
No Docker commands execute unless DockerContainerPattern is set and Docker is running.&lt;/p&gt;
&lt;h2 id="validation"&gt;Validation&lt;/h2&gt;
&lt;p&gt;Tested against real (POC) MongoBleed exploit traffic across MongoDB 6.0, 7.0, 8.0, and 8.2:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attack traffic: 499 connections in 0.3s (111,716/min), 0% metadata → HIGH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Production traffic analysis (legitimate patterns observed over multiple days):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Normal velocity: 0.2–3.2 connections/min (vs exploit: 100,000+/min)&lt;/li&gt;
&lt;li&gt;Normal metadata rate: 99–100% (vs exploit: 0%)&lt;/li&gt;
&lt;li&gt;Daily connection volumes: 300–4,500 connections with consistent metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.CVE202514847.MongoBleed
author: Eric Capuano (https://bsky.app/profile/eric.zip)
description: |
 Hunts for evidence of CVE-2025-14847 (MongoBleed) exploitation on MongoDB servers.

 MongoBleed is a memory disclosure vulnerability in MongoDB's zlib decompression
 that allows attackers to extract sensitive data (credentials, session tokens, PII)
 from server memory by establishing many rapid connections without authentication.

 ## Affected Versions

 - MongoDB 8.2.0 - 8.2.2 (fixed in 8.2.3)
 - MongoDB 8.0.0 - 8.0.16 (fixed in 8.0.17)
 - MongoDB 7.0.0 - 7.0.27 (fixed in 7.0.28)
 - MongoDB 6.0.0 - 6.0.26 (fixed in 6.0.27)
 - MongoDB 5.0.0 - 5.0.31 (fixed in 5.0.32)
 - MongoDB 4.4.0 - 4.4.29 (fixed in 4.4.30)
 - All MongoDB 4.2.x versions (EOL)
 - All MongoDB 4.0.x versions (EOL)
 - All MongoDB 3.6.x versions (EOL)

 ## Detection Logic

 The exploit creates thousands of connections to probe for memory leaks but never
 sends client metadata like legitimate MongoDB drivers do. This artifact detects
 the attack by analyzing connection patterns in MongoDB JSON logs:

 1. Parse MongoDB logs for connection events (id:22943) and metadata (id:51800)
 2. Aggregate connections per source IP within the time window
 3. Calculate metadata rate (legitimate drivers: ~90-100%, exploit: 0%)
 4. Calculate connection velocity (exploit: ~100,000+ connections/min)
 5. Flag IPs matching attack characteristics

 ## Risk Levels

 | Level | Criteria |
 |--------|----------|
 | HIGH | ≥100 connections AND &amp;lt;10% metadata rate AND ≥500 conn/min |
 | MEDIUM | ≥100 connections AND &amp;lt;10% metadata rate (low velocity) |
 | LOW | ≥100 connections (normal metadata rate) |
 | INFO | &amp;lt;100 connections |

 Velocity-based detection reduces false positives from long-running low-activity
 scenarios while ensuring real attacks (100,000+ conn/min) are always flagged HIGH.

 ## Sources

 - **MongoDBLogAnalysis**: Parse log files from disk
 - **DockerMongoDBLogs**: Parse logs from Docker containers (requires Docker daemon)
 - **RawConnectionEvents**: Detailed view of individual connection events

 Sources are skipped when preconditions aren't met (no Docker, empty container pattern).
 No Docker commands execute unless DockerContainerPattern is set and Docker is running.

 ## Validation

 Tested against real (POC) MongoBleed exploit traffic across MongoDB 6.0, 7.0, 8.0, and 8.2:
 - Attack traffic: 499 connections in 0.3s (111,716/min), 0% metadata → HIGH

 Production traffic analysis (legitimate patterns observed over multiple days):
 - Normal velocity: 0.2–3.2 connections/min (vs exploit: 100,000+/min)
 - Normal metadata rate: 99–100% (vs exploit: 0%)
 - Daily connection volumes: 300–4,500 connections with consistent metadata

reference:
 - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-14847
 - https://github.com/joe-desimone/mongobleed
 - https://www.ox.security/blog/attackers-could-exploit-zlib-to-exfiltrate-data-cve-2025-14847/

type: CLIENT

precondition: SELECT OS FROM info() WHERE OS = 'linux'

parameters:
 - name: MongoLogGlobs
 description: |
 JSON array of glob patterns to find MongoDB log files.
 Override for non-standard installations (e.g., custom paths, Atlas, containers).
 Default covers Ubuntu/Debian, RHEL/CentOS, and JSON log formats.
 type: string
 default: |
 ["/var/log/mongodb/*.log*", "/var/log/mongod.log*", "/var/log/mongo*.json*"]

 - name: DockerContainerPattern
 description: |
 Docker container name pattern to match (supports wildcards).
 Examples: "mongo*", "*mongodb*", "prod-mongo-*"
 Leave BLANK to skip Docker scanning entirely (no Docker commands will be executed).
 type: string
 default: ""

 - name: ConnectionThreshold
 description: Minimum connections from single IP to flag as suspicious
 type: int
 default: 100

 - name: MetadataRatioThreshold
 description: Maximum metadata/connection ratio to flag (0.1 = 10%)
 type: float
 default: 0.1

 - name: VelocityThreshold
 description: |
 Minimum connections per minute to consider as attack velocity.
 MongoBleed creates ~130,000 connections/minute. Default 500/min is conservative.
 type: int
 default: 500

 - name: TimeRangeMinutes
 description: Look back period in minutes
 type: int
 default: 60

sources:
 - name: MongoDBLogAnalysis
 description: Parse MongoDB logs and detect MongoBleed attack patterns
 query: |
 -- Calculate time range cutoff
 LET cutoff_time = timestamp(epoch=now() - TimeRangeMinutes * 60)

 -- Find MongoDB log files
 LET log_files = SELECT OSPath
 FROM glob(globs=parse_json_array(data=MongoLogGlobs))
 WHERE OSPath =~ "\\.(log|json)"

 -- Parse each log file line by line as JSON, filtered by time range
 LET parsed_logs = SELECT * FROM foreach(
 row=log_files,
 query={
 SELECT
 OSPath,
 parse_json(data=Line) AS LogEntry
 FROM parse_lines(filename=OSPath)
 WHERE Line =~ "^\\{"
 AND timestamp(string=parse_json(data=Line).t.`$date`) &amp;gt;= cutoff_time
 })

 -- Extract connection events
 LET connection_events = SELECT
 OSPath,
 LogEntry.t.`$date` AS Timestamp,
 LogEntry.id AS EventId,
 LogEntry.msg AS Message,
 LogEntry.attr.remote AS Remote,
 LogEntry.attr.connectionId AS ConnectionId,
 regex_replace(source=LogEntry.attr.remote, re=":\\d+$", replace="") AS SourceIP
 FROM parsed_logs
 WHERE LogEntry.id IN (22943, 51800, 22944)

 -- Aggregate by source IP
 LET aggregated = SELECT
 SourceIP,
 count() AS TotalEvents,
 sum(item=if(condition=(EventId = 22943), then=1, else=0)) AS Connections,
 sum(item=if(condition=(EventId = 51800), then=1, else=0)) AS MetadataEvents,
 sum(item=if(condition=(EventId = 22944), then=1, else=0)) AS Disconnections,
 min(item=Timestamp) AS FirstSeen,
 max(item=Timestamp) AS LastSeen
 FROM connection_events
 GROUP BY SourceIP

 -- Calculate velocity and detect attack pattern
 LET with_velocity = SELECT
 SourceIP,
 Connections,
 MetadataEvents,
 Disconnections,
 FirstSeen,
 LastSeen,
 (timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) / 1000000000.0 AS DurationSeconds,
 if(condition=((timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) &amp;gt; 0),
 then=Connections * 60.0 / ((timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) / 1000000000.0),
 else=Connections * 60.0) AS ConnectionsPerMinute
 FROM aggregated

 SELECT
 SourceIP,
 Connections,
 MetadataEvents,
 Disconnections,
 FirstSeen,
 LastSeen,
 format(format="%.1fs", args=[DurationSeconds]) AS Duration,
 format(format="%.0f/min", args=[ConnectionsPerMinute]) AS Velocity,
 if(condition=(Connections &amp;gt; 0),
 then=format(format="%.2f%%", args=[MetadataEvents * 100.0 / Connections]),
 else="N/A") AS MetadataRate,
 if(condition=(Connections &amp;gt;= ConnectionThreshold AND
 (MetadataEvents * 1.0 / Connections) &amp;lt; MetadataRatioThreshold AND
 ConnectionsPerMinute &amp;gt;= VelocityThreshold),
 then="HIGH - Likely MongoBleed Exploitation",
 else=if(condition=(Connections &amp;gt;= ConnectionThreshold AND
 (MetadataEvents * 1.0 / Connections) &amp;lt; MetadataRatioThreshold),
 then="MEDIUM - Suspicious Pattern (low velocity)",
 else=if(condition=(Connections &amp;gt;= ConnectionThreshold),
 then="LOW - High Connection Rate",
 else="INFO"))) AS RiskLevel,
 "CVE-2025-14847" AS CVE,
 "MongoBleed MongoDB Memory Leak" AS ThreatName
 FROM with_velocity
 WHERE Connections &amp;gt; 10
 ORDER BY Connections DESC

 - name: DockerMongoDBLogs
 description: Parse MongoDB logs from Docker containers matching pattern
 query: |
 -- Check if Docker is available and pattern is configured
 LET docker_available = DockerContainerPattern != "" AND stat(filename="/var/run/docker.sock")

 -- Calculate time range
 LET since_duration = format(format="%dm", args=[TimeRangeMinutes])

 -- Find all containers matching the pattern (only if Docker available)
 LET matching_containers = SELECT * FROM if(condition=docker_available,
 then={
 SELECT
 parse_string_with_regex(
 string=Stdout,
 regex="^(?P&amp;lt;ContainerName&amp;gt;.+)$"
 ).ContainerName AS ContainerName
 FROM execve(
 argv=["docker", "ps", "--filter", "name=" + DockerContainerPattern, "--format", "{{.Names}}"],
 sep="\n"
 )
 WHERE Stdout != ""
 })

 -- Get docker logs from each matching container (use --since for efficiency)
 LET docker_logs = SELECT * FROM foreach(
 row=matching_containers,
 query={
 SELECT
 ContainerName,
 parse_json(data=Stdout) AS LogEntry,
 Stdout AS RawLine
 FROM execve(argv=["docker", "logs", ContainerName, "--since", since_duration, "--tail", "50000"], sep="\n")
 WHERE Stdout =~ "^\\{"
 })

 -- Extract connection events from docker logs
 LET docker_events = SELECT
 ContainerName,
 LogEntry.t.`$date` AS Timestamp,
 LogEntry.id AS EventId,
 LogEntry.msg AS Message,
 LogEntry.attr.remote AS Remote,
 LogEntry.attr.connectionId AS ConnectionId,
 regex_replace(source=LogEntry.attr.remote, re=":\\d+$", replace="") AS SourceIP
 FROM docker_logs
 WHERE LogEntry.id IN (22943, 51800, 22944)

 -- Aggregate by container and source IP
 LET docker_aggregated = SELECT
 ContainerName,
 SourceIP,
 count() AS TotalEvents,
 sum(item=if(condition=(EventId = 22943), then=1, else=0)) AS Connections,
 sum(item=if(condition=(EventId = 51800), then=1, else=0)) AS MetadataEvents,
 sum(item=if(condition=(EventId = 22944), then=1, else=0)) AS Disconnections,
 min(item=Timestamp) AS FirstSeen,
 max(item=Timestamp) AS LastSeen
 FROM docker_events
 GROUP BY ContainerName, SourceIP

 -- Calculate velocity and detect attack pattern
 LET docker_with_velocity = SELECT
 ContainerName,
 SourceIP,
 Connections,
 MetadataEvents,
 Disconnections,
 FirstSeen,
 LastSeen,
 (timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) / 1000000000.0 AS DurationSeconds,
 if(condition=((timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) &amp;gt; 0),
 then=Connections * 60.0 / ((timestamp(string=LastSeen).UnixNano - timestamp(string=FirstSeen).UnixNano) / 1000000000.0),
 else=Connections * 60.0) AS ConnectionsPerMinute
 FROM docker_aggregated

 SELECT
 ContainerName,
 SourceIP,
 Connections,
 MetadataEvents,
 Disconnections,
 FirstSeen,
 LastSeen,
 format(format="%.1fs", args=[DurationSeconds]) AS Duration,
 format(format="%.0f/min", args=[ConnectionsPerMinute]) AS Velocity,
 if(condition=(Connections &amp;gt; 0),
 then=format(format="%.2f%%", args=[MetadataEvents * 100.0 / Connections]),
 else="N/A") AS MetadataRate,
 if(condition=(Connections &amp;gt;= ConnectionThreshold AND
 (MetadataEvents * 1.0 / Connections) &amp;lt; MetadataRatioThreshold AND
 ConnectionsPerMinute &amp;gt;= VelocityThreshold),
 then="HIGH - Likely MongoBleed Exploitation",
 else=if(condition=(Connections &amp;gt;= ConnectionThreshold AND
 (MetadataEvents * 1.0 / Connections) &amp;lt; MetadataRatioThreshold),
 then="MEDIUM - Suspicious Pattern (low velocity)",
 else=if(condition=(Connections &amp;gt;= ConnectionThreshold),
 then="LOW - High Connection Rate",
 else="INFO"))) AS RiskLevel,
 "CVE-2025-14847" AS CVE,
 "MongoBleed MongoDB Memory Leak" AS ThreatName
 FROM docker_with_velocity
 WHERE Connections &amp;gt; 10
 ORDER BY Connections DESC

 - name: RawConnectionEvents
 description: Raw connection events for detailed analysis
 query: |
 -- Calculate time range cutoff
 LET cutoff_time = timestamp(epoch=now() - TimeRangeMinutes * 60)

 -- Find MongoDB log files
 LET log_files = SELECT OSPath
 FROM glob(globs=parse_json_array(data=MongoLogGlobs))
 WHERE OSPath =~ "\\.(log|json)"

 -- Parse and return raw connection events, filtered by time range
 SELECT
 OSPath AS LogFile,
 parse_json(data=Line).t.`$date` AS Timestamp,
 parse_json(data=Line).id AS EventId,
 parse_json(data=Line).msg AS Message,
 parse_json(data=Line).attr.remote AS Remote,
 parse_json(data=Line).attr.connectionId AS ConnectionId,
 parse_json(data=Line).attr.connectionCount AS ConnectionCount
 FROM foreach(
 row=log_files,
 query={
 SELECT OSPath, Line
 FROM parse_lines(filename=OSPath)
 WHERE Line =~ "^\\{" AND Line =~ '"id":(22943|51800|22944)'
 AND timestamp(string=parse_json(data=Line).t.`$date`) &amp;gt;= cutoff_time
 })
 ORDER BY Timestamp DESC
 LIMIT 1000

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.Honeyfiles</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.honeyfiles/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.honeyfiles/</guid><description>&lt;p&gt;This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using eBPF. The process tracker must be enabled, we use this to enrich events. You also must be using Velociraptor &amp;gt;= 0.74 to support eBPF. Honeyfiles created by this artifact are removed at exit.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TargetPath - Location to create honeyfile.&lt;/li&gt;
&lt;li&gt;Enabled - Only generate the honeyfile if this is set to &amp;lsquo;Y&amp;rsquo;&lt;/li&gt;
&lt;li&gt;MagicBytes - The starting magic bytes of the honeyfile.&lt;/li&gt;
&lt;li&gt;MinSize,MaxSize - The size of the honeyfile will be a random value between MinSize and MaxSize.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.Honeyfiles
author: Zane Gittins &amp;amp; Matt Green (@mgreen27).
description: |
 This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using eBPF. The process tracker must be enabled, we use this to enrich events. You also must be using Velociraptor &amp;gt;= 0.74 to support eBPF. Honeyfiles created by this artifact are removed at exit.

 * TargetPath - Location to create honeyfile.
 * Enabled - Only generate the honeyfile if this is set to 'Y'
 * MagicBytes - The starting magic bytes of the honeyfile.
 * MinSize,MaxSize - The size of the honeyfile will be a random value between MinSize and MaxSize.

type: CLIENT_EVENT

parameters:
 - name: Honeyfiles
 description: The honeyfiles to generate and monitor.
 type: csv
 default: |
 TargetPath,Enabled,MagicBytes,MinSize,MaxSize
 "%USERPROFILE%/.ssh/my_id_rsa",Y,2D2D2D2D2D424547494E205253412050524956415445204B45592D2D2D2D2D,10249,20899
 "%USERPROFILE%/.aws/credentials",Y,5B64656661756C745D,512,2048
 "%USERPROFILE%/.gcloud/credentials.db",Y,53514c69746520666f726d6174203300,512,2048
 "%USERPROFILE%/.azure/azureProfile.json",Y,7B0D0A,512,2048
 - name: ProcessExceptionsRegex
 description: Except these processes from detections when they access honeyfiles.
 type: string
 default: "/usr/bin/updatedb"
 - name: HoneyUserRegex
 description: User name regex that will be used to host honeyfiles.
 type: string
 default: "."
sources:
 - precondition:
 SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") &amp;gt;= 0

 query: |
 LET RandomChars(size) = SELECT
 format(format="%02x", args=rand(range=256)) AS HexByte
 FROM range(end=size)
 
 LET check_exist(path) = SELECT
 OSPath,
 Size,
 IsDir,
 if(condition=read_file(filename=OSPath)[-7:] =~ 'VRHoney',
 then=True,
 else=False) AS IsHoneyFile
 FROM stat(filename=path)
 
 LET enumerate_path = SELECT regex_replace(source=TargetPath,
 re='''\%USERPROFILE\%''',
 replace=Homedir) AS TargetPath,
 *,
 check_exist(path=regex_replace(
 source=TargetPath,
 re='''\%USERPROFILE\%''',
 replace=Homedir))[0] AS Exists,
 MaxSize - rand(range=(MaxSize - MinSize)) -
 len(list=unhex(string=MagicBytes)) - 7 AS _PaddingSize
 FROM Honeyfiles
 
 LET target_users = SELECT User,
 Homedir,
 Uid
 FROM Artifact.Linux.Sys.Users()
 WHERE int(int=Uid) &amp;gt;= 1000
 AND NOT Homedir = '/nonexistent'
 AND User =~ HoneyUserRegex
 
 LET show_honeyfiles = SELECT TargetPath,
 Enabled,
 MagicBytes,
 MinSize,
 MaxSize,
 _PaddingSize,
 Exists.Size AS Size,
 Exists.IsHoneyFile AS IsHoneyFile
 FROM foreach(row=target_users, query=enumerate_path)
 
 LET copy_honeyfiles = SELECT
 *, if(condition=Enabled =~ "^(Y|YES)$"
 AND (NOT Size OR IsHoneyFile),
 then=log(message="Creating file %v", dedup=-1, args=TargetPath)
 AND copy(dest=TargetPath,
 create_directories='y',
 accessor='data',
 filename=unhex(
 string=MagicBytes + join(
 array=RandomChars(size=_PaddingSize).HexByte) +
 format(format='%x', args='VRHoney'))),
 else="File does not exist") AS CreateHoneyFile
 FROM show_honeyfiles
 
 LET remove_honeyfiles = SELECT
 *, _PaddingSize,
 if(condition=IsHoneyFile,
 then=log(message="Removing %v", args=TargetPath, dedup=-1)
 AND rm(filename=TargetPath),
 else="File does not exist") AS RemoveHoneyFile
 FROM show_honeyfiles
 
 LET add_honeyfiles = SELECT
 TargetPath,
 Enabled,
 MagicBytes,
 MinSize,
 MaxSize,
 check_exist(path=TargetPath)[0].Size AS Size,
 check_exist(path=TargetPath)[0].IsHoneyFile AS IsHoneyFile
 FROM copy_honeyfiles
 
 LET chmod_honeyfiles = SELECT *
 FROM foreach(row=add_honeyfiles,
 query={
 SELECT TargetPath,
 Enabled,
 MagicBytes,
 MinSize,
 MaxSize,
 Size,
 IsHoneyFile
 FROM execve(argv=["chmod", "+r", TargetPath])
 })
 
 LET _ &amp;lt;= atexit(query={ SELECT * FROM remove_honeyfiles })
 
 LET WatchFiles &amp;lt;= to_dict(item={
 SELECT TargetPath AS _key,
 IsHoneyFile AS _value
 FROM chmod_honeyfiles
 WHERE IsHoneyFile
 })
 
 LET CurrentPid &amp;lt;= getpid()
 
 LET TargetEvents = SELECT *
 FROM watch_ebpf(events=["security_file_open"])
 WHERE System.EventName = "security_file_open"
 AND System.ProcessID != CurrentPid
 AND System.HostProcessID = System.ProcessID
 
 LET AuditEvents = SELECT
 *, timestamp(string=System.Timestamp) AS Timestamp,
 get(item=WatchFiles, field=EventData.pathname) AS IsHoneyFile
 FROM TargetEvents
 WHERE IsHoneyFile != NULL
 
 LET Track = SELECT
 Timestamp,
 System.ProcessID AS Pid,
 EventData.pathname AS FileName,
 process_tracker_get(id=System.ProcessID).Data AS ProcInfo,
 join(array=process_tracker_callchain(id=System.ProcessID).Data.Name,
 sep="-&amp;gt;") AS CallChain,
 (System.ProcessID + EventData.pathname) AS DedupKey
 FROM AuditEvents
 WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex
 
 SELECT Timestamp,
 Pid,
 FileName,
 ProcInfo,
 CallChain
 FROM dedup(query={
 SELECT *
 FROM delay(query=Track, delay=5)
 },
 key="DedupKey",
 timeout=2)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.IncorrectPermissions</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.incorrectpermissions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.incorrectpermissions/</guid><description>&lt;p&gt;NOTE: Requires velociraptor 0.7.1 or higher. – Alternatively, import the
artifact dependency Linux.Sys.Groups manually into your installation.&lt;/p&gt;
&lt;p&gt;This artifacts checks a number of files and directories to verify whether
they have the expected owner, group owner and mode. A file with an incorrect
owner may allow attackers to modify important system files. Similarly,
incorrect mode, like word-writable configuration or passwd/shadow files may
also be signs of serious misconfiguration or signs of malicious activity.&lt;/p&gt;
&lt;p&gt;The parameter FilesToInspect contains lines of globs to search for. Each
line may specify expected user, expected group, expected file mode and
expected directory mode. It is very important that the order of the lines
is in order of increasing specificity. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csv"&gt;/etc/*,root,root,644,755
/etc/?shadow*,,shadow,640,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, every file in the directory /etc is expected to be owned by root:root
and have file permissions set to 644, and group permissions set to 755.
The files under /etc matching &amp;ldquo;?shadow*&amp;rdquo; are still expected to be owned by
root, since the override for user is empty, but the group is no longer
expected to be &amp;ldquo;root&amp;rdquo;, but &amp;ldquo;shadow&amp;rdquo;. File permissions should be &amp;ldquo;640&amp;rdquo;
instead of &amp;ldquo;644&amp;rdquo;. Note that this is an example and will most likely return
hits, since a number of files in /etc have different owners and modes.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;User&amp;rdquo; may either be an integer (UID) or a string (username). &amp;ldquo;Group&amp;rdquo;
may be either an integer (GID) or a string (group name). The names for all
UIDs and GIDs are looked up and displayed along with their IDs in the result.&lt;/p&gt;
&lt;p&gt;Modes may be specified in either octal numbers or strings.&lt;/p&gt;
&lt;p&gt;Modes specified in octal numbers, e.g. 755, 640, 1777, are matched
using a regular expression, so that both &amp;ldquo;0640&amp;rdquo;, &amp;ldquo;640&amp;rdquo; and &amp;ldquo;100640&amp;rdquo; matches
&amp;ldquo;100640&amp;rdquo;. An implicit anchor, &amp;lsquo;$&amp;rsquo;, is used to match against the end of the
octal mode string.&lt;/p&gt;
&lt;p&gt;When using mode strings (NumericMode unchecked), modes take the format
&amp;ldquo;-rwx-r-x-r-x&amp;rdquo;. Regex comparison is used, and an implicit &amp;lsquo;$&amp;rsquo; anchor
is inserted at the end of the string. String modes allows for verifying only
certain bits of permissions, like ensuring that only the owner has write
access, no one has permission to execute, but read access is not important:
&amp;ldquo;r.-.&amp;ndash;.&amp;ndash;&amp;rdquo;. Or ensuring that SUID/GUID is not set. For finding files
specifically with SUID set, look at Linux.Sys.SUID.&lt;/p&gt;
&lt;p&gt;Mixing both formats is not supported and will result in unexpected results.&lt;/p&gt;
&lt;p&gt;This artifact can also be used to look for all files owned by root with
world-writable permissions, for instance. Uncheck NumericMode, add a glob,
select &amp;ldquo;root&amp;rdquo; as owner and enter any invalid permission string in UserMode.
This will return every file owned by root. In the notebook, add something
like &amp;ldquo;WHERE Mode=~&amp;lsquo;w.$&amp;rsquo;&amp;rdquo; to the query. The User field may also be empty,
essentially returning every file in the glob as long as the UserMode field
contains an invalid value. This turns this artifact into a file finder-like
tool with metadata like username and group names for further processing.&lt;/p&gt;
&lt;p&gt;The following columns are returned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSPath&lt;/li&gt;
&lt;li&gt;IsDir&lt;/li&gt;
&lt;li&gt;UID&lt;/li&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;li&gt;EUser (expected user from FilesToInspect)&lt;/li&gt;
&lt;li&gt;GID&lt;/li&gt;
&lt;li&gt;Group&lt;/li&gt;
&lt;li&gt;EGroup (expected group from FilesToInspect)&lt;/li&gt;
&lt;li&gt;Mode (file/directory mode/permissions)&lt;/li&gt;
&lt;li&gt;EMode (expected file/directory mode from FilesToInspect)&lt;/li&gt;
&lt;li&gt;Mismatch (a comma-separated string of one or several of &amp;ldquo;uid&amp;rdquo;, &amp;ldquo;gid&amp;rdquo; and &amp;ldquo;mode&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Mtime&lt;/li&gt;
&lt;li&gt;Ctime&lt;/li&gt;
&lt;li&gt;Atime&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that the artifacts used to look up usernames and group names use the
files /etc/passwd and /etc/group. You will have to modify this artifact to
use &lt;code&gt;getent passwd&lt;/code&gt;/&lt;code&gt;getent group&lt;/code&gt; to use NSS and get users and groups from
Active Directory etc.&lt;/p&gt;
&lt;p&gt;The provided default values in FilesToInspect is an example only.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.IncorrectPermissions
author: Andreas Misje – @misje
description: |
 NOTE: Requires velociraptor 0.7.1 or higher. – Alternatively, import the
 artifact dependency Linux.Sys.Groups manually into your installation.

 This artifacts checks a number of files and directories to verify whether
 they have the expected owner, group owner and mode. A file with an incorrect
 owner may allow attackers to modify important system files. Similarly,
 incorrect mode, like word-writable configuration or passwd/shadow files may
 also be signs of serious misconfiguration or signs of malicious activity.

 The parameter FilesToInspect contains lines of globs to search for. Each
 line may specify expected user, expected group, expected file mode and
 expected directory mode. It is very important that the order of the lines
 is in order of increasing specificity. For example:

 ```csv
 /etc/*,root,root,644,755
 /etc/?shadow*,,shadow,640,
 ```

 Here, every file in the directory /etc is expected to be owned by root:root
 and have file permissions set to 644, and group permissions set to 755.
 The files under /etc matching "?shadow*" are still expected to be owned by
 root, since the override for user is empty, but the group is no longer
 expected to be "root", but "shadow". File permissions should be "640"
 instead of "644". Note that this is an example and will most likely return
 hits, since a number of files in /etc have different owners and modes.

 "User" may either be an integer (UID) or a string (username). "Group"
 may be either an integer (GID) or a string (group name). The names for all
 UIDs and GIDs are looked up and displayed along with their IDs in the result.

 Modes may be specified in either octal numbers or strings.

 Modes specified in octal numbers, e.g. 755, 640, 1777, are matched
 using a regular expression, so that both "0640", "640" and "100640" matches
 "100640". An implicit anchor, '$', is used to match against the end of the
 octal mode string.

 When using mode strings (NumericMode unchecked), modes take the format
 "-rwx-r-x-r-x". Regex comparison is used, and an implicit '$' anchor
 is inserted at the end of the string. String modes allows for verifying only
 certain bits of permissions, like ensuring that only the owner has write 
 access, no one has permission to execute, but read access is not important:
 "r.-.--.--". Or ensuring that SUID/GUID is not set. For finding files
 specifically with SUID set, look at Linux.Sys.SUID.

 Mixing both formats is not supported and will result in unexpected results.

 This artifact can also be used to look for all files owned by root with
 world-writable permissions, for instance. Uncheck NumericMode, add a glob,
 select "root" as owner and enter any invalid permission string in UserMode.
 This will return every file owned by root. In the notebook, add something
 like "WHERE Mode=~'w.$'" to the query. The User field may also be empty,
 essentially returning every file in the glob as long as the UserMode field
 contains an invalid value. This turns this artifact into a file finder-like
 tool with metadata like username and group names for further processing.

 The following columns are returned:

 - OSPath
 - IsDir
 - UID
 - User
 - EUser (expected user from FilesToInspect)
 - GID
 - Group
 - EGroup (expected group from FilesToInspect)
 - Mode (file/directory mode/permissions)
 - EMode (expected file/directory mode from FilesToInspect)
 - Mismatch (a comma-separated string of one or several of "uid", "gid" and "mode")
 - Mtime
 - Ctime
 - Atime

 Note that the artifacts used to look up usernames and group names use the
 files /etc/passwd and /etc/group. You will have to modify this artifact to
 use `getent passwd`/`getent group` to use NSS and get users and groups from
 Active Directory etc.

 The provided default values in FilesToInspect is an example only.

parameters:
 - name: FilesToInspect
 type: csv
 default: |
 Globs,User,Group,FileMode,DirMode
 /etc/passwd?,root,root,644,
 /etc/?shadow?,root,shadow,640,
 /etc/group?,root,root,,
 description: The files to investigate. The default is just an example.
 - name: NumericMode
 type: bool
 default: true
 description: |
 Whether modes should be interpreted, compared and presented as octal
 numbers (e.g. 640) rather than strings (e.g. -rw-rw-r--)
 - name: IncludeDirs
 type: bool
 description: Include directories
 - name: FollowLinks
 type: bool
 description: Inlcude all symlinks, even though they may interfere with the results

precondition: |
 SELECT OS From info() WHERE OS = 'linux'

sources:
 - name: Discrepancies
 query: |
 /* Passwd/group will be looked up a lot. Make it efficient: */
 LET Users &amp;lt;= memoize(query={
 SELECT int(int=Uid) AS UID, User FROM Artifact.Linux.Sys.Users()
 }, key='UID')
 LET Groups &amp;lt;= memoize(query={
 SELECT GID, Group FROM Artifact.Linux.Sys.Groups()
 }, key='GID')

 LET FindUser(uid) = get(item=Users, field=uid).User
 LET FindGroup(gid) = get(item=Groups, field=gid).Group
 LET StrIf(str) = if(condition=str, then=str(str=str))

 LET Files = SELECT OSPath, IsDir, ModeString,
 /* If the globs are specified in the correct order, picking the
 last item will get a correct override behaviour: */
 /* Filter out all empty strings and keep integers: */
 filter(list=enumerate(items=User), regex='.+')[-1] AS EUser,
 filter(list=enumerate(items=Group), regex='.+')[-1] AS EGroup,
 filter(list=enumerate(items=FileMode), regex='.+')[-1] AS FMode,
 filter(list=enumerate(items=DirMode), regex='.+')[-1] AS DMode
 /* globs() can of course take a list of globs, like FilesToInspect.Globs,
 but by using that approach, we would no longer be able to tie
 User, Group etc. to the individual globs: */
 FROM foreach(row={
 SELECT Globs AS _Globs, * FROM FilesToInspect
 }, query={
 SELECT OSPath, IsDir, User, Group, FileMode, DirMode,
 Mode.String AS ModeString
 FROM glob(globs=_Globs)
 WHERE (IncludeDirs OR NOT IsDir) AND (NOT IsLink OR FollowLinks)
 })
 GROUP BY OSPath

 LET FilesInfo = SELECT * FROM foreach(row=Files, async=true, query={
 SELECT OSPath, Sys.Uid AS UID, Sys.Gid AS GID, if(condition=NumericMode,
 then=format(format='%o', args=[Sys.Mode]), else=ModeString)
 AS Mode, Mtime, Atime, Ctime, EUser, EGroup, log(message='%v, %v, %v', args=[Sys.Mode, ModeString, FMode]), StrIf(str=FMode) AS FMode,
 StrIf(str=DMode) AS DMode, IsDir
 FROM stat(filename=OSPath)
 })
 GROUP BY OSPath

 LET _UIDFiltered = SELECT OSPath, IsDir,
 UID,
 EUser,
 GID, FindGroup(gid=GID) AS Group,
 null AS EGroup,
 'uid' AS Mismatch,
 Mode,
 null AS EMode,
 Mtime, Atime, Ctime,
 get(item=Users, field=UID) AS _u
 FROM FilesInfo
 WHERE EUser AND _u.UID=UID AND
 /* User can be either an ID or a string: */
 if(condition=EUser=~'^\\d+$', then=EUser!=UID,
 else=EUser!=_u.User)

 LET _GIDFiltered = SELECT OSPath, IsDir,
 UID, FindUser(uid=UID) AS User,
 EUser,
 GID,
 EGroup,
 'gid' AS Mismatch,
 Mode,
 null AS EMode,
 Mtime, Atime, Ctime,
 get(item=Groups, field=GID) AS _g
 FROM FilesInfo
 WHERE EGroup AND _g.GID=GID AND
 if(condition=EGroup=~'^\\d+$', then=EGroup!=GID,
 else=EGroup!=_g.Group)

 LET _FileModeFiltered = SELECT OSPath, IsDir,
 UID, FindUser(uid=UID) AS User,
 EUser,
 GID, FindGroup(gid=GID) AS Group,
 EGroup,
 'mode' AS Mismatch,
 Mode,
 FMode AS EMode,
 Mtime, Atime, Ctime
 FROM FilesInfo
 WHERE NOT IsDir AND FMode AND NOT Mode=~FMode+'$'

 LET _DirModeFiltered = SELECT OSPath, IsDir,
 UID, FindUser(uid=UID) AS User,
 EUser,
 GID, FindGroup(gid=GID) AS Group,
 EGroup,
 'mode' AS Mismatch,
 Mode,
 DMode AS EMode,
 Mtime, Atime, Ctime
 FROM FilesInfo
 WHERE IsDir AND DMode AND NOT Mode=~DMode+'$'

 SELECT OSPath, IsDir, UID, User, EUser, GID, Group, EGroup, Mode, EMode,
 join(array=enumerate(items=Mismatch), sep=',') AS Mismatch,
 Mtime, Atime, Ctime
 FROM chain(a={
 SELECT OSPath, IsDir, UID, _u.User AS User, EUser,
 GID, Group, EGroup, Mode, EMode,
 join(array=enumerate(items=Mismatch), sep=',') AS Mismatch,
 Mtime, Atime, Ctime
 FROM _UIDFiltered
 GROUP BY OSPath
 }, b={
 SELECT OSPath, IsDir, UID, User, EUser, GID, _g.Group AS Group,
 EGroup, Mode, EMode,
 join(array=enumerate(items=Mismatch), sep=',') AS Mismatch,
 Mtime, Atime, Ctime
 FROM _GIDFiltered
 GROUP BY OSPath
 }, c={
 SELECT OSPath, IsDir, UID, User, EUser, GID, Group, EGroup, Mode, EMode,
 join(array=enumerate(items=Mismatch), sep=',') AS Mismatch,
 Mtime, Atime, Ctime
 FROM _FileModeFiltered
 GROUP BY OSPath
 }, d={
 SELECT OSPath, IsDir, UID, User, EUser, GID, Group, EGroup, Mode, EMode,
 join(array=enumerate(items=Mismatch), sep=',') AS Mismatch,
 Mtime, Atime, Ctime
 FROM _DirModeFiltered
 GROUP BY OSPath
 })
 GROUP BY OSPath
 ORDER BY OSPath

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.MemFD</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.memfd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.memfd/</guid><description>&lt;p&gt;This artifact will parse /proc/*/exe files and look for processes
that have been executed from memory via memfd_create()&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.MemFD
author: alternate
description: |
 This artifact will parse /proc/*/exe files and look for processes 
 that have been executed from memory via memfd_create()

reference: 
 - https://github.com/4ltern4te/velociraptor-contrib/blob/main/Linux.Detection.MemFD/README.md

type: CLIENT

precondition: SELECT OS From info() where OS = "linux"

parameters:
 - name: FileNameGlob
 description: Glob pattern to search
 default: "/proc/*/exe"
 type: str

 - name: SearchRegex
 description: Pattern to match looking for memfd executions
 default: ^\/memfd:.*?\(deleted\)
 type: regex

sources:
- name: findMemFD
 query: |
 SELECT * FROM glob(globs=FileNameGlob, accessor='file') WHERE Data.Link =~ SearchRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.SSHKeyFileCmd</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.sshkeyfilecmd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.sshkeyfilecmd/</guid><description>&lt;p&gt;This artifact will parse ~/.ssh/authorized_keys and ~/.ssh/id_*.pub looking for the command option
to detect potential persistence&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.SSHKeyFileCmd
author: alternate
description: |
 This artifact will parse ~/.ssh/authorized_keys and ~/.ssh/id_*.pub looking for the command option
 to detect potential persistence


reference: 
 - https://github.com/4ltern4te/velociraptor-contrib/blob/main/Linux.Detection.SSHKeyFileCmd/README.md
 - https://blog.thc.org/infecting-ssh-public-keys-with-backdoors
 - https://man.openbsd.org/OpenBSD-current/man8/sshd.8#AUTHORIZED_KEYS_FILE_FORMAT

type: CLIENT

precondition: SELECT OS From info() where OS = "linux"

parameters:
 - name: SSHKeyFilesGlob
 default: |
 ["/{root,home/*}/.ssh/authorized_keys","/{root,home/*}/.ssh/authorized_keys2","/{root,home/*}/.ssh/*.pub"]

 - name: CommandRegex
 description: Command option regex
 default: (?P&amp;lt;CMD&amp;gt;command=".*?")
 type: regex

sources:
 - name: findSSHAuthKeyCmd
 query: |
 LET files = SELECT OSPath FROM glob(globs=parse_json_array(data=SSHKeyFilesGlob))
 SELECT OSPath, CMD FROM foreach(
 row=files,
 query={
 SELECT OSPath, CMD FROM parse_records_with_regex(file=OSPath, regex=CommandRegex)
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Detection.vRealizeLogInsightExploitation</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.vrealizeloginsightexploitation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.detection.vrealizeloginsightexploitation/</guid><description>&lt;p&gt;Checks for exploitation of vRealize Log Insight VMSA-2023-0001 exploitation
artifacts. The presence of a path traversal in the FileName field
is evidence of compromise. There is still a path to exploitation without
leveraging the path traversal vuln. Any attempt to run
REMOTE_PAK_DOWNLOAD_COMMAND from a non-vRealize server is malicious.
#VMWare #vRealize #exploit&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Detection.vRealizeLogInsightExploitation
author: ACEResponder.com
description: |
 Checks for exploitation of vRealize Log Insight VMSA-2023-0001 exploitation 
 artifacts. The presence of a path traversal in the FileName field
 is evidence of compromise. There is still a path to exploitation without
 leveraging the path traversal vuln. Any attempt to run
 REMOTE_PAK_DOWNLOAD_COMMAND from a non-vRealize server is malicious.
 #VMWare #vRealize #exploit

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

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

 query: |
 -- Get runtime.log
 Let lines = SELECT split(string=Data,sep='\\r?\\n|\\r') as List
 FROM read_file(filenames="/var/log/loginsight/runtime.log")
 -- Get REMOTE_PAK_DOWNLOAD_COMMAND matches.

 LET results = SELECT * FROM foreach(row=lines,
 query={
 SELECT parse_string_with_regex(
 string=_value,
 regex=[
 "^\\[(?P&amp;lt;Time&amp;gt;[^\\]]+)\\].*REMOTE_PAK_DOWNLOAD_COMMAND.*requestUrl:(?P&amp;lt;RequestUrl&amp;gt;[^,]+), fileName:(?P&amp;lt;FileName&amp;gt;[^\)]+).*$"
 ]) as Record
 FROM foreach(row=List)
 WHERE _value
 AND _value =~ ".*REMOTE_PAK_DOWNLOAD_COMMAND.*"
 })
 -- output rows
 SELECT 
 Record.Time AS Time,
 Record.RequestUrl AS RequestUrl,
 Record.FileName AS FileName
 FROM results

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Event.Network.Nethogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.event.network.nethogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.event.network.nethogs/</guid><description>&lt;p&gt;Monitor network use per process using the tool &amp;ldquo;nethogs&amp;rdquo;. This artifact will
list all processes that produces (non-local) network traffic on the client.
The NetstatEnriched artifact is used to provide detailed information about the
process using netstat and the process tracker, along with the bytes received
and sent in bytes per second.&lt;/p&gt;
&lt;p&gt;Note that the tool/package &amp;ldquo;nethogs&amp;rdquo; needs to be installed before calling this
artifact. Set the paramater InstallNethogs to true in order to automatically
install the package and its dependencies (Debian-based systems only).&lt;/p&gt;
&lt;p&gt;Using techniques like stacking, rare occurances of processes contacting the
Internet can be spotted. Notebook suggestions give you total traffic overview,
as well as boilerplate code to plot the traffic for a selected process.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Event.Network.Nethogs
author: 'Andreas Misje - @misje'
type: CLIENT_EVENT
description: |
 Monitor network use per process using the tool "nethogs". This artifact will
 list all processes that produces (non-local) network traffic on the client.
 The NetstatEnriched artifact is used to provide detailed information about the
 process using netstat and the process tracker, along with the bytes received
 and sent in bytes per second.

 Note that the tool/package "nethogs" needs to be installed before calling this
 artifact. Set the paramater InstallNethogs to true in order to automatically
 install the package and its dependencies (Debian-based systems only).

 Using techniques like stacking, rare occurances of processes contacting the
 Internet can be spotted. Notebook suggestions give you total traffic overview,
 as well as boilerplate code to plot the traffic for a selected process.

parameters:
 - name: InstallNethogs
 description: Install nethogs using apt-get
 type: bool
 default: false

 - name: NetstatCachePeriod
 description: Number of seconds to cache netstat data
 type: int
 default: 10

 - name: ProcessRegex
 description: |
 Only look for processes whose name / command line matches this regex
 type: regex
 default: .+

 - name: PIDRegex
 description: |
 Only look for processes whose PID matches this regex
 type: regex
 default: .+

 - name: UIDRegex
 description: |
 Only look for processes whose owner ID (UID) matches this regex
 type: regex
 default: .+

precondition:
 SELECT * FROM info() where OS = 'linux'

sources:
 - query: |
 LET Hoggers = SELECT Timestamp,
 Process,
 int(int=PID) AS PID,
 UID,
 parse_float(string=Sent) AS Sent,
 parse_float(string=Recv) AS Recv
 FROM foreach(
 row={
 SELECT *
 FROM execve(argv=['/usr/sbin/nethogs', '-t', '-C'],
 length=10000,
 sep='\n\nRefreshing:\n')
 },
 query={
 SELECT timestamp(epoch=now()) AS Timestamp,
 *
 FROM parse_records_with_regex(
 accessor='data',
 file=Stdout,
 regex='''^\s*(?P&amp;lt;Process&amp;gt;[^\t]+)/(?P&amp;lt;PID&amp;gt;\d+)/(?P&amp;lt;UID&amp;gt;\d+)\t(?P&amp;lt;Sent&amp;gt;[^\t]+)\t(?P&amp;lt;Recv&amp;gt;\S+)''')
 WHERE Process =~ ProcessRegex
 AND PID =~ PIDRegex
 AND UID =~ UIDRegex
 })

 LET Netstat &amp;lt;= memoize(
 name='netstat',
 key='Pid',
 period=NetstatCachePeriod,
 query={
 SELECT *
 FROM Artifact.Linux.Network.NetstatEnriched()
 })

 LET Result = SELECT *
 FROM foreach(
 row={
 SELECT *
 FROM Hoggers
 },
 query={
 SELECT *
 FROM foreach(
 row={
 SELECT 
 dict(
 Timestamp=Timestamp,
 Process=Process,
 PID=PID,
 UID=UID,
 Sent=Sent,
 Recv=Recv,
 ProcInfo=dict(
 CommandLine=NULL,
 Username=NULL,
 StartTime=NULL)) + (get(
 item=Netstat,
 field=PID) || dict(
 Name=NULL,
 Laddr=NULL,
 Lport=NULL,
 Raddr=NULL,
 Rport=NULL,
 Status=NULL,
 ProcInfo=dict(),
 CallChain=NULL,
 ChildrenTree=NULL)) AS Contents
 FROM scope()
 WHERE Contents
 },
 column='Contents')
 })

 // Leverage the InstallDeb utility to do the actual package install:
 LET InstallDeps = SELECT *
 FROM if(
 condition=InstallNethogs,
 then={
 SELECT *
 FROM Artifact.Linux.Utils.InstallDeb(DebName='nethogs')
 })

 SELECT *
 FROM chain(a_install=InstallDeps,
 b_result=Result)

 notebook:
 - type: vql
 name: Traffic
 template: |
 // Modify these to adjust the time frame:
 // LET StartTime &amp;lt;= '2024-01-01T00:00:00Z'
 // LET EndTimeTime &amp;lt;= '2024-01-01T00:00:00Z'
 /*
 # Network traffic

 {{ $TimeRange := Query "SELECT StartTime, EndTime FROM scope()" | Expand }}
 Network traffic (in bytes per second) between {{ Get $TimeRange "0.StartTime" }}
 and {{ Get $TimeRange "0.EndTime" }}
 */
 LET ColumnTypes = dict(
 _ChildrenTree='tree')
 
 SELECT 
 Timestamp,
 PID,
 ProcInfo.Name || Process AS Name,
 ProcInfo.CommandLine AS CmdLine,
 ProcInfo.Username AS Username,
 ProcInfo.StartTime AS StartTime,
 Laddr,
 Lport,
 Raddr,
 Rport,
 Status,
 humanize(
 bytes=Sent * 1024) AS Sent,
 humanize(
 bytes=Recv * 1024) AS Recv,
 ProcInfo AS _ProcInfo,
 CallChain AS _CalLChain,
 ChildrenTree AS _ChildrenTree
 FROM source(start_time=StartTime,
 end_time=EndTime)
 LIMIT 50

 - type: vql_suggestion
 name: Total traffic
 template: |
 // Modify these to adjust the time frame:
 // LET StartTime &amp;lt;= '2024-01-01T00:00:00Z'
 // LET EndTimeTime &amp;lt;= '2024-01-01T00:00:00Z'
 /*
 # Network traffic summary

 {{ $TimeRange := Query "SELECT StartTime, EndTime FROM scope()" | Expand }}
 This is a **rough estimate** of the total bytes sent and received between
 {{ Get $TimeRange "0.StartTime" }} and {{ Get $TimeRange "0.EndTime" }}.
 */
 LET Summary = SELECT 
 PID,
 ProcInfo.Name || Process AS Name,
 ProcInfo.CommandLine AS CommandLine,
 ProcInfo.Username AS Username,
 ProcInfo.StartTime AS StartTime,
 // nethogs -t outputs a data rate every second. Adding these
 // values give us a rough estimate of the data transferred
 sum(
 item=Sent * 1024) AS Sent,
 sum(
 item=Recv * 1024) AS Recv
 FROM source(start_time=StartTime,
 end_time=EndTime)
 GROUP BY PID, Name
 
 SELECT *,
 humanize(
 bytes=Sent) AS Sent,
 humanize(
 bytes=Recv) AS Recv,
 humanize(
 bytes=Recv + Sent) AS Total
 FROM Summary
 LIMIT 50

 - type: vql_suggestion
 name: Plot traffic for PID
 template: |
 // Modify these to adjust the time frame:
 // LET StartTime &amp;lt;= '2024-01-01T00:00:00Z'
 // LET EndTimeTime &amp;lt;= '2024-01-01T00:00:00Z'
 // The process whose traffic to plot:
 LET PIDTarget = 1234

 /*
 {{ $Vars := Query "SELECT PIDTarget, StartTime, EndTime FROM scope()" | Expand }}
 # Network traffic for PID {{ Get $Vars "0.PIDTarget" }}

 Network traffic (in bytes per second) between {{ Get $Vars "0.StartTime" }}
 and {{ Get $Vars "0.EndTime" }}
 */
 LET SinglePSStats = SELECT 
 Timestamp.Unix AS Timestamp,
 Sent * 1024 AS Sent,
 Recv * 1024 AS Recv
 FROM source(start_time=StartTime,
 end_time=EndTime)
 WHERE PID = PIDTarget
 LIMIT 50

 /*
 {{ Query "SELECT * FROM SinglePSStats" | TimeChart }}
 */

 // We do not really need this, but we need to execute some VQL
 // in order for the plot to appear:
 SELECT *
 FROM SinglePSStats
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Events.EBPFEnriched</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.events.ebpfenriched/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.events.ebpfenriched/</guid><description>&lt;p&gt;This artifact forwards EBPF events generated on the endpoint and enriches events with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process details (CommandLine, ParentImage, etc.)&lt;/li&gt;
&lt;li&gt;Docker container details (ContainerName, ContainerImage, Usernames, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Requires Linux.Events.TrackProcesses (process tracker), and docker v29+ for hashing of executables and username enrichment in docker containers.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Events.EBPFEnriched
author: Zane Gittins
description: |
 This artifact forwards EBPF events generated on the endpoint and enriches events with:
 
 * Process details (CommandLine, ParentImage, etc.)
 * Docker container details (ContainerName, ContainerImage, Usernames, etc.)
 
 Requires Linux.Events.TrackProcesses (process tracker), and docker v29+ for hashing of executables and username enrichment in docker containers.

type: CLIENT_EVENT

parameters:
 - name: Events
 description: Events to forward
 type: csv
 default: |
 Event,Desc,Enabled
 bpf_attach,A bpf program is attached,N
 chdir,Process changes directory,N
 fchownat,File ownership is changed,Y
 file_modification,A process changes the ctime of a file,N
 kill,Kill another process,N
 magic_write,Intercepts file writes to capture the header magic,Y
 mkdir,Process makes new directory,N
 module_free,A module is unloaded from the kernel,Y
 mount,A filesystem is mounted,Y
 openat,A process is opening a file (noisy),N
 openat2,A process is opening a file (noisy),N
 sched_process_exec,A process starts,Y
 sched_process_exit,A process ends,N
 security_file_open,Files are opened,N
 security_inode_mknod,A new node is created with mknod (e.g. fifo or device file),Y
 security_inode_rename,File is being renamed,N
 security_inode_symlink,Create a symlink,Y
 security_kernel_post_read_file,Fires when the kernel reads a file (e.g. module),Y
 security_socket_accept,A process accepted a connection,Y
 security_socket_bind,A process bind to a local port,Y
 security_socket_connect,A process is making a connection,Y
 setxattr,Setting and extended attribute to a file,Y
 umount2,A filesystem is being unmounted,Y
 unlink,A file is deleted,N
 net_packet_dns,DNS network traffic,Y
 net_packet_http_request,http requests,N
 ptrace,abused for process injection,Y
 process_vm_writev,abused for process injection,Y
 - name: Exclusions
 description: Granular event exclusion rules for EventData fields.
 type: csv
 default: |
 Event,Reason,FieldName,ExclusionRegex
 magic_write,Noisy,pathname,.(txt|cmrk2|cmrk4|pid|json|procs|bin|dblwr)$
 magic_write,Noisy,pathname,^/sys/fs/cgroup/
 security_socket_connect,Noisy,remote_addr.sa_family,AF_UNIX
 net_packet_dns,SLD Queries,proto_dns.questions.name,^[^.]*$
 - name: DockerEnrich
 description: |
 If enabled, we attempt to enrich events from docker containers.
 type: bool
 default: True
 - name: DockerAPIEndpoint
 description: |
 Docker API endpoint to retrieve container details.
 type: string
 default: "/var/run/docker.sock:unix/containers/json"
 - name: HashOnExecution
 description: |
 Calculate hashes on process execution (sched_process_exec).
 type: bool
 default: True
 - name: BufferSize
 description: |
 Size of buffer used to delay events for enrichment. Larger buffer size increases enrichment chance, but also memory usage.
 default: 5000
 type: int64
 - name: EnrichmentDelay
 description: | 
 Number of seconds to delay enriching events to increase chance they are in the process tracker.
 type: int64
 default: 5

export: |
 // Get hostname from info, as ebpf also has container names.
 LET ComputerName &amp;lt;= dict(H={ SELECT Hostname FROM info() }).H[0].Hostname
 
 // Get paths to /etc/passwd from client and docker containers using overlayfs. Used to enrich events with username.
 LET AllPasswdPaths = SELECT
 OSPath
 FROM glob(
 globs=["/var/lib/docker/rootfs/overlayfs/*/etc/passwd", "/etc/passwd"])
 
 // Get 12 character container id or computer name. We truncate ComputerName at 15 chars for matching on System.HostName (UtsName(16 chars) - null byte)
 LET GetName(Path) = if(
 condition=(Path =~ "docker"),
 then=parse_string_with_regex(
 regex="\\/(?&amp;lt;ContainerID&amp;gt;[a-z0-9]{12})",
 string=Path).ContainerID,
 else=ComputerName[:15])
 
 // Enrich usernames from /etc/passwd
 LET UsernameLookup &amp;lt;= memoize(key="CombinedID",
 query={
 SELECT *
 FROM foreach(row=AllPasswdPaths,
 query={
 SELECT User AS Username,
 atoi(string=Uid) AS UserID,
 GetName(Path=OSPath) + Uid AS CombinedID
 FROM split_records(
 filenames=OSPath,
 regex=":",
 record_regex="\r?\n",
 columns=["User", "X", "Uid", "Gid", "Description", "Homedir", "Shell"])
 })
 },
 period=120)
 
 // Get hash of a file on host or in docker container via overlayfs
 LET get_hash_cache(OSPath, HostName, IsContainer) =
 if(condition=(HostName
 AND IsContainer),
 then=hash(path=("/var/lib/docker/rootfs/overlayfs/" +
 HostName + OSPath),
 hashselect=["SHA256"]).SHA256,
 else=hash(path=OSPath, hashselect=["SHA256"]).SHA256)
 
 // Parse Exclusions
 LET ExclusionRules &amp;lt;= SELECT *
 FROM Exclusions
 
 // Function to check if an event should be excluded
 LET ShouldExclude(EventName, EventData) = len(
 list=array(_={
 SELECT *
 FROM foreach(row=ExclusionRules)
 WHERE Event = EventName
 AND get(item=EventData, member=FieldName) =~ ExclusionRegex
 LIMIT 1
 })) &amp;gt; 0
 
 // Communicate with docker API to get all running containers
 LET data = SELECT parse_json_array(data=Content) AS Containers
 FROM http_client(url=DockerAPIEndpoint)
 
 LET ContainerLookup &amp;lt;= memoize(key="ContainerID",
 query={
 SELECT format(format="%.12s", args=Id) AS ContainerID,
 Id AS FullContainerID,
 join(array=Names, sep=", ") AS ContainerName,
 Image AS ContainerImage,
 State AS ContainerState,
 Status AS ContainerStatus,
 timestamp(epoch=Created) AS ContainerCreated
 FROM foreach(row=data, query={ SELECT * FROM foreach(row=Containers) })
 },
 period=30)
 
 // Get detailed process information for all events
 LET GetProcInfo(EventData, Tracker, pTracker) = dict(
 Image=Tracker.Data.Exe || EventData.cmdpath ||
 System.ProcessName,
 ImageName=System.ProcessName,
 CommandLine=Tracker.Data.CommandLine || join(array=EventData.argv, sep=" "),
 ParentImage=pTracker.Data.Exe,
 ParentCommandLine=pTracker.Data.CommandLine,
 CreateTime=timestamp(
 epoch=EventData.ctime) || System.ThreadStartTime,
 CallChain=join(
 array=process_tracker_callchain(
 id=System.HostProcessID).Data.Name,
 sep="-&amp;gt;"),
 TrackerHit=if(
 condition=Tracker != NULL,
 then=true,
 else=false))

sources:
 - precondition:
 SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") &amp;gt;= 0
 query: |
 // Comsume only process execution events.
 LET SelectedEvents &amp;lt;= SELECT *
 FROM Events
 WHERE Enabled =~ "Y"
 AND Event = "sched_process_exec"
 
 // Primary event loop, we exclude our own pid and evaluate exclusion rules.
 LET Logs = SELECT timestamp(epoch=now()) AS Timestamp,
 *,
 System.HostProcessID != System.ProcessID AS IsContainer
 FROM watch_ebpf(events=SelectedEvents.Event)
 WHERE System.HostProcessID != getpid()
 AND System.HostParentProcessID != getpid()
 AND NOT ShouldExclude(EventName=System.EventName, EventData=EventData)
 
 SELECT
 ComputerName,
 System,
 EventData,
 GetProcInfo(EventData=EventData,
 Tracker=process_tracker_get(id=System.HostProcessID),
 pTracker=process_tracker_get(id=System.HostParentProcessID)) AS ProcInfo,
 IsContainer,
 get(
 item=UsernameLookup,
 field=(System.HostName + str(
 str=System.UserID))).Username AS Username,
 if(
 condition=(IsContainer
 AND DockerEnrich),
 then=get(
 item=ContainerLookup,
 field=System.HostName)) AS ContainerEnrich,
 if(
 condition=(System.EventName = "sched_process_exec"
 AND HashOnExecution),
 then=cache(
 period=300,
 func=get_hash_cache(
 OSPath=EventData.pathname,
 HostName=get(
 item=ContainerLookup,
 field=System.HostName).FullContainerID,
 IsContainer=IsContainer),
 // Cache on dev (device id) + inode, this strategy saves cpu on containers using same overlayfs
 key=str(
 str=EventData.dev) + "-" + str(
 str=EventData.inode))) AS Hash
 FROM delay(
 query={
 SELECT
 *
 FROM Logs
 },
 delay=EnrichmentDelay,
 buffer_size=BufferSize)
 - precondition:
 SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") &amp;gt;= 0
 query: |
 // Comsume only process injection events, which can be very bursty.
 LET SelectedEvents &amp;lt;= SELECT *
 FROM Events
 WHERE Enabled =~ "Y"
 AND Event =~ "^(ptrace|process_vm_writev)"
 
 // Primary event loop, we exclude our own pid and evaluate exclusion rules.
 LET Logs = SELECT timestamp(epoch=now()) AS Timestamp,
 *,
 System.HostProcessID != System.ProcessID AS IsContainer,
 System.HostProcessID AS ProcessID
 FROM watch_ebpf(events=SelectedEvents.Event)
 WHERE System.HostProcessID != getpid()
 AND System.HostParentProcessID != getpid()
 AND NOT ShouldExclude(EventName=System.EventName, EventData=EventData)
 
 SELECT
 ComputerName,
 System,
 EventData,
 GetProcInfo(EventData=EventData,
 Tracker=process_tracker_get(id=System.HostProcessID),
 pTracker=process_tracker_get(id=System.HostParentProcessID)) AS ProcInfo,
 IsContainer,
 get(
 item=UsernameLookup,
 field=(System.HostName + str(
 str=System.UserID))).Username AS Username,
 if(
 condition=(IsContainer
 AND DockerEnrich),
 then=get(
 item=ContainerLookup,
 field=System.HostName)) AS ContainerEnrich
 FROM dedup(
 query={
 SELECT
 *
 FROM Logs
 },
 key="ProcessID",
 size=BufferSize)
 - precondition:
 SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") &amp;gt;= 0
 query: |
 // Comsume only security_socket_connect, which can be very bursty.
 LET SelectedEvents &amp;lt;= SELECT *
 FROM Events
 WHERE Enabled =~ "Y"
 AND Event =~ "^(security_socket_connect)"
 
 // Primary event loop, we exclude our own pid and evaluate exclusion rules.
 LET Logs = SELECT timestamp(epoch=now()) AS Timestamp,
 *,
 System.HostProcessID != System.ProcessID AS IsContainer,
 (str(str=System.HostProcessID) +
 EventData.remote_addr.sin_addr +
 EventData.remote_addr.sin_port +
 EventData.remote_addr.sa_family) AS DedupKey
 FROM watch_ebpf(events=SelectedEvents.Event)
 WHERE System.HostProcessID != getpid()
 AND System.HostParentProcessID != getpid()
 AND NOT ShouldExclude(EventName=System.EventName, EventData=EventData)
 
 SELECT
 ComputerName,
 System,
 EventData,
 GetProcInfo(EventData=EventData,
 Tracker=process_tracker_get(id=System.HostProcessID),
 pTracker=process_tracker_get(id=System.HostParentProcessID)) AS ProcInfo,
 IsContainer,
 get(
 item=UsernameLookup,
 field=(System.HostName + str(
 str=System.UserID))).Username AS Username,
 if(
 condition=(IsContainer
 AND DockerEnrich),
 then=get(
 item=ContainerLookup,
 field=System.HostName)) AS ContainerEnrich
 FROM dedup(
 query={
 SELECT
 *
 FROM Logs
 },
 key="DedupKey",
 size=BufferSize)
 - precondition:
 SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") &amp;gt;= 0
 query: |
 // Default catch all consumer for events that are not handled in other sources.
 LET SelectedEvents &amp;lt;= SELECT *
 FROM Events
 WHERE Enabled =~ "Y"
 AND NOT Event =~ "^(sched_process_exec|security_socket_connect|ptrace|process_vm_writev)"
 
 // Primary event loop, we exclude our own pid and evaluate exclusion rules.
 LET Logs = SELECT timestamp(epoch=now()) AS Timestamp,
 *,
 System.HostProcessID != System.ProcessID AS IsContainer
 FROM watch_ebpf(events=SelectedEvents.Event)
 WHERE System.HostProcessID != getpid()
 AND System.HostParentProcessID != getpid()
 AND NOT ShouldExclude(EventName=System.EventName, EventData=EventData)
 
 SELECT
 ComputerName,
 System,
 EventData,
 GetProcInfo(EventData=EventData,
 Tracker=process_tracker_get(id=System.HostProcessID),
 pTracker=process_tracker_get(id=System.HostParentProcessID)) AS ProcInfo,
 IsContainer,
 get(
 item=UsernameLookup,
 field=(System.HostName + str(
 str=System.UserID))).Username AS Username,
 if(
 condition=(IsContainer
 AND DockerEnrich),
 then=get(
 item=ContainerLookup,
 field=System.HostName)) AS ContainerEnrich
 FROM delay(
 query={
 SELECT
 *
 FROM Logs
 },
 delay=(EnrichmentDelay + 5),
 buffer_size=BufferSize)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.ExtractKthread</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.kthread/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.collection.kthread/</guid><description>&lt;p&gt;This artifact parses &lt;code&gt;/proc/[0-9]*/status&lt;/code&gt; files and extracts the &lt;code&gt;ProcessName&lt;/code&gt; and &lt;code&gt;Kthread&lt;/code&gt; values. Helpful for identifying imposter processes.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.ExtractKthread
author: Andy Swift
description: |
 This artifact parses `/proc/[0-9]*/status` files and extracts the `ProcessName` and `Kthread` values. Helpful for identifying imposter processes.

type: CLIENT

precondition: SELECT OS FROM info() WHERE OS = "linux"

parameters:
 - name: FileNameGlob
 description: Glob pattern to search for process status files.
 default: "/proc/[0-9]*/status"
 type: str

sources:
- name: extractKthread
 query: |
 LET FileInfos &amp;lt;= SELECT OSPath, read_file(filename=OSPath) AS content
 FROM glob(globs=FileNameGlob, accessor='file')
 WHERE content =~ 'Kthread:\\s*(\\d+)'

 LET ParsedInfos &amp;lt;= SELECT OSPath,
 parse_string_with_regex(
 string=content,
 regex=[
 '^Name:\\s*(?P&amp;lt;Name&amp;gt;.+)',
 'Kthread:\\s*(?P&amp;lt;KthreadValue&amp;gt;\\d+)'
 ]
 ) AS ParsedContent
 FROM FileInfos

 SELECT OSPath,
 ParsedContent.Name AS ProcessName,
 ParsedContent.KthreadValue AS Kthread
 FROM ParsedInfos

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Forensics.EnvironmentVariables</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.environmentvariables/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.environmentvariables/</guid><description>&lt;p&gt;This artifact detects potential persistence mechanisms on Linux systems by analyzing environment variable files and login scripts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MITRE ATT&amp;amp;CK&lt;/strong&gt;: &lt;a href="https://attack.mitre.org/techniques/T1546/004/" target="_blank" &gt;T1546.004&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Forensics.EnvironmentVariables
author: Idan Beit-Yosef @ ibyf0r3ns1cs
description: |
 This artifact detects potential persistence mechanisms on Linux systems by analyzing environment variable files and login scripts. 
 
 **MITRE ATT&amp;amp;CK**: [T1546.004](https://attack.mitre.org/techniques/T1546/004/)

reference:
 - https://unit42.paloaltonetworks.com/unit42-new-iotlinux-malware-targets-dvrs-forms-botnet/
 - https://intezer.com/blog/research/kaiji-new-chinese-linux-malware-turning-to-golang/
 - https://www.anomali.com/blog/illicit-cryptomining-threat-actor-rocke-changes-tactics-now-more-difficult-to-detect
 - https://www.anomali.com/blog/pulling-linux-rabbit-rabbot-malware-out-of-a-hat
 - https://blog.sucuri.net/2018/05/shell-logins-as-a-magento-reinfection-vector.html

parameters:
 - name: LinuxEnvGlobs
 type: csv
 default: |
 Glob
 /home/*/.bashrc
 /home/*/.bash_profile
 /home/*/.bash_login
 /home/*/.profile
 /home/*/.zshrc
 /etc/profile
 /etc/environment
 /home/*/.bash_logout
 
 - name: LoginScriptGlobs
 type: csv
 default: |
 Glob
 /etc/profile.d/*.sh
 
 - name: LinuxEnvModifiers
 default: ^(export|alias)
 type: regex
 
 - name: LinuxEnvNetworkUtils
 default: wget|curl|scp|ssh|nc\s|/usr/bin/nc\s|/bin/nc\s|https?://[^\s]*
 type: regex
 
 - name: LinuxEnvScripting
 default: python|perl|ruby|php|base64
 type: regex
 
precondition: SELECT OS From info() where OS = 'linux'

sources:
 - name: ModifierDetection
 query: |
 LET EnvFiles = SELECT OSPath FROM glob(globs=LinuxEnvGlobs.Glob)
 SELECT * FROM foreach(row=EnvFiles,
 query={
 SELECT Line, OSPath FROM parse_lines(filename=OSPath)
 WHERE
 Line =~ LinuxEnvModifiers
 })

 - name: NetworkUtilsDetection
 query: |
 LET EnvFiles = SELECT OSPath FROM glob(globs=LinuxEnvGlobs.Glob)
 SELECT * FROM foreach(row=EnvFiles,
 query={
 SELECT Line, OSPath FROM parse_lines(filename=OSPath)
 WHERE
 Line =~ LinuxEnvNetworkUtils
 })
 
 - name: ScriptingDetection
 query: |
 LET EnvFiles = SELECT OSPath FROM glob(globs=LinuxEnvGlobs.Glob)
 SELECT * FROM foreach(row=EnvFiles,
 query={
 SELECT Line, OSPath FROM parse_lines(filename=OSPath)
 WHERE
 Line =~ LinuxEnvScripting
 })
 
 - name: LoginScriptsDetection
 query: |
 SELECT OSPath,upload(file=OSPath) AS Upload FROM glob(globs=LoginScriptGlobs.Glob)

 
column_types:
- name: Upload
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Forensics.ProcFD</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.procfd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.procfd/</guid><description>&lt;p&gt;This artifact collects metadata about open file descriptors from active processes on a Linux system.
Outputs include regular files, sockets, device files, and deleted files used by each process.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Forensics.ProcFD
author: Chris DiSalle - @chrisdfir
description: |
 This artifact collects metadata about open file descriptors from active processes on a Linux system. 
 Outputs include regular files, sockets, device files, and deleted files used by each process.
 
reference:
 - https://sandflysecurity.com/blog/investigating-linux-process-file-descriptors-for-incident-response-and-forensics/
 - https://fareedfauzi.github.io/2024/03/29/Linux-Forensics-cheatsheet.html#review-processes
 
type: CLIENT

precondition: SELECT OS From info() where OS = 'linux'

sources:
 - name: RegularFiles
 query: |
 LET open_fds &amp;lt;= SELECT
 OSPath,
 OSPath[1] AS PID,
 Data.Link AS FilePath,
 Mtime,
 Atime,
 Ctime,
 Btime,
 read_file(filename="/proc/" + OSPath[1] + "/comm") AS ParentCommand,
 read_file(filename="/proc/" + OSPath[1] + "/cmdline") AS ParentCmdLine,
 read_file(filename="/proc/" + OSPath[1] + "/loginuid") AS LoginUID,
 format(format="%o", args=[Mode]) AS OctalMode,
 Mode.String AS StringMode
 FROM glob(globs="/proc/*/fd/*")
 
 SELECT
 OSPath AS FDPath,
 FilePath AS FDLink,
 ParentCmdLine AS ProcessCmdLine,
 ParentCommand AS Process,
 LoginUID,
 Mtime,
 Atime,
 Ctime,
 Btime,
 OctalMode,
 StringMode
 FROM open_fds
 WHERE FilePath =~ "^/" AND NOT FilePath =~ "^/dev/"

 - name: Sockets
 query: |
 SELECT
 OSPath AS FDPath,
 FilePath AS FDLink,
 ParentCmdLine AS ProcessCmdLine,
 ParentCommand AS Process,
 LoginUID,
 Mtime,
 Atime,
 Ctime,
 Btime,
 OctalMode,
 StringMode
 FROM open_fds
 WHERE FilePath =~ "socket:"

 - name: DeviceFiles
 query: |
 SELECT
 OSPath AS FDPath,
 FilePath AS FDLink,
 ParentCmdLine AS ProcessCmdLine,
 ParentCommand AS Process,
 LoginUID,
 Mtime,
 Atime,
 Ctime,
 Btime,
 OctalMode,
 StringMode
 FROM open_fds
 WHERE FilePath =~ "^/dev/"

 - name: DeletedFiles
 query: |
 SELECT
 OSPath AS FDPath,
 FilePath AS FDLink,
 ParentCmdLine AS ProcessCmdLine,
 ParentCommand AS Process,
 LoginUID,
 Mtime,
 Atime,
 Ctime,
 Btime,
 OctalMode,
 StringMode
 FROM open_fds
 WHERE FilePath =~ "deleted"

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Forensics.RecentlyUsed</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.recentlyused/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.recentlyused/</guid><description>&lt;p&gt;Parses the &amp;lsquo;recently-used.xbel&amp;rsquo; XML file for all standard Linux users.&lt;/p&gt;
&lt;p&gt;This file notably records a list of recent files accessed by applications and is also an alternative source for download history.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Forensics.RecentlyUsed
description: |
 Parses the 'recently-used.xbel' XML file for all standard Linux users.
 
 This file notably records a list of recent files accessed by applications and is also an alternative source for download history.

author: Deepak Sharma - @rxurien

type: CLIENT

precondition: SELECT OS From info() where OS = 'linux'

parameters:
 - name: RecentsFile
 default: '.local/share/recently-used.xbel'
 
sources:
 - name: Recent Entries
 query: |
 LET ParseBookmarks = SELECT * from foreach(
 row={
 SELECT Uid, User, Homedir from Artifact.Linux.Sys.Users()
 },
 query={
 SELECT FullPath, Mtime, Ctime, User, Uid
 FROM glob(
 globs=RecentsFile,
 root=Homedir)
 })

 SELECT * from foreach(
 row=ParseBookmarks,
 query={
 SELECT 
 User,
 Uid as UID,
 _value.Attrhref as FilePath,
 _value.Attradded as TimeAdded,
 _value.Attrmodified as TimeModified,
 _value.Attrvisited as TimeVisited,
 _value.info.metadata.`mime-type`.Attrtype as MimeType,
 _value.info.metadata.applications.application.Attrname as ApplicationName,
 _value.info.metadata.applications.application.Attrexec as ApplicationExec,
 _value.info.metadata.applications.application.Attrmodified as ApplicationModTime,
 _value.info.metadata.applications.application.Attrcount as ApplicationCount,
 FullPath as SourceFile
 FROM items(item=parse_xml(file=FullPath).xbel.bookmark)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Forensics.Targets</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.targets/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.forensics.targets/</guid><description>&lt;p&gt;This artifact collects all necessary artifacts files and directories from Linux operating system.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Forensics.Targets
author: Cedric MAURUGEON - @kidrek
description: |
 This artifact collects all necessary artifacts files and directories from Linux operating system. 
 
reference:
 - https://github.com/ForensicArtifacts/artifacts/blob/main/artifacts/data/linux.yaml

parameters:
 - name: BootTargets
 type: csv
 default: |
 Glob
 /boot/grub/grub.cfg
 /boot/grub2/grub.cfg
 /boot/initramfs*
 /boot/initrd*
 /etc/init.d/**
 /etc/insserv.conf
 /etc/insserv.conf.d/**

 - name: CertificateTargets
 type: csv
 default: |
 Glob
 /etc/ca-certificates.conf
 /etc/ssl/certs/ca-certificates.crt
 /usr/share/ca-certificates/**
 /usr/local/share/ca-certificates/**

 - name: CronTargets
 type: csv
 default: |
 Glob
 /etc/anacrontab
 /etc/at.allow
 /etc/at.deny
 /etc/cron.allow
 /etc/cron.d/**
 /etc/cron.daily/**
 /etc/cron.deny
 /etc/cron.hourly/**
 /etc/cron.monthly/**
 /etc/cron.weekly/**
 /etc/crontab
 /var/at/tabs/**
 /var/spool/anacron/cron.*
 /var/spool/at/**
 /var/spool/cron/**

 - name: LogTargets
 type: csv
 default: |
 Glob
 /etc/rsyslog.conf
 /etc/rsyslog.d/**
 /var/log/apache2/**
 /var/log/apt/history.log*
 /var/log/apt/term.log*
 /var/log/auth*
 /var/log/cron.log*
 /var/log/daemon*
 /var/log/journal/**
 /var/log/kern*
 /var/log/lastlog
 /var/log/mail*
 /var/log/messages*
 /var/log/secure*
 /var/log/syslog*
 /var/log/nginx/**
 /var/log/ufw.log*

 - name: NetworkTargets
 type: csv
 default: |
 Glob
 /etc/netplan/*.yaml
 /etc/network/if-up.d/**
 /etc/network/if-down.d/**
 /etc/network/interfaces
 /etc/resolv.conf
 /etc/default/ufw
 /etc/ufw/sysctl.conf
 /etc/ufw/*.rules
 /etc/ufw/applications.d/**

 - name: PackageTargets
 type: csv
 default: |
 Glob
 /etc/apt/sources.list
 /etc/apt/sources.list.d/*
 /etc/apt/trusted.gpg
 /etc/apt/trusted.gpg.d/*
 /etc/apt/trustdb.gpg
 /etc/yum.conf
 /etc/yum.repos.d/*.repo
 /usr/share/keyrings/*
 /var/lib/dpkg/status

 - name: ServiceTargets
 type: csv
 default: |
 Glob
 /etc/systemd/system.control/*.timer
 /etc/systemd/systemd.attached/*.timer
 /etc/systemd/system/*.timer
 /etc/systemd/user/*.timer
 /lib/systemd/system/*.timer
 /lib/systemd/user/*.timer
 /run/systemd/generator.early/*.timer
 /run/systemd/generator.late/*.timer
 /run/systemd/generator/*.timer
 /run/systemd/system.control/*.timer
 /run/systemd/systemd.attached/*.timer
 /run/systemd/system/*.timer
 /run/systemd/transient/*.timer
 /run/systemd/user/*.timer
 /run/user/*/systemd/generator.early/*.timer
 /run/user/*/systemd/generator.late/*.timer
 /run/user/*/systemd/generator/*.timer
 /run/user/*/systemd/transient/*.timer
 /run/user/*/systemd/user.control/*.timer
 /run/user/*/systemd/user/*.timer
 /usr/lib/systemd/system/*.timer
 /usr/lib/systemd/user/*.timer
 /home/*/.config/systemd/user.control/*.timer
 /home/*/.config/systemd/user/*.timer
 /home/*/.local/share/systemd/user/*.timer
 /root/.config/systemd/user.control/*.timer
 /root/.config/systemd/user/*.timer
 /root/.local/share/systemd/user/*.timer
 /etc/systemd/system.control/*.service
 /etc/systemd/systemd.attached/*.service
 /etc/systemd/system/*.service
 /etc/systemd/user/*.service
 /lib/systemd/system/*.service
 /lib/systemd/user/*.service
 /run/systemd/generator.early/*.service
 /run/systemd/generator.late/*.service
 /run/systemd/generator/*.service
 /run/systemd/system.control/*.service
 /run/systemd/systemd.attached/*.service
 /run/systemd/system/*.service
 /run/systemd/transient/*.service
 /run/systemd/user/*.service
 /run/user/*/systemd/generator.early/*.service
 /run/user/*/systemd/generator.late/*.service
 /run/user/*/systemd/generator/*.service
 /run/user/*/systemd/transient/*.service
 /run/user/*/systemd/user.control/*.service
 /run/user/*/systemd/user/*.service
 /usr/lib/systemd/system/*.service
 /usr/lib/systemd/user/*.service
 /home/*/.config/systemd/user.control/*.service
 /home/*/.config/systemd/user/*.service
 /home/*/.local/share/systemd/user/*.service
 /root/.config/systemd/user.control/*.service
 /root/.config/systemd/user/*.service
 /root/.local/share/systemd/user/*.service


 - name: SystemTargets
 type: csv
 default: |
 Glob
 /dev/shm/**
 /etc/fstab
 /etc/hostname
 /etc/issue
 /etc/issue.net
 /etc/ld.so.preload
 /etc/localtime
 /etc/ntp.conf
 /etc/modprobe.d/*
 /etc/modules.conf
 /etc/ssh/**
 /etc/timezone
 /etc/udev/rules.d/*
 /usr/lib/udev/rules.d/*

 - name: SystemVersionTargets
 type: csv
 default: |
 Glob
 /etc/debian_version
 /etc/centos-release
 /etc/enterprise-release
 /etc/oracle-release
 /etc/redhat-release
 /etc/rocky-release
 /etc/SuSE-release
 /etc/system-release
 /etc/lsb-release
 /etc/os-release
 /usr/lib/os-release

 - name: UserTargets
 type: csv
 default: |
 Glob
 /etc/passwd
 /etc/shadow
 /etc/sudoers
 /etc/sudoers.d/**
 /etc/group
 /home/*/.config/mozilla/**
 /home/*/snap/firefox/common/.mozilla/**
 /home/*/.config/google-chrome/**
 /home/*/snap/chromium/common/chromium/Default/**
 /home/*/.aliases
 /home/*/.profile
 /home/*/.*_history
 /home/*/.*rc
 /home/*/.ssh/*
 /home/*/.wget-hsts
 /root/.config/mozilla/**
 /root/snap/firefox/common/.mozilla/**
 /root/.config/google-chrome/**
 /root/snap/chromium/common/chromium/Default/**
 /root/.aliases
 /root/.profile
 /root/.*_history
 /root/.*rc
 /root/.ssh/*
 /root/.wget-hsts

precondition: SELECT OS From info() where OS = 'linux'

sources:
 - name: BootTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=BootTargets.Glob)

 - name: CertificateTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=CertificateTargets.Glob)

 - name: CronTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=CronTargets.Glob)

 - name: LogTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=LogTargets.Glob)

 - name: NetworkTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=NetworkTargets.Glob)

 - name: PackageTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=PackageTargets.Glob)

 - name: ServiceTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=ServiceTargets.Glob)

 - name: SystemTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=SystemTargets.Glob)

 - name: SystemVersionTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=SystemVersionTargets.Glob)

 - name: UserTargets
 query: |
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM glob(globs=UserTargets.Glob)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.LogAnalysis.ChopChopGo</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.loganalysis.chopchopgo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.loganalysis.chopchopgo/</guid><description>&lt;p&gt;This artifact leverages ChopChopGo to enable usage of Sigma rules to faciliate detection within Linux logs.&lt;/p&gt;
&lt;p&gt;From the project&amp;rsquo;s description:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ChopChopGo inspired by Chainsaw utilizes Sigma rules for forensics artifact recovery, enabling rapid and comprehensive analysis of logs and other artifacts to identify potential security incidents and threats on Linux.&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.LogAnalysis.ChopChopGo
description: |

 This artifact leverages ChopChopGo to enable usage of Sigma rules to faciliate detection within Linux logs.
 
 From the project's description:
 
 `ChopChopGo inspired by Chainsaw utilizes Sigma rules for forensics artifact recovery, enabling rapid and comprehensive analysis of logs and other artifacts to identify potential security incidents and threats on Linux.`
 
reference:
 - https://github.com/M00NLIG7/ChopChopGo

author: Wes Lambert - @therealwlambert, @weslambert@infosec.exchange
tools:
 - name: ChopChopGo
 url: https://github.com/M00NLIG7/ChopChopGo/releases/download/v1.0.0-beta-3/ChopChopGo_v1.0.0-beta-3.zip
 
precondition: SELECT OS From info() where OS = 'linux'

parameters: 
 - name: ExecLength
 description: Size (in bytes) of output that will be returned for a single row for execve(). This value may need to be adjusted depending on the size of your event logs.
 type: int
 default: "100000000"
 
 - name: Rules
 description: Sigma rules to use for detection 
 type: string
 default: /ChopChopGo/rules/linux/builtin/syslog/
 
 - name: Target 
 description: Refers to the type of data you woud like to analyze. For example, `journald` or `syslog`.
 type: string
 default: syslog
 
sources:
 - query: |
 LET Toolzip &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="ChopChopGo", IsExecutable=FALSE)
 LET TmpDir &amp;lt;= tempdir()
 LET TmpResults &amp;lt;= tempfile()
 LET UnzipIt &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)
 LET SigmaRules &amp;lt;= TmpDir + Rules
 LET ExecCCG &amp;lt;= SELECT * FROM execve(argv=[
 TmpDir + '/ChopChopGo/ChopChopGo',
 "-rules", SigmaRules,
 "-target", Target,
 "-out", "json"], length=ExecLength)
 SELECT *
 FROM foreach(
 row=ExecCCG, 
 query={
 SELECT 
 Timestamp,
 Title,
 Message AS Message,
 Tags,
 Author,
 ID
 FROM parse_json_array(data=Stdout)})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Memory.AVML</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.memory.avml/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.memory.avml/</guid><description>&lt;p&gt;Acquires a full memory image in LiME output format. We download
avml and use it to acquire a full memory image.
NOTE: This artifact usually transfers a lot of data. You should
increase the default timeout to allow it to complete.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Memory.AVML
author: Zawadi Done - @zawadidone
description: |
 Acquires a full memory image in LiME output format. We download
 avml and use it to acquire a full memory image.
 NOTE: This artifact usually transfers a lot of data. You should
 increase the default timeout to allow it to complete.

required_permissions:
 - EXECVE

tools:
 - name: avml
 github_project: microsoft/avml
 github_asset_regex: avml
 serve_locally: true

precondition: SELECT OS From info() where OS = 'linux' AND Architecture = "amd64"

sources:
 - query: |
 SELECT * FROM foreach(
 row={
 SELECT OSPath, tempfile(extension=".lime", remove_last=TRUE) AS Tempfile 
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="avml")
 },
 query={
 SELECT Stdout, Stderr,
 if(condition=Complete, then=upload(file=Tempfile, name="memory.lime")) As Upload
 FROM execve(argv=[OSPath, Tempfile], sep="\r\n")
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Network.Nethogs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.nethogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.nethogs/</guid><description>&lt;p&gt;Monitor network use per process using the tool &amp;ldquo;nethogs&amp;rdquo;. This artifact will
list all processes that produces (non-local) network traffic on the client.
The NetstatEnriched artifact is used to provide detailed information about the
process using netstat and the process tracker, along with the bytes received
and sent in bytes per second.&lt;/p&gt;
&lt;p&gt;Note that the tool/package &amp;ldquo;nethogs&amp;rdquo; needs to be installed before calling this
artifact. Set the parameter InstallNethogs to true in order to automatically
install the package and its dependencies (Debian-based systems only).&lt;/p&gt;
&lt;p&gt;Using techniques like stacking, rare occurances of processes contacting the
Internet can be spotted. Notebook suggestions give you total traffic overview,
as well as boilerplate code to plot the traffic for a selected process.&lt;/p&gt;
&lt;p&gt;Also see Linux.Event.Network.Nethogs for a nethogs event artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Network.Nethogs
author: 'Andreas Misje - @misje'
description: |
 Monitor network use per process using the tool "nethogs". This artifact will
 list all processes that produces (non-local) network traffic on the client.
 The NetstatEnriched artifact is used to provide detailed information about the
 process using netstat and the process tracker, along with the bytes received
 and sent in bytes per second.

 Note that the tool/package "nethogs" needs to be installed before calling this
 artifact. Set the parameter InstallNethogs to true in order to automatically
 install the package and its dependencies (Debian-based systems only).

 Using techniques like stacking, rare occurances of processes contacting the
 Internet can be spotted. Notebook suggestions give you total traffic overview,
 as well as boilerplate code to plot the traffic for a selected process.

 Also see Linux.Event.Network.Nethogs for a nethogs event artifact.

parameters:
 - name: InstallNethogs
 description: Install nethogs using apt-get
 type: bool
 default: false

 - name: Duration
 type: int
 description: Number of seconds to monitor processes
 default: 300

 - name: NetstatCachePeriod
 description: Number of seconds to cache netstat data
 type: int
 default: 10

 - name: ProcessRegex
 description: |
 Only look for processes whose name / command line matches this regex
 type: regex
 default: .+

 - name: PIDRegex
 description: |
 Only look for processes whose PID matches this regex
 type: regex
 default: .+

 - name: UIDRegex
 description: |
 Only look for processes whose owner ID (UID) matches this regex
 type: regex
 default: .+

precondition:
 SELECT * FROM info() where OS = 'linux'

sources:
 - query: |
 LET Hoggers = SELECT Timestamp,
 Process,
 int(int=PID) AS PID,
 UID,
 parse_float(string=Sent) AS Sent,
 parse_float(string=Recv) AS Recv
 FROM query(
 timeout=Duration,
 inherit=true,
 query={
 SELECT *
 FROM foreach(
 row={
 SELECT *
 FROM execve(argv=['/usr/sbin/nethogs', '-t', '-C'],
 length=10000,
 sep='\n\nRefreshing:\n')
 },
 query={
 SELECT timestamp(epoch=now()) AS Timestamp,
 *
 FROM parse_records_with_regex(
 accessor='data',
 file=Stdout,
 regex='''^\s*(?P&amp;lt;Process&amp;gt;[^\t]+)/(?P&amp;lt;PID&amp;gt;\d+)/(?P&amp;lt;UID&amp;gt;\d+)\t(?P&amp;lt;Sent&amp;gt;[^\t]+)\t(?P&amp;lt;Recv&amp;gt;\S+)''')
 WHERE Process =~ ProcessRegex
 AND PID =~ PIDRegex
 AND UID =~ UIDRegex
 })
 })

 LET Netstat &amp;lt;= memoize(
 name='netstat',
 key='Pid',
 period=NetstatCachePeriod,
 query={
 SELECT *
 FROM Artifact.Linux.Network.NetstatEnriched()
 })

 LET Result = SELECT *
 FROM foreach(
 row={
 SELECT *
 FROM Hoggers
 },
 query={
 SELECT *
 FROM foreach(
 row={
 SELECT 
 dict(
 Timestamp=Timestamp,
 Process=Process,
 PID=PID,
 UID=UID,
 Sent=Sent,
 Recv=Recv,
 ProcInfo=dict(
 CommandLine=NULL,
 Username=NULL,
 StartTime=NULL)) + (get(
 item=Netstat,
 field=PID) || dict(
 Name=NULL,
 Laddr=NULL,
 Lport=NULL,
 Raddr=NULL,
 Rport=NULL,
 Status=NULL,
 ProcInfo=dict(),
 CallChain=NULL,
 ChildrenTree=NULL)) AS Contents
 FROM scope()
 WHERE Contents
 },
 column='Contents')
 })

 // Leverage the InstallDeb utility to do the actual package install:
 LET InstallDeps = SELECT *
 FROM if(
 condition=InstallNethogs,
 then={
 SELECT *
 FROM Artifact.Linux.Utils.InstallDeb(DebName='nethogs')
 })

 SELECT *
 FROM chain(a_install=InstallDeps,
 b_result=Result)

 notebook:
 - type: vql
 name: Traffic
 template: |
 /*
 # Network traffic

 {{ $TimeRange := Query "SELECT min(item=Timestamp) AS StartTime, max(item=Timestamp) AS EndTime FROM source() GROUP BY 1" | Expand }}
 Network traffic (in bytes per second) between {{ Get $TimeRange "0.StartTime" }}
 and {{ Get $TimeRange "0.EndTime" }}
 */
 LET ColumnTypes = dict(
 _ChildrenTree='tree')

 SELECT 
 Timestamp,
 PID,
 ProcInfo.Name || Process AS Name,
 ProcInfo.CommandLine AS CmdLine,
 ProcInfo.Username AS Username,
 ProcInfo.StartTime AS StartTime,
 Laddr,
 Lport,
 Raddr,
 Rport,
 Status,
 humanize(
 bytes=Sent * 1024) AS Sent,
 humanize(
 bytes=Recv * 1024) AS Recv,
 ProcInfo AS _ProcInfo,
 CallChain AS _CalLChain,
 ChildrenTree AS _ChildrenTree
 FROM source()
 LIMIT 50

 - type: vql_suggestion
 name: Total traffic
 template: |
 /*
 # Network traffic summary

 {{ $TimeRange := Query "SELECT min(item=Timestamp) AS StartTime, max(item=Timestamp) AS EndTime FROM source() GROUP BY 1" | Expand }}
 This is a **rough estimate** of the total bytes sent and received between
 {{ Get $TimeRange "0.StartTime" }} and {{ Get $TimeRange "0.EndTime" }}.
 */
 LET Summary = SELECT 
 PID,
 ProcInfo.Name || Process AS Name,
 ProcInfo.CommandLine AS CommandLine,
 ProcInfo.Username AS Username,
 ProcInfo.StartTime AS StartTime,
 // nethogs -t outputs a data rate every second. Adding these
 // values give us a rough estimate of the data transferred
 sum(
 item=Sent * 1024) AS Sent,
 sum(
 item=Recv * 1024) AS Recv
 FROM source()
 GROUP BY PID, Name

 SELECT *,
 humanize(
 bytes=Sent) AS Sent,
 humanize(
 bytes=Recv) AS Recv,
 humanize(
 bytes=Recv + Sent) AS Total
 FROM Summary
 LIMIT 50

 - type: vql_suggestion
 name: Plot traffic for PID
 template: |
 // The process whose traffic to plot:
 LET PIDTarget = 1234

 /*
 {{ $Vars := Query "SELECT PIDTarget, min(item=Timestamp) AS StartTime, max(item=Timestamp) AS EndTime FROM source() GROUP BY 1" | Expand }}
 # Network traffic for PID {{ Get $Vars "0.PIDTarget" }}

 Network traffic (in bytes per second) between {{ Get $Vars "0.StartTime" }}
 and {{ Get $Vars "0.EndTime" }}
 */
 LET SinglePSStats = SELECT 
 Timestamp.Unix AS Timestamp,
 Sent * 1024 AS Sent,
 Recv * 1024 AS Recv
 FROM source()
 WHERE PID = PIDTarget
 LIMIT 50

 /*
 {{ Query "SELECT * FROM SinglePSStats" | TimeChart }}
 */

 // We do not really need this, but we need to execute some VQL
 // in order for the plot to appear:
 SELECT *
 FROM SinglePSStats
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Network.Netstat.Watcher</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.netstat.watcher/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.netstat.watcher/</guid><description>&lt;p&gt;Collects a one-time snapshot of current non-LISTEN remote connections and a continuous diff stream of added/removed/changed connections. Loopback destinations are excluded by default (127.0.0.1 and ::1) via a configurable regex. The sampling interval (SampleIntervalSec) and the overall monitoring window (MonitorDurationSec) are fully parameterized. Each record includes process metadata via process_tracker_get&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Network.Netstat.Watcher
type: CLIENT
author: Antonio Blescia (TheThMando)
description: &amp;gt;
 Collects a one-time snapshot of current non-LISTEN remote connections and a continuous diff stream of added/removed/changed connections. Loopback destinations are excluded by default (127.0.0.1 and ::1) via a configurable regex. 
 The sampling interval (SampleIntervalSec) and the overall monitoring window (MonitorDurationSec) are fully parameterized. Each record includes process metadata via process_tracker_get
implied_permissions:
 - IMPERSONATION
parameters:
 - name: SampleIntervalSec
 description: Sampling interval in seconds used by diff() while monitoring connections.
 type: int
 default: 60
 - name: MonitorDurationSec
 type: int
 description: Total monitoring window in seconds; the outer query stops after this duration.
 default: 600
 - name: ExcludeRemoteIPsRegex
 type: regex
 description: Regex of remote IPs to exclude (matched against Raddr.IP).
 default: '127.0.0.1|::1'

sources:
 - name: RemoteConnectionsSnapshot
 query: |
 SELECT timestamp(epoch=now()) AS now_utc,
 Pid,
 Status,
 FamilyString,
 Laddr,
 Raddr,
 process_tracker_get(id=Pid) AS ProcInfo
 FROM netstat()
 WHERE Status != "LISTEN"
 and NOT Raddr.IP =~ ExcludeRemoteIPsRegex


 - name: RemoteConnectionsDiffMonitor
 query: |
 SELECT *
 FROM query(query={
 SELECT timestamp(epoch=now()) AS now_utc,
 Diff,
 Timestamp,
 Pid,
 Status,
 FamilyString,
 Laddr,
 Raddr,
 process_tracker_get(id=Pid) AS ProcInfo
 FROM diff(query={
 SELECT Timestamp,
 Pid,
 Status,
 FamilyString,
 Laddr,
 Raddr,
 format(format="%d|%s|%s|%s:%d|%s:%d",
 args=[Pid, L3, L4, Laddr.IP, Laddr.Port,
 Raddr.IP, Raddr.Port]) AS DiffKey
 FROM netstat()
 WHERE Status != "LISTEN"
 and NOT Raddr.IP =~ ExcludeRemoteIPsRegex
 },
 key="DiffKey",
 period=SampleIntervalSec)
 WHERE Diff =~ "added|removed|changed"
 },
 env=dict(SampleIntervalSec=SampleIntervalSec,
 ExcludeRemoteIPsRegex=ExcludeRemoteIPsRegex),
 timeout=MonitorDurationSec)
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Network.NM.Connections</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.nm.connections/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.network.nm.connections/</guid><description>&lt;p&gt;NetworkManager is a popular high-level interface for configuring
networks in Linux systems, in particular Ubuntu and other Debian-based
flavours. This artifact lists the NetworkManager state, all configured
connections and their settings, as well as when the connections were
last activated. A list of BSSIDs per connection is also retrieved.&lt;/p&gt;
&lt;p&gt;All the information is retrieved from NetworkManager configuration
files and other state files. Connection information is stored in
the /etc/NetworkManager/system-connections as long as the &amp;ldquo;keyfile&amp;rdquo;
plugin is selected in /etc/NetworkManager/NetworkManager.conf (this
is the default). Note that by default, NetworkManager doesn&amp;rsquo;t manage
connections defined in /etc/network/interfaces.&lt;/p&gt;
&lt;p&gt;Whether the connections are currently active is not stored in file
and must be queried using using nmcli or through dbus. This artifact
runs nmcli as an external program to retrieve this information.
Information such as IP addresses, routes, DNS servers, available Wi-Fi
networks and other settings will also be collected through nmcli.&lt;/p&gt;
&lt;p&gt;This artifact also exports two functions, parse_ini(filename) and
parse_ini_as_dict(filename), which may be useful to parse INI files
in other artifacts.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Network.NM.Connections
author: 'Andreas Misje - @misje'
description: |
 NetworkManager is a popular high-level interface for configuring
 networks in Linux systems, in particular Ubuntu and other Debian-based
 flavours. This artifact lists the NetworkManager state, all configured
 connections and their settings, as well as when the connections were
 last activated. A list of BSSIDs per connection is also retrieved.

 All the information is retrieved from NetworkManager configuration
 files and other state files. Connection information is stored in
 the /etc/NetworkManager/system-connections as long as the "keyfile"
 plugin is selected in /etc/NetworkManager/NetworkManager.conf (this
 is the default). Note that by default, NetworkManager doesn't manage
 connections defined in /etc/network/interfaces.

 Whether the connections are currently active is not stored in file
 and must be queried using using nmcli or through dbus. This artifact
 runs nmcli as an external program to retrieve this information.
 Information such as IP addresses, routes, DNS servers, available Wi-Fi
 networks and other settings will also be collected through nmcli.

 This artifact also exports two functions, parse_ini(filename) and
 parse_ini_as_dict(filename), which may be useful to parse INI files
 in other artifacts.

reference:
 - https://developer-old.gnome.org/NetworkManager/stable/nm-settings-keyfile.html
 - https://developer-old.gnome.org/NetworkManager/stable/settings-connection.html
 - https://developer-old.gnome.org/NetworkManager/stable/settings-802-11-wireless.html

type: CLIENT

required_permissions:
 - EXECVE

parameters:
 - name: RedactSecrets
 default: true
 type: bool
 description: |
 Replace Wi-FI PSKs (wifi-security/psk) with "\&amp;lt;REDACTED\&amp;gt;".

export: |
 /* Parse an INI config file and return Section (the part enclosed in '[]' on
 lines of their own), Key and Value. */
 LET parse_ini(filename) = SELECT * FROM foreach(row={
 SELECT * FROM parse_records_with_regex(file=filename,
 regex='''(?m)\[\s*(?P&amp;lt;Section&amp;gt;[^\]]+)\s*\](?P&amp;lt;Contents&amp;gt;[^\[]*)''')
 }, query={
 SELECT Section, Key, Value
 FROM parse_records_with_regex(file=Contents,
 accessor='data',
 regex='^[\s\n]*(?P&amp;lt;Key&amp;gt;[^=]+)=(?P&amp;lt;Value&amp;gt;.*)')
 })

 /* Parse an INI config file and return a single column, Contents, with
 the contents. Section names are prepended to keys, separated by '/'. */
 LET parse_ini_as_dict(filename) = SELECT to_dict(item={
 SELECT lowcase(string=Section + '/' + Key) AS _key, Value AS _value
 FROM parse_ini(filename=filename)
 }) AS Contents
 FROM scope()

column_types:
 - name: LastActivated
 type: timestamp
 description: |
 When the connection was last fully successfully activated. This
 timestamp may be updated periodically while the connection is active.

precondition: |
 SELECT OS FROM info() WHERE OS = 'linux'

sources:
 - name: State
 description: |
 NetworkManager have three states that may be toggled:
 NetworkingEnabled, which disables all networking (managed by
 NetworkManager); WirelessEnabled, which disables wireless networking;
 and WWANEnabled, which disables mobile data connections.
 query: |
 LET State_ = SELECT parse_string_with_regex(string=Data,
 regex=('''NetworkingEnabled=(?P&amp;lt;NetworkingEnabled&amp;gt;\S+)''',
 '''WirelessEnabled=(?P&amp;lt;WirelessEnabled&amp;gt;\S+)''',
 '''WWANEnabled=(?P&amp;lt;WWANEnabled&amp;gt;\S+)''')) AS Fields
 FROM read_file(filenames='/var/lib/NetworkManager/NetworkManager.state')

 LET State = SELECT Fields.NetworkingEnabled AS NetworkingEnabled,
 Fields.WirelessEnabled AS WirelessEnabled,
 Fields.WWANEnabled AS WWANEnabled
 FROM State_

 SELECT * FROM State

 - name: ConnectionConfigs
 description: |
 All connections configured in NetworkManager. Columns returned are
 OSPath and a dict with the connection configuration.
 query: |
 LET ConfiguredConnections &amp;lt;= SELECT * FROM foreach(row={
 SELECT OSPath FROM glob(globs='/etc/NetworkManager/system-connections/*.nmconnection')
 }, query=if(condition=RedactSecrets, then={
 SELECT OSPath,
 Contents + dict(`wifi-security/psk`='&amp;lt;REDACTED&amp;gt;')
 AS Contents
 FROM parse_ini_as_dict(filename=OSPath)
 }, else={
 SELECT *, OSPath FROM parse_ini_as_dict(filename=OSPath)
 })
 )

 SELECT OSPath, Contents FROM ConfiguredConnections

 - name: Connections
 description: |
 Return a handful of useful properties from ConnectionConfigs in a
 more readable table with individual column names: Name, UUID, Type,
 Device and LastActivated. LastActivated are fetched from another
 state file and combined with the results from ConnectionConfigs.
 query: |
 LET Timestamps = SELECT UUID, if(condition=parse_float(string=Timestamp),
 then=timestamp(epoch=Timestamp), else=null) AS Timestamp
 FROM parse_records_with_regex(file='/var/lib/NetworkManager/timestamps',
 regex='''(?P&amp;lt;UUID&amp;gt;[-A-Fa-f0-9]+)+=(?P&amp;lt;Timestamp&amp;gt;\S+)''')

 LET Connections &amp;lt;= SELECT Name, _UUID AS UUID, Type, Device, LastActivated
 FROM foreach(row={
 SELECT * FROM ConfiguredConnections
 }, query={
 SELECT Contents.`connection/id` AS Name,
 Contents.`connection/uuid` AS _UUID,
 Contents.`connection/type` AS Type,
 Contents.`connection/interface-name` AS Device,
 Timestamp AS LastActivated
 FROM Timestamps
 WHERE _UUID=UUID
 })

 SELECT * FROM Connections

 - name: ActiveConnections
 description: |
 Return connections from Connections that are currently active,
 by asking the NetworkManager daemon through the utility "nmcli".
 query: |
 LET nmcli = SELECT Stdout
 FROM execve(argv=['nmcli', '-t', '-f', 'uuid', 'connection', 'show', '--active'])

 LET ActiveConnections = SELECT * FROM foreach(row={
 SELECT * FROM parse_lines(accessor='data',
 filename=nmcli.Stdout)
 }, query={
 SELECT * FROM Connections WHERE UUID=Line
 })

 SELECT * FROM ActiveConnections

 - name: DeviceStatus
 description: |
 Ask NetworkManager through "nmcli" about the status of all network
 interfaces, managed as well unmanaged, with detailed information such
 as IP addresses, routes, MTU and DNS settings.
 query: |
 LET nmcli = SELECT Stdout
 FROM execve(argv=['nmcli', '-t', 'device', 'show'])

 LET DeviceStatus = SELECT * FROM foreach(row=split(sep='\n\n',
 string=nmcli.Stdout), query={
 SELECT parse_string_with_regex(string=_value,
 regex='''GENERAL.DEVICE:(?P&amp;lt;Device&amp;gt;.+)''').Device AS Device,
 to_dict(item={
 SELECT Key AS _key, Value AS _value
 FROM parse_records_with_regex(file=_value, accessor='data',
 regex='^\n?(?P&amp;lt;Key&amp;gt;[^:]+):(?P&amp;lt;Value&amp;gt;.*)')
 }) AS Status
 FROM scope()
 })

 /* We're pretty much done now, but the output could be a lot nicer to
 work with. */

 LET S = scope()
 LET Status &amp;lt;= SELECT * FROM foreach(row={SELECT * FROM DeviceStatus},
 column='Status')

 LET to_array(col, dev) = filter(list=array(a={
 SELECT * FROM column_filter(include=col, query={
 SELECT * FROM Status WHERE `GENERAL.DEVICE` = dev
 })}), condition='x=&amp;gt;x')

 LET prettify_route(col, dev) = SELECT *
 FROM foreach(row=to_array(dev=dev, col=col), query={
 SELECT S.Dest AS Dest, S.NextHop AS NextHop, int(int=S.Metric) AS Metric
 FROM foreach(row={
 SELECT parse_string_with_regex(string=S._value, regex=(
 '''dst\s*=\s*(?P&amp;lt;Dest&amp;gt;[^,]+)''',
 '''nh\s*=\s*(?P&amp;lt;NextHop&amp;gt;[^,]+)''',
 '''mt\s*=\s*(?P&amp;lt;Metric&amp;gt;\d+)''')) AS R
 FROM scope()
 }, column='R')
 })
 WHERE Dest

 SELECT `GENERAL.DEVICE` AS Device,
 S.`GENERAL.TYPE` AS Type,
 S.`GENERAL.CONNECTION` AS Connection,
 S.`GENERAL.STATE` AS State,
 S.`GENERAL.HWADDR` AS Mac,
 S.`GENERAL.MTU` AS MTU,
 to_array(dev=`GENERAL.DEVICE`, col='IP4.ADDRESS') AS Addresses,
 prettify_route(dev=`GENERAL.DEVICE`, col='IP4.ROUTE') AS Routes,
 S.`IP4.GATEWAY` AS Gateway,
 to_array(dev=`GENERAL.DEVICE`, col='IP4.DNS') AS DNSServers,
 to_array(dev=`GENERAL.DEVICE`, col='IP4.DOMAIN') AS DNSDomains,
 to_array(dev=`GENERAL.DEVICE`, col='IP4.SEARCHES') AS DNSSearches,
 to_array(dev=`GENERAL.DEVICE`, col='IP6.ADDRESS') AS _IPv6Addresses,
 prettify_route(dev=`GENERAL.DEVICE`, col='IP6.ROUTE') AS _IPv6Routes,
 S.`IP6.GATEWAY` AS _IPv6Gateway,
 to_array(dev=`GENERAL.DEVICE`, col='IP6.DNS') AS _IPv6DNSServers,
 to_array(dev=`GENERAL.DEVICE`, col='IP6.DOMAIN') AS _IPv6DNSDomains,
 to_array(dev=`GENERAL.DEVICE`, col='IP6.SEARCHES') AS _IPv6DNSSearches
 FROM Status

 - name: AvailableAccessPoints
 description: |
 Ask NetworkManager through "nmcli" about details about all available
 Wi-Fi access points
 query: |
 LET nmcli = SELECT Stdout
 FROM execve(argv=['nmcli', '-t', '-m', 'multiline', '-f',
 'ssid,bssid,mode,chan,freq,rate,signal,security,wpa-flags,rsn-flags,device,active,in-use',
 'device', 'wifi', 'list'])

 LET AccessPoints = SELECT * FROM foreach(row=filter(list=split(sep='\x01\x02',
 /* Separate sections of key–values by injecting a blob and then
 split on that string. nmcli also has a "tabular" output mode,
 but ":", the separator, is also part of the output and is
 "escaped" by "/", making the parsing difficult. */
 string=regex_replace(source=nmcli.Stdout, re='(?m)^IN-USE:.*$',
 replace='$0\x01\x02')), regex='.'), query={

 SELECT to_dict(item={
 SELECT Key AS _key, Value as _value FROM parse_records_with_regex(
 file=_value, accessor='data', regex='^\n?(?P&amp;lt;Key&amp;gt;[^:]+):(?P&amp;lt;Value&amp;gt;.*)')
 }) AS Contents FROM scope() WHERE _value
 })
 WHERE Contents

 SELECT DEVICE AS Device, SSID, BSSID, MODE AS Mode, CHAN AS Chan,
 FREQ AS Freq, RATE AS Rate, SIGNAL AS Signal, SECURITY AS Security,
 ACTIVE='yes' AS Active, `WPA-FLAGS` AS WPAFlags, `RSN-FLAGS` AS RSNFlags,
 `IN-USE`='*' AS InUse
 FROM foreach(row=AccessPoints, column='Contents')

 - name: SeenBSSIDs
 description: |
 A list of BSSIDs (each BSSID formatted as a MAC address like
 "00:11:22:33:44:55") that have been detected as part of the Wi-Fi
 network. NetworkManager internally tracks previously seen BSSIDs.
 query: |
 LET SeenBSSIDs &amp;lt;= SELECT UUID AS _UUID, filter(list=split(sep_string=',', string=BSSIDs),
 regex='.+') AS BSSIDs
 FROM parse_records_with_regex(file='/var/lib/NetworkManager/seen-bssids',
 regex='''(?P&amp;lt;UUID&amp;gt;[-A-Fa-f0-9]+)+=(?P&amp;lt;BSSIDs&amp;gt;\S+)''')

 SELECT * FROM foreach(row=SeenBSSIDs, query={
 SELECT Name, UUID, Device, BSSIDs FROM Connections
 WHERE _UUID=UUID
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Persistence.LdPreload</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ldpreload/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ldpreload/</guid><description>&lt;p&gt;Parses the GNU glibc &lt;strong&gt;LD_PRELOAD&lt;/strong&gt; mechanism. Any path listed in
&lt;code&gt;/etc/ld.so.preload&lt;/code&gt; or assigned to &lt;code&gt;LD_PRELOAD&lt;/code&gt; is force‑loaded into every
dynamically linked executable. A single
rogue entry therefore grants system‑wide code execution and persistence at
process start‑up.&lt;/p&gt;
&lt;p&gt;The artifact has two scopes:&lt;/p&gt;
&lt;p&gt;• Parses &lt;code&gt;/etc/ld.so.preload&lt;/code&gt;&lt;br&gt;
• Checks &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/environ&lt;/code&gt; for an &lt;code&gt;LD_PRELOAD=&lt;/code&gt; entry.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Persistence.LdPreload
author: Matt Green - @mgreen27
description: |
 Parses the GNU glibc **LD_PRELOAD** mechanism. Any path listed in 
 `/etc/ld.so.preload` or assigned to `LD_PRELOAD` is force‑loaded into every 
 dynamically linked executable. A single 
 rogue entry therefore grants system‑wide code execution and persistence at
 process start‑up.
 
 The artifact has two scopes:

 • Parses `/etc/ld.so.preload` 
 • Checks `/proc/&amp;lt;pid&amp;gt;/environ` for an `LD_PRELOAD=` entry.

references:
 - https://attack.mitre.org/techniques/T1574/006/

type: CLIENT

parameters:
 - name: TargetGlob
 default: /etc/ld.so.preload
 - name: ContentRegex
 default: .
 description: Regex to target suspicious content strings.
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'linux' 
 query: |
 SELECT OSPath,
 Mtime,
 Atime,
 Ctime,
 Btime,
 Size,
 read_file(filename=OSPath)[0:5000] AS Content
 FROM glob(globs=TargetGlob)
 WHERE Content =~ ContentRegex

 - name: Environment Variable
 query: |
 LET target_proc = SELECT OSPath,
 parse_string_with_regex(
 regex='''LD_PRELOAD=(?&amp;lt;LD_PRELOAD&amp;gt;[^\x00]+)''',
 string=read_file(filename=OSPath + '/environ')).LD_PRELOAD AS LD_PRELOAD
 FROM glob(
 globs='/proc/[0-9]*')
 WHERE LD_PRELOAD
 
 LET parsed_proc = SELECT
 *, int(int=OSPath[1]) AS Pid,
 to_dict(item={
 SELECT * FROM parse_csv(
 filename=OSPath + '/status', 
 separator=':', 
 columns=['_key','_value']) 
 }) AS Status
 FROM target_proc
 
 SELECT
 Pid,
 Status.PPid AS PPid,
 Status.Name AS Name,
 stat(filename=OSPath + '/exe').Data.Link AS Exe,
 read_file(filename=OSPath + '/cmdline') AS Cmdline,
 LD_PRELOAD,
 stat(filename=OSPath + '/cwd').Data.Link AS WorkingDir,
 split(string=read_file(filename=OSPath + '/environ'), sep='''\x00''') AS Environ
 FROM parsed_proc
 WHERE LD_PRELOAD =~ ContentRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Remediation.Quarantine.IPTables</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.remediation.quarantine/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.remediation.quarantine/</guid><description>&lt;p&gt;Quarantine a Linux host using iptables rules.&lt;/p&gt;
&lt;p&gt;NOTE: This is still a work in progress and may not work exactly as expected. Only use this artifact in a TEST environment/lab. It has been tested against Ubuntu hosts with iptables enabled.&lt;/p&gt;
&lt;p&gt;NOTE: There is now a built in Linux.Remediation.Quarantine which works a bit better&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Remediation.Quarantine.IPTables
description: |
 Quarantine a Linux host using iptables rules.

 NOTE: This is still a work in progress and may not work exactly as expected. Only use this artifact in a TEST environment/lab. It has been tested against Ubuntu hosts with iptables enabled.

 NOTE: There is now a built in Linux.Remediation.Quarantine which works a bit better

type: CLIENT
author: Wes Lambert -- @therealwlambert

parameters:
 - name: RemovePolicy
 type: bool
 description: Tickbox to remove policy.
 - name: NotificationMessage
 description: |
 Optional notification to send to logged in users.

sources:
 - query: |

 // Get domain, port, and Frontends for VR, like we do in the Windows Quarantine artifact (H/T @mgreen27)
 LET get_domain(URL) = parse_string_with_regex(string=URL, regex='^https?://(?P&amp;lt;Domain&amp;gt;[^:/]+)').Domain

 LET get_port(URL) = if(condition= URL=~"https://[^:]+/", then="443",else=if(condition= URL=~"http://[^:]+/", then="80",else=parse_string_with_regex(string=URL,
 regex='^https?://[^:/]+(:(?P&amp;lt;Port&amp;gt;[0-9]*))?/').Port))

 LET Frontends &amp;lt;= SELECT VRAddr, VRPort FROM foreach(row=config.server_urls, query={
 SELECT
 get_domain(URL=_value) AS VRAddr,
 get_port(URL=_value) AS VRPort
 FROM scope()
 })

 LET RemoveOldSavedRules = SELECT * FROM execve(argv=["bash", "-c", "rm", "-f", "/root/original-rules"])

 LET RestoreOldRules = SELECT * FROM chain(
 a={SELECT log(message="Removing quarantine policy...") FROM scope()},
 b={SELECT * FROM execve(argv=["iptables-restore", "/root/original-rules"])},
 c={SELECT * FROM execve(argv=["rm", "-f", "/root/original-rules"])}
 )

 LET IptablesExists &amp;lt;= SELECT ReturnCode FROM execve(argv=["ls","/usr/sbin/iptables"]) WHERE ReturnCode = 0

 LET RuleBackupDoesntExist = SELECT ReturnCode FROM execve(argv=["ls","/root/original-rules"]) WHERE ReturnCode = 2

 LET SaveCurrentRules = SELECT * FROM execve(argv=["iptables-save", "-f", "/root/original-rules"])

 LET RuleBackup = if(condition=RuleBackupDoesntExist, then=SaveCurrentRules, else=log(message="Rule backup already exists!"))

 LET ZenityExists = SELECT ReturnCode FROM execve(argv=["ls","/usr/bin/zenity"]) WHERE ReturnCode = 0

 LET ZenityCommand = SELECT * FROM execve(argv=["zenity", "--info", "--title", "ALERT", "--text", NotificationMessage])

 LET WallExists = SELECT ReturnCode FROM execve(argv=["ls","/usr/bin/wall"]) WHERE ReturnCode = 0

 LET WallCommand = SELECT * FROM execve(argv=["wall", "-n", NotificationMessage])

 LET XMessageExists = SELECT ReturnCode FROM execve(argv=["ls","/usr/bin/xmessage"]) WHERE ReturnCode = 0

 LET XMessageCommand = SELECT * FROM execve(argv=["xmessage", NotificationMessage])

 LET Display = SELECT ReturnCode FROM execve(argv=["xhost"]) WHERE ReturnCode = 0

 LET NotifyCommand = SELECT * FROM
 if(condition=Display,
 then={SELECT * FROM
 if(condition=ZenityExists,
 then=ZenityCommand,
 else=if(condition=XMessageExists,
 then=XMessageCommand
 )
 )
 },
 else={ SELECT * FROM
 if(condition=WallExists,
 then=WallCommand,
 else={ SELECT log(message="Unable to perform notification, as not suitable applications were found.") FROM scope() })
 }
 )

 LET NotifyUsers = SELECT * FROM if(condition=NotificationMessage,then=NotifyCommand)

 LET RemoveQuarantine = SELECT *, timestamp(epoch=now()) as Time FROM RestoreOldRules

 LET InputAllow = SELECT * from foreach(row=Frontends, query={ SELECT * FROM execve(argv=['iptables', '-A', 'INPUT', '-s', VRAddr, '-j', 'ACCEPT'])})

 LET ForwardAllow = SELECT * from foreach(row=Frontends, query={ SELECT * FROM execve(argv=['iptables', '-A', 'FORWARD', '-s', VRAddr, '-j', 'ACCEPT'])})

 LET OutputAllow = SELECT * from foreach(row=Frontends, query={ SELECT * FROM execve(argv=['iptables', '-A', 'OUTPUT', '-p', 'tcp', '-d', VRAddr, '--dport', VRPort, '-j', 'ACCEPT'])})

 LET InputDrop = SELECT * FROM execve(argv=['iptables', '-P', 'INPUT', 'DROP'])

 LET DockerChainExists = SELECT ReturnCode FROM execve(argv=['iptables', '-nL', 'DOCKER-USER']) WHERE ReturnCode = 0

 LET DockerDrop = SELECT if(condition=DockerChainExists, then={SELECT * FROM execve(argv=['iptables', '-I', 'DOCKER-USER', '-j', 'DROP'])}) FROM scope()

 LET ForwardDrop = SELECT * FROM execve(argv=['iptables', '-P', 'FORWARD', 'DROP'])

 LET OutputDrop = SELECT * FROM execve(argv=['iptables', '-P', 'OUTPUT', 'DROP'])

 SELECT if(condition=IptablesExists,
 then=if(condition=RemovePolicy,
 then=RemoveQuarantine,
 else={ SELECT * FROM chain(
 a=NotifyUsers,
 b=RuleBackup,
 c=InputAllow,
 d=ForwardAllow,
 e=OutputAllow,
 f=InputDrop,
 g=DockerDrop,
 h=ForwardDrop,
 i=OutputDrop
 )
 }
 ),
 else=log(message="Iptables not found. Only Iptables-based quarantine is supported for Linux hosts at this time.")
 ) AS Quarantine FROM scope()

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sys.APTHistory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.apthistory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.apthistory/</guid><description>&lt;p&gt;APT (Advanced Package Tool) maintains a log of software installation/removal/upgrades, as well as associated command-line invocations.&lt;/p&gt;
&lt;p&gt;This artifact parses the APT &lt;code&gt;history.log&lt;/code&gt;, as well as archived history logs to provide this information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sys.APTHistory
description: |
 APT (Advanced Package Tool) maintains a log of software installation/removal/upgrades, as well as associated command-line invocations.
 
 This artifact parses the APT `history.log`, as well as archived history logs to provide this information.

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: APTHistoryLogs
 default: /var/log/apt/history.log*
 description: APT history log(s)
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'linux'

 query: |
 LET APTHistoryList = SELECT OSPath FROM glob(globs=split(string=APTHistoryLogs, sep=","))
 LET ParseRecords = SELECT OSPath, parse_string_with_regex(
 string=Record,
 regex=['Start-Date:\\s(?P&amp;lt;StartDate&amp;gt;.+)',
 'Commandline:\\s(?P&amp;lt;CommandLine&amp;gt;.+)',
 'Requested-By:\\s(?P&amp;lt;RequestedBy&amp;gt;.+)',
 'Install:\\s(?P&amp;lt;Install&amp;gt;.+)',
 'Remove:\\s(?P&amp;lt;Remove&amp;gt;.+)',
 'Upgrade:\\s(?P&amp;lt;Upgrade&amp;gt;.+)',
 'End-Date:\\s(?P&amp;lt;EndDate&amp;gt;.+)']) as Event
 FROM parse_records_with_regex(accessor="gzip",file=OSPath, regex='''(?sm)^(?P&amp;lt;Record&amp;gt;Start-Date:.+?)\n\n''')
 SELECT * FROM foreach(row=APTHistoryList,query=ParseRecords)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sys.Getcap</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/getcap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/getcap/</guid><description>&lt;p&gt;Inspects extended file capabilities with getcap.&lt;br&gt;
Since Linux 2.6.24, setcap can attach fine-grained privilege bits to
executables, letting them perform the specific privileged actions they
require instead of running as root.&lt;br&gt;
If a binary that’s writable or executable by non-privileged users is granted
excessive capabilities, attackers can exploit it for privilege escalation.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sys.Getcap
author: Matt Green - @mgreen27
description: |
 Inspects extended file capabilities with getcap. 
 Since Linux 2.6.24, setcap can attach fine-grained privilege bits to 
 executables, letting them perform the specific privileged actions they 
 require instead of running as root. 
 If a binary that’s writable or executable by non-privileged users is granted 
 excessive capabilities, attackers can exploit it for privilege escalation.
 
reference:
 - https://dfir.ch/posts/linux_capabilities/
 - https://man7.org/linux/man-pages/man7/capabilities.7.html
 
 
parameters:
 - name: TargetPath
 default: /
 description: Target path for getcap. Default / will scan all. Globs also work - e.g /usr/bin/*
 - name: CapRegex
 default: .
 description: "Regex for capability to search for: e.g cap_setuid=ep"

required_permissions:
 - EXECVE
 
sources:
 - precondition: |
 SELECT OS
 FROM info()
 WHERE OS = 'linux'


 query: |
 LET results = SELECT Stdout
 FROM execve(argv=["getcap", "-r", TargetPath], sep='\n')
 WHERE Stdout =~ "cap"
 
 LET caps = SELECT split(sep=' ', string=Stdout)[:-1][0] AS Binary,
 split(sep=' ', string=Stdout)[-1] AS Capabilities
 FROM results
 WHERE Capabilities =~ CapRegex
 
 SELECT *
 FROM foreach(row=caps,
 query={
 SELECT OSPath,
 Capabilities,
 Mode.String AS ModeString,
 Size,
 Mtime,
 Atime,
 Ctime,
 Btime
 FROM stat(filename=Binary)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sys.JournalCtl</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.journalctl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.journalctl/</guid><description>&lt;p&gt;Parse the output of the journalctl command. Journalctl is an interface to the systemd journal, which records information about system events.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sys.JournalCtl
description: |
 Parse the output of the journalctl command. Journalctl is an interface to the systemd journal, which records information about system events.
 
reference:
 - https://man7.org/linux/man-pages/man1/journalctl.1.html
parameters:
 - name: Length 
 default: 10000
 type: int
 - name: DateAfter
 type: timestamp
 - name: DateBefore
 type: timestamp

author: Wes Lambert -- @therealwlambert/@weslambert@infosec.exchange
sources:
 - query:
 LET JournalFormat(ts) = format(format='%d-%02d-%02d %02d:%02d:%02d UTC',
 args=[ts.Year, ts.Month, ts.Day, ts.Hour, ts.Minute, ts.Second])
 LET DateAfterTime = JournalFormat(ts=if(condition=DateAfter,
 then=DateAfter, else=timestamp(epoch='1600-01-01')))
 LET DateBeforeTime = JournalFormat(ts=if(condition=DateBefore,
 then=DateBefore, else=timestamp(epoch='2200-01-01')))
 LET JCtlOut = SELECT * FROM execve(length=Length, argv=['/usr/bin/journalctl',
 '-o', 'json', '-S', DateAfterTime, '-U', DateBeforeTime], sep="\n")
 SELECT
 timestamp(string=ParsedOutput.__REALTIME_TIMESTAMP) AS Timestamp,
 ParsedOutput._HOSTNAME AS _Hostname,
 ParsedOutput.MESSAGE AS Message,
 ParsedOutput._MACHINE_ID AS _MachineID,
 ParsedOutput._BOOT_ID AS BootID,
 ParsedOutput.SYSLOG_IDENTIFIER AS _SyslogIdentifier,
 ParsedOutput.PRIORITY AS _Priority,
 ParsedOutput.SYSLOG_FACILITY AS _SyslogFacility,
 ParsedOutput.__MONOTONIC_TIMESTAMP AS _MonotonicTS,
 ParsedOutput._SOURCE_MONOTONIC_TIMESTAMP AS _SourceMonoTS,
 ParsedOutput._TRANSPORT AS _Transport,
 ParsedOutput.__CURSOR AS Cursor
 FROM foreach(row={SELECT parse_json(data=Stdout) AS ParsedOutput FROM JCtlOut WHERE Stdout})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sys.Modinfo</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/modinfo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/modinfo/</guid><description>&lt;p&gt;Collects detailed metadata about Linux kernel modules using modinfo. Useful for
malicious kernel module hunting.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Live mode (default) - Parses /proc/modules, then runs modinfo &lt;name&gt; for each loaded
module. Default search is /lib/modules/$(uname -r)/**/&lt;name&gt;.ko&lt;/li&gt;
&lt;li&gt;Disk mode - If ModuleTargetGlob is supplied, skips live
enumeration and instead uses glob, running modinfo &lt;path&gt; for every matching glob hit. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both modes use ModuleNameRegex to filter by name.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sys.Modinfo
author: Matt Green - @mgreen27
description: |
 Collects detailed metadata about Linux kernel modules using modinfo. Useful for 
 malicious kernel module hunting.

 - Live mode (default) - Parses /proc/modules, then runs modinfo &amp;lt;name&amp;gt; for each loaded
 module. Default search is /lib/modules/$(uname -r)/**/&amp;lt;name&amp;gt;.ko
 - Disk mode - If ModuleTargetGlob is supplied, skips live
 enumeration and instead uses glob, running modinfo &amp;lt;path&amp;gt; for every matching glob hit. 
 
 Both modes use ModuleNameRegex to filter by name.
parameters:
 - name: ModuleNameRegex
 default: .
 - name: ModuleTargetGlob
 description: Glob to target. If set will bypass live analysis and use glob instead.
 
required_permissions:
 - EXECVE
 
sources:
 - precondition: |
 SELECT OS
 FROM info()
 WHERE OS = 'linux'

 query: |
 LET proc_mod = SELECT Name,
 dict(Source='/proc/mod',
 Name=Name,
 Size=Size,
 UseCount=UseCount,
 UsedBy=UsedBy,
 Status=Status,
 Address=Address) AS SourceInfo
 FROM Artifact.Linux.Proc.Modules()
 WHERE Name =~ ModuleNameRegex
 
 LET target_glob = SELECT OSPath AS Name,
 dict(Source='glob',
 OSPath=OSPath,
 Size=Size,
 Mtime=Mtime,
 Magic=magic(path=OSPath)) AS SourceInfo
 FROM glob(globs=ModuleTargetGlob)
 
 SELECT
 SourceInfo,
 if(condition=Extracted.filename, then=Extracted.filename, else=Stderr) AS Filename,
 if(
 condition=Extracted.name,
 then=Extracted.name,
 else=SourceInfo.Name) AS Name,
 Extracted.alias AS Alias,
 Extracted.license AS License,
 Extracted.description AS Description,
 Extracted.author AS Author,
 Extracted.srcversion AS SrcVersion,
 Extracted.depends AS Depends,
 Extracted.retpoline AS Retpoline,
 Extracted.intree AS Intree,
 Extracted.vermagic AS Vermagic,
 if(
 condition=Extracted.filename
 and (Extracted.signature OR Extracted.sig_key),
 then=dict(
 Id=Extracted.sig_id,
 Signer=Extracted.signer,
 Key=Extracted.sig_key,
 Hashalgo=Extracted.sig_hashalgo,
 Signature=Extracted.signature),
 else='') AS Signature
 FROM foreach(
 row=if(
 condition=ModuleTargetGlob,
 then=target_glob,
 else=proc_mod),
 query={
 SELECT
 SourceInfo,
 parse_string_with_regex(
 string=Stdout,
 regex=[
 '''filename:\s+(?P&amp;lt;filename&amp;gt;[^\n]*)\n''', 
 '''alias:\s+(?P&amp;lt;alias&amp;gt;[^\n]*)\n''', 
 '''license:\s+(?P&amp;lt;license&amp;gt;[^\n]*)\n''', 
 '''description:\s+(?P&amp;lt;description&amp;gt;[^\n]*)\n''', 
 '''author:\s+(?P&amp;lt;author&amp;gt;[^\n]*)\n''', 
 '''srcversion:\s+(?P&amp;lt;srcversion&amp;gt;[^\n]*)\n''', 
 '''depends:\s+(?P&amp;lt;depends&amp;gt;[^\n]*)\n''', 
 '''retpoline:\s+(?P&amp;lt;retpoline&amp;gt;[^\n]*)\n''', 
 '''intree:\s+(?P&amp;lt;intree&amp;gt;[^\n]*)\n''', 
 '''name:\s+(?P&amp;lt;name&amp;gt;[^\n]*)\n''', 
 '''vermagic:\s+(?P&amp;lt;vermagic&amp;gt;[^\n]*)\n''', 
 '''sig_id:\s+(?P&amp;lt;sig_id&amp;gt;[^\n]*)\n''', 
 '''signer:\s+(?P&amp;lt;signer&amp;gt;[^\n]*)\n''', 
 '''sig_key:\s+(?P&amp;lt;sig_key&amp;gt;[A-Z0-9:\s]*)\n[^\t]''', 
 '''sig_hashalgo:\s+(?P&amp;lt;sig_hashalgo&amp;gt;[^\n]*)\n''',
 '''signature:\s+(?P&amp;lt;signature&amp;gt;[A-Z0-9:\n\t]*)\n([a-z]|$)'''
 ]) AS Extracted,
 Stderr
 FROM execve(
 argv=["modinfo", Name])
 })
 WHERE Name =~ ModuleNameRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sys.SystemdTimer</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.systemdtimer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sys.systemdtimer/</guid><description>&lt;p&gt;List and parse content of Systemd timers.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sys.SystemdTimer

author: Wes Lambert - @therealwlambert

description: List and parse content of Systemd timers. 

reference:
 - https://www.digitalforensics.ch/nikkel18.pdf
 - https://lloydrochester.com/post/unix/systemd-timer-example/
 
parameters:
 - name: TimerLocation
 default: /lib/systemd/system/*.timer,/usr/lib/systemd/system/*.timer,/etc/systemd/system/*.timer,~/.config/systemd/user/*.timer
 description: The location of Systemd timers
 
sources:
 - precondition: |
 SELECT OS From info() where OS = 'linux'
 queries:
 - |
 SELECT *, read_file(filename=OSPath) FROM glob(globs=split(string=TimerLocation, sep=","))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sysinternals.Sysmon</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sysinternals.sysmon/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sysinternals.sysmon/</guid><description>&lt;p&gt;Parses syslog for Sysmon events on Linux&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;: &lt;a href="https://github.com/Sysinternals/SysmonForLinux" target="_blank" &gt;https://github.com/Sysinternals/SysmonForLinux&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can also be modified to forward events (as a client
event artifact), similar to Windows.Sysinternals.SysmonLogForward.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sysinternals.Sysmon
author: Wes Lambert -- @therealwlambert
description: |
 Parses syslog for Sysmon events on Linux

 **Reference**: https://github.com/Sysinternals/SysmonForLinux

 This artifact can also be modified to forward events (as a client
 event artifact), similar to Windows.Sysinternals.SysmonLogForward.

type: CLIENT

precondition: SELECT OS From info() where OS = 'linux'

parameters:
 - name: syslogPath
 default: /var/log/syslog

 - name: sysmonGrok
 description: A Grok expression for parsing Sysmon events from syslog on Linux machines
 default: &amp;gt;-
 %{SYSLOGTIMESTAMP:Timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: %{GREEDYDATA:event}
 - name: StartDate
 type: timestamp
 description: "Parse events on or after this date (YYYY-MM-DDTmm:hh:ssZ)"
 - name: EndDate
 type: timestamp
 description: "Parse events on or before this date (YYYY-MM-DDTmm:hh:ssZ)"
 - name: IDRegex
 default: "."
 - name: EventDataRegex
 description: "IOC Filter to reduce results"
 default: "."
 - name: ParentUserRegex
 description: "User filter by parent user for process artefacts"
 default: "."
 

sources:
 - queries:
 # Basic syslog parsing via GROK expressions.
 - LET UnparsedEvents = SELECT * FROM foreach(
 row={
 SELECT * FROM glob(globs=syslogPath)
 }, query={
 SELECT grok(grok=sysmonGrok, data=Line) AS Event,
 OSPath
 FROM parse_lines(filename=OSPath)
 WHERE Event.program = "sysmon" AND Event.event =~ "&amp;lt;Event&amp;gt;"
 })
 - LET ParsedEvents = SELECT parse_xml(accessor='data', file=Event.event).Event AS Event FROM UnparsedEvents
 - SELECT timestamp(string=Event.System.TimeCreated.AttrSystemTime) AS TimeCreated,
 Event.System.EventID AS EventID,
 Event.System.Channel AS _Channel,
 Event.System.EventRecordID AS EventRecordID,
 Event.System.EventID AS EventID,
 Event.System.Computer AS Computer,
 Event.System AS System,
 to_dict(item={SELECT AttrName AS _key, `#text` AS _value FROM Event.EventData.Data}) AS EventData
 FROM ParsedEvents
 WHERE
 if(condition=StartDate, then=TimeCreated &amp;gt;= timestamp(string=StartDate), else=true)
 AND if(condition=EndDate, then=TimeCreated &amp;lt;= timestamp(string=EndDate), else=true)
 AND str(str=EventID) =~ IDRegex
 AND EventData =~ EventDataRegex
 AND EventData.ParentUser =~ ParentUserRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Sysinternals.SysmonEvent</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sysinternals.sysmonevent/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.sysinternals.sysmonevent/</guid><description>&lt;p&gt;Parses syslog for Sysmon events on Linux using a unix domain socket.&lt;/p&gt;
&lt;p&gt;NOTE: This is an experimental patch for sysmon that gets it to write events
to a unix domain socket.&lt;/p&gt;
&lt;p&gt;Until it merges upstream you can get it from here:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;: &lt;a href="https://github.com/Velocidex/SysmonForLinux" target="_blank" &gt;https://github.com/Velocidex/SysmonForLinux&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Sysinternals.SysmonEvent
description: |
 Parses syslog for Sysmon events on Linux using a unix domain socket.
 
 NOTE: This is an experimental patch for sysmon that gets it to write events 
 to a unix domain socket. 
 
 Until it merges upstream you can get it from here:
 
 **Reference**: https://github.com/Velocidex/SysmonForLinux

type: CLIENT_EVENT

precondition: SELECT OS From info() where OS = 'linux'

parameters:
 - name: SysmonUnixDomainSocket
 default: /var/run/sysmon.sock
 
sources:
 - query: |
 LET ParsedEvents = 
 SELECT parse_json(data=Data).Event AS Event 
 FROM netcat(type='unix', address=SysmonUnixDomainSocket, retry=10)
 WHERE Data
 
 SELECT timestamp(string=Event.System.TimeCreated.SystemTime) AS TimeCreated,
 Event.System.EventID AS EventID,
 Event.System.Channel AS _Channel,
 Event.System.EventRecordID AS EventRecordID,
 Event.System.EventID AS EventID,
 Event.System.Computer AS Computer,
 Event.System AS System, 
 Event.EventData AS EventData
 FROM ParsedEvents

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.System.BashLogout</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.system.bashlogout/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.system.bashlogout/</guid><description>&lt;p&gt;Capture Bash logout files for examination of abnormal activity.&lt;/p&gt;
&lt;p&gt;Bash logout files are used to run certain commands upon user logout, such as clearing the shell or terminal state. An adversary could leverage this capability to clear logs, cover tracks, delete files, etc.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.System.BashLogout
description: |
 Capture Bash logout files for examination of abnormal activity. 
 
 Bash logout files are used to run certain commands upon user logout, such as clearing the shell or terminal state. An adversary could leverage this capability to clear logs, cover tracks, delete files, etc.

type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: BashLogoutGlob
 default: /home/*/.bash_logout
- name: ContentFilter
 default: .
 description: Filter used for searching through file content
- name: UploadFiles
 default: False
 description: "Upload Bash logout files in scope"
 type: bool
precondition:
 SELECT OS From info() where OS = 'linux'

sources:
 - query: |
 
 LET BashLogoutList = SELECT OSPath, Mtime
 FROM glob(globs=split(string=BashLogoutGlob, sep=","))
 
 SELECT OSPath, Mtime, parse_string_with_regex(regex="(?sm)(?P&amp;lt;Commands&amp;gt;^[a-z].*)", string=read_file(filename=OSPath)).Commands AS Content, 
 if(condition=UploadFiles,then=upload(file=OSPath)) AS Upload
 FROM foreach(row=BashLogoutList)
 WHERE Content =~ ContentFilter

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.System.PAM</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/linux.system.pam/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/linux.system.pam/</guid><description>&lt;p&gt;This artifact enumerates applicable lines from the files that reside in &lt;code&gt;/etc/PAM.d/&lt;/code&gt;. This information can be useful for auditing and compliance purposes, or to identify suspicious activity on Linux systems.&lt;/p&gt;
&lt;p&gt;For example, we could use the &lt;code&gt;RecordFilter&lt;/code&gt; parameter to check for the presence of &lt;code&gt;pam_exec.so&lt;/code&gt;, which can be used within PAM configuration to invoke arbitrary scripts.&lt;/p&gt;
&lt;p&gt;From MITRE ATT&amp;amp;CK:&lt;/p&gt;
&lt;p&gt;Adversaries may modify pluggable authentication modules (PAM) to access user credentials or enable otherwise unwarranted access to accounts. PAM is a modular system of configuration files, libraries, and executable files which guide authentication for many services. The most common authentication module is PAM_unix.so, which retrieves, sets, and verifies account authentication information in /etc/passwd and /etc/shadow&lt;/p&gt;
&lt;p&gt;Adversaries may modify components of the PAM system to create backdoors. PAM components, such as PAM_unix.so, can be patched to accept arbitrary adversary supplied values as legitimate credentials.&lt;/p&gt;
&lt;p&gt;Malicious modifications to the PAM system may also be abused to steal credentials. Adversaries may infect PAM resources with code to harvest user credentials, since the values exchanged with PAM components may be plain-text since PAM does not store passwords.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.System.PAM

description: |
 This artifact enumerates applicable lines from the files that reside in `/etc/PAM.d/`. This information can be useful for auditing and compliance purposes, or to identify suspicious activity on Linux systems.
 
 For example, we could use the `RecordFilter` parameter to check for the presence of `pam_exec.so`, which can be used within PAM configuration to invoke arbitrary scripts. 

 
 From MITRE ATT&amp;amp;CK:
 
 Adversaries may modify pluggable authentication modules (PAM) to access user credentials or enable otherwise unwarranted access to accounts. PAM is a modular system of configuration files, libraries, and executable files which guide authentication for many services. The most common authentication module is PAM_unix.so, which retrieves, sets, and verifies account authentication information in /etc/passwd and /etc/shadow
 
 Adversaries may modify components of the PAM system to create backdoors. PAM components, such as PAM_unix.so, can be patched to accept arbitrary adversary supplied values as legitimate credentials.
 
 Malicious modifications to the PAM system may also be abused to steal credentials. Adversaries may infect PAM resources with code to harvest user credentials, since the values exchanged with PAM components may be plain-text since PAM does not store passwords.
 
reference:
 - https://linux.die.net/man/5/PAM.d
 - https://attack.mitre.org/techniques/T1556/003/
 - https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1556.003/T1556.003.md
 - https://book.hacktricks.xyz/linux-hardening/linux-post-exploitation#sniffing-logon-passwords-with-PAM
 
type: CLIENT
author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
 - name: PAMGlob
 default: /etc/pam.d/*
 - name: RecordFilter
 default: .
 description: Filter used for targeting specific records by content
 - 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"
 
precondition:
 SELECT OS From info() where OS = 'linux'
 
sources:
 - query: |
 LET DateAfterTime &amp;lt;= if(condition=DateAfter,
 then=timestamp(epoch=DateAfter), else=timestamp(epoch="1600-01-01"))
 LET DateBeforeTime &amp;lt;= if(condition=DateBefore,
 then=timestamp(epoch=DateBefore), else=timestamp(epoch="2200-01-01")) 
 LET PAMGlobList = SELECT Mtime, OSPath
 FROM glob(globs=split(string=PAMGlob, sep=","))
 SELECT * FROM foreach(row=PAMGlobList, 
 query={ SELECT Mtime, 
 OSPath, 
 Line AS Record
 FROM parse_lines(filename=OSPath) 
 WHERE Record =~ RecordFilter
 AND Mtime &amp;lt; DateBeforeTime
 AND Mtime &amp;gt; DateAfterTime
 AND NOT Record =~ '^#' 
 AND NOT Record = ''})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Linux.Volatility.Create.Profile</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/volatility_profile/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/volatility_profile/</guid><description>&lt;p&gt;This artifact is used to create the profile to the environnements Debian / Ubuntu.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Linux.Volatility.Create.Profile
author: URCA (Corentin Garcia / Emmanuel Mesnard)
description: |
 This artifact is used to create the profile to the environnements Debian / Ubuntu.


required_permissions:
 - EXECVE

tools:
 - name: Volatility
 url: https://github.com/volatilityfoundation/volatility/archive/master.zip

parameters:
 - name: Zipname
 type: string
 default: Ubuntu
 
precondition: SELECT OS From info() where OS = 'linux'

sources:
 - queries:
 - LET dirtmp = tempdir(remove_last=true)
 
 LET vola = SELECT * FROM execve(argv=['bash', '-c', 'mv /tmp/master.zip /tmp/volatility-master.zip ; cd /tmp/ ; apt install -y dwarfdump zip unzip ; unzip -o /tmp/volatility-master.zip -d /tmp/ ; cd /tmp/volatility-master/tools/linux/ ; make clean ; make ; zip /tmp/' + Zipname + '.zip /tmp/volatility-master/tools/linux/module.dwarf /boot/System.map-$(uname -r)'])
 
 SELECT * FROM foreach(
 row={
 SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Volatility")
 },
 query={
 SELECT * FROM chain(
 a={SELECT *, if(condition=Complete, then=upload(file="/tmp/" + Zipname + ".zip", name=Zipname + ".zip")) As Upload FROM vola},
 b={SELECT * FROM execve(argv=['bash', '-c', 'mv /tmp/volatility-master /tmp/volatility-master.zip /tmp/' + Zipname + '.zip ' + dirtmp])})
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.Cache</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.cache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.cache/</guid><description>&lt;p&gt;Applications can use the NSURL cache to store specific data that is useful to the operation of the application in a &lt;code&gt;Cache.db&lt;/code&gt; file on disk. The data contained within this file could potentially be useful to investigators or incident responders, such as URLs that were accessed, as well as data requested or returned.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.Cache
description: |
 Applications can use the NSURL cache to store specific data that is useful to the operation of the application in a `Cache.db` file on disk. The data contained within this file could potentially be useful to investigators or incident responders, such as URLs that were accessed, as well as data requested or returned.

reference:
 - https://developer.apple.com/documentation/foundation/nsurl

type: CLIENT

author: Wes Lambert - @therealwlambert

parameters:
- name: CacheGlob
 default: /Users/*/Library/Caches/*/Cache.db

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET CacheList = SELECT FullPath
 FROM glob(globs=split(string=CacheGlob, sep=","))

 LET CacheQuery = SELECT *
 FROM sqlite(file=FullPath, query="SELECT cfurl_cache_response.entry_ID AS entry_ID, version, hash_value, storage_policy, request_key, time_stamp, partition, request_object, response_object FROM cfurl_cache_response INNER JOIN cfurl_cache_blob_data ON cfurl_cache_response.entry_ID = cfurl_cache_blob_data.entry_ID INNER JOIN cfurl_cache_receiver_data ON cfurl_cache_response.entry_ID = cfurl_cache_receiver_data.entry_ID")
 
 SELECT * FROM foreach(
 row=CacheList,
 query={ 
 SELECT
 time_stamp AS Timestamp,
 basename(path=dirname(path=FullPath)) AS Application,
 entry_ID AS EntryID,
 version AS Version,
 hash_value AS Hash,
 storage_policy AS StoragePolicy,
 request_key AS URL,
 plist(file=request_object, accessor="data") AS Request,
 plist(file=response_object, accessor="data") AS Response,
 partition AS Partition,
 FullPath
 FROM CacheQuery
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.Firefox.History</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.firefox.history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.firefox.history/</guid><description>&lt;p&gt;Read all Users Firefox history.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.Firefox.History
description: |
 Read all Users Firefox history.

parameters:
 - name: historyGlobs
 default: /Users/*/Library/Application Support/Firefox/Profiles/*/places.sqlite
 - name: urlSQLQuery
 default: |
 SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch') AS visit_time, moz_places.url as visited_url,title, visit_count,
 typed, frecency, last_visit_date, description, rev_host, preview_image_url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id
 - name: userRegex
 default: .

reference:
 - https://www.foxtonforensics.com/browser-history-examiner/firefox-history-location
 - https://en.wikiversity.org/wiki/Firefox/Browsing_history_database
 
author: https://github.com/x64-julian

precondition: SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET history_files = SELECT
 parse_string_with_regex(regex="/Users/(?P&amp;lt;User&amp;gt;[^/]+)", string=OSPath).User AS User,
 OSPath
 FROM glob(globs=historyGlobs)

 SELECT * FROM foreach(row=history_files,
 query={
 SELECT User, OSPath,
 visit_time, visited_url, title,description, visit_count, typed, frecency,
 last_visit_date, rev_host, preview_image_url
 FROM sqlite(
 file=OSPath,
 query=urlSQLQuery)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.KnowledgeC</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.knowledgec/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.knowledgec/</guid><description>&lt;p&gt;On macOS, the KnowledgeC DB can provide various details around application activities and usage, as well as device power status.&lt;/p&gt;
&lt;p&gt;More information about this database can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.mac4n6.com/blog/2018/8/5/knowledge-is-power-using-the-knowledgecdb-database-on-macos-and-ios-to-determine-precise-user-and-application-usage" target="_blank" &gt;https://www.mac4n6.com/blog/2018/8/5/knowledge-is-power-using-the-knowledgecdb-database-on-macos-and-ios-to-determine-precise-user-and-application-usage&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.KnowledgeC
description: |
 On macOS, the KnowledgeC DB can provide various details around application activities and usage, as well as device power status.
 
 More information about this database can be found here: 
 
 https://www.mac4n6.com/blog/2018/8/5/knowledge-is-power-using-the-knowledgecdb-database-on-macos-and-ios-to-determine-precise-user-and-application-usage

reference:
 - https://www.mac4n6.com/blog/2018/8/5/knowledge-is-power-using-the-knowledgecdb-database-on-macos-and-ios-to-determine-precise-user-and-application-usage

type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: KCDBGlob
 default: /private/var/db/CoreDuet/Knowledge/knowledgeC.db,/Library/Application Support/Knowledge/knowledgeC.db

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - name: Application Activities
 query: |
 LET KCDBList = SELECT OSPath
 FROM glob(globs=split(string=KCDBGlob, sep=","))

 LET KCDBAppActivities = SELECT *
 FROM sqlite(file=OSPath, query='''
 SELECT
 datetime(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "ENTRY CREATION", 
 ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
 CASE ZOBJECT.ZSTARTDAYOFWEEK 
 WHEN "1" THEN "Sunday"
 WHEN "2" THEN "Monday"
 WHEN "3" THEN "Tuesday"
 WHEN "4" THEN "Wednesday"
 WHEN "5" THEN "Thursday"
 WHEN "6" THEN "Friday"
 WHEN "7" THEN "Saturday"
 END "DAY OF WEEK",
 datetime(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "START", 
 datetime(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "END", 
 (ZOBJECT.ZENDDATE-ZOBJECT.ZSTARTDATE) as "USAGE IN SECONDS", 
 ZOBJECT.ZSTREAMNAME, 
 ZOBJECT.ZVALUESTRING,
 ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__ACTIVITYTYPE AS "ACTIVITY TYPE", 
 ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__TITLE as "TITLE", 
 ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__USERACTIVITYREQUIREDSTRING as "ACTIVITY STRING",
 datetime(ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__EXPIRATIONDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "EXPIRATION DATE"
 FROM ZOBJECT
 left join ZSTRUCTUREDMETADATA on ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
 WHERE ZSTREAMNAME is "/app/activity" or ZSTREAMNAME is "/app/inFocus"''')
 
 SELECT timestamp(string=`ENTRY CREATION`) AS Timestamp,	
 `GMT OFFSET` AS OffsetGMT,	
 `DAY OF WEEK` AS DayOfWeek,	
 `START` AS Start,
 `END` AS End,
 `USAGE IN SECONDS` AS Usage,	
 ZSTREAMNAME AS StreamName,
 ZVALUESTRING AS StreamValue,	
 `ACTIVITY TYPE` AS ActivityType, 	
 TITLE AS Title,
 `ACTIVITY STRING` AS Activity,	
 `EXPIRATION DATE` AS ExpirationDate
 FROM foreach(row=KCDBList,query=KCDBAppActivities)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.NetworkUsage</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.networkusage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.networkusage/</guid><description>&lt;p&gt;On macOS, the NetUsage DB can provide various details around application network utilization. With this artifact, we can get an idea of what applications are utilizing the network for communications and to what degree. We can also identify if usage has occurred through a WIFI network or a wired network.&lt;/p&gt;
&lt;p&gt;More information about this database can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.mac4n6.com/blog/2019/1/6/network-and-application-usage-using-netusagesqlite-amp-datausagesqlite-ios-databases" target="_blank" &gt;http://www.mac4n6.com/blog/2019/1/6/network-and-application-usage-using-netusagesqlite-amp-datausagesqlite-ios-databases&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.NetworkUsage
description: |
 On macOS, the NetUsage DB can provide various details around application network utilization. With this artifact, we can get an idea of what applications are utilizing the network for communications and to what degree. We can also identify if usage has occurred through a WIFI network or a wired network.
 
 More information about this database can be found here: 
 
 http://www.mac4n6.com/blog/2019/1/6/network-and-application-usage-using-netusagesqlite-amp-datausagesqlite-ios-databases
reference:
 - http://www.mac4n6.com/blog/2019/1/6/network-and-application-usage-using-netusagesqlite-amp-datausagesqlite-ios-databases

type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: NetUsageGlob
 default: /private/var/networkd/netusage.sqlite,/private/var/networkd/db/netusage.sqlite

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET NetUsageList = SELECT OSPath
 FROM glob(globs=split(string=NetUsageGlob, sep=","))

 LET NetUsageDetails = SELECT *
 FROM sqlite(file=OSPath, query='''
 SELECT
 DATETIME(ZPROCESS.ZTIMESTAMP + 978307200, 'unixepoch') AS "PROCESS TIMESTAMP",
 DATETIME(ZPROCESS.ZFIRSTTIMESTAMP + 978307200, 'unixepoch') AS "PROCESS FIRST TIMESTAMP",
 DATETIME(ZLIVEUSAGE.ZTIMESTAMP + 978307200, 'unixepoch') AS "LIVE USAGE TIMESTAMP",
 ZBUNDLENAME AS "BUNDLE ID",
 ZPROCNAME AS "PROCESS NAME",
 ZWIFIIN AS "WIFI IN",
 ZWIFIOUT AS "WIFI OUT",
 ZWWANIN AS "WWAN IN",
 ZWWANOUT AS "WWAN OUT",
 ZWIREDIN AS "WIRED IN",
 ZWIREDOUT AS "WIRED OUT",
 ZXIN AS "X IN",
 ZXOUT AS "X OUT",
 ZLIVEUSAGE.Z_PK AS "ZLIVEUSAGE TABLE ID" 
 FROM ZLIVEUSAGE 
 LEFT JOIN ZPROCESS ON ZPROCESS.Z_PK = ZLIVEUSAGE.ZHASPROCESS''')
 
 SELECT timestamp(string=`PROCESS TIMESTAMP`) AS Timestamp,	
 `PROCESS FIRST TIMESTAMP` AS FirstTimestamp,	
 `LIVE USAGE TIMESTAMP` AS LiveUsageTimestamp,
 `BUNDLE ID` AS BundleID,
 `PROCESS NAME` AS ProcessName,	
 `WIFI IN` AS WifiIn,
 `WIFI OUT` AS WifiOut,	
 `WIRED IN` AS WiredIn, 	
 `WIRED OUT` AS WiredOut,
 `X IN` AS _XIn,	
 `X OUT` AS _XOut,
 `ZLIVEUSAGE TABLE ID` AS LiveUsageTableID
 FROM foreach(row=NetUsageList,query=NetUsageDetails)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.Notes</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.notes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.notes/</guid><description>&lt;p&gt;This artifact provides details about notes taken using the default Notes application on macOS. These notes can be useful during an investigation, especially if tied to interesting files.&lt;/p&gt;
&lt;p&gt;Deleted notes and attachments can also be recovered in some instances.&lt;/p&gt;
&lt;p&gt;The SQL query within this artifact was primarily derived from Yogesh Khatri&amp;rsquo;s referenced blog post.&lt;/p&gt;
&lt;p&gt;NOTE: This artifact may not cover all attachments at this time, and there are many more great pieces of data to discover! More information can be found in the &lt;code&gt;ZICCLOUDSYNCINGOBJECT&lt;/code&gt; table.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.Notes
description: |
 This artifact provides details about notes taken using the default Notes application on macOS. These notes can be useful during an investigation, especially if tied to interesting files. 
 
 Deleted notes and attachments can also be recovered in some instances.
 
 The SQL query within this artifact was primarily derived from Yogesh Khatri's referenced blog post.
 
 NOTE: This artifact may not cover all attachments at this time, and there are many more great pieces of data to discover! More information can be found in the `ZICCLOUDSYNCINGOBJECT` table.
 
reference:
 - http://www.swiftforensics.com/2018/02/reading-notes-database-on-macos.html

type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: NotesGlob
 default: /Users/*/Library/Containers/com.apple.Notes/Data/Library/Notes/NotesV*.storedata,/Users/*/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite
- name: UploadFiles
 default: False
 description: "Upload attachments in scope"
 type: bool
precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET NotesList = SELECT OSPath
 FROM glob(globs=split(string=NotesGlob, sep=","))

 LET NotesDetails = SELECT Key AS _Key,
 split(sep='\/', string=OSPath)[2] AS User,
 Note,
 Title,
 Snippet,
 NoteID AS _NoteID,
 timestamp(cocoatime=CreatedTS) AS CreatedTime,
 timestamp(cocoatime=LastOpenedDate) AS LastOpenedTime,
 timestamp(cocoatime=DirModificationDate) AS LastDirModifcation,
 Account AS _Account,
 Directory,
 DirectoryID,
 AttachmentName,
 AttachmentSize,
 AttachmentUUID,
 if(condition=AttachmentUUID,then='Users/' + split(sep='\/', string=OSPath)[2] + '/Library/Group Containers/group.com.apple.notes/Accounts/LocalAccount/Media/' + AttachmentUUID + '/' + AttachmentName) AS AttachmentLocation,
 AccountName AS _AccountName,
 AccountID AS _AccountID,
 AccountType AS _AccountType,
 gunzip(string=Data) AS Data,
 OSPath
 FROM sqlite(file=OSPath, 
 query=if(condition=OSPath =~ ".sqlite", 
 then='''SELECT n.Z_PK AS Key, 
 n.ZNOTE as Note, 
 c1.ZTITLE1 as Title, 
 c1.ZSNIPPET as Snippet, 
 c1.ZIDENTIFIER as NoteID,
 c1.ZCREATIONDATE3 as CreatedTS,
 c1.ZFOLDERMODIFICATIONDATE AS DirModificationDate,
 c1.ZLASTOPENEDDATE AS LastOpenedDate,
 c2.ZACCOUNT3 as Account, 
 c2.ZTITLE2 as Directory, 
 c2.ZIDENTIFIER as DirectoryID,
 c4.ZFILENAME as AttachmentName,
 c3.ZFILESIZE as AttachmentSize, 
 c4.ZIDENTIFIER as AttachmentUUID,
 c5.ZNAME as AccountName, 
 c5.ZIDENTIFIER as AccountID, 
 c5.ZACCOUNTTYPE as AccountType,
 n.ZDATA as Data
 FROM ZICNOTEDATA as n 
 LEFT JOIN ZICCLOUDSYNCINGOBJECT as c1 ON c1.ZNOTEDATA = n.Z_PK 
 LEFT JOIN ZICCLOUDSYNCINGOBJECT as c2 ON c2.Z_PK = c1.ZFOLDER 
 LEFT JOIN ZICCLOUDSYNCINGOBJECT as c3 ON c3.ZNOTE= n.ZNOTE 
 LEFT JOIN ZICCLOUDSYNCINGOBJECT as c4 ON c4.ZATTACHMENT1= c3.Z_PK 
 LEFT JOIN ZICCLOUDSYNCINGOBJECT as c5 ON c5.Z_PK = c1.ZACCOUNT2 
 ORDER BY Key''', 
 else='''SELECT n.Z_PK as Key, 
 datetime(n.ZDATECREATED + 978307200, 'unixepoch') as CreatedTS, 
 datetime(n.ZDATEEDITED + 978307200, 'unixepoch') as Modtime, 
 n.ZTITLE AS Title, 
 (SELECT ZNAME from ZFOLDER where n.ZFOLDER=ZFOLDER.Z_PK) as Directory,
 (SELECT zf2.ZACCOUNT from ZFOLDER as zf1 
 LEFT JOIN ZFOLDER as zf2 on (zf1.ZPARENT=zf2.Z_PK) where n.ZFOLDER=zf1.Z_PK) as DirectoryParent,
 ac.ZEMAILADDRESS as Email, 
 ac.ZACCOUNTDESCRIPTION as AccountDescription, 
 b.ZHTMLSTRING as HTMLString, 
 att.ZCONTENTID as ContentID, 
 att.ZFILEURL as FileURL
 FROM ZNOTE as n
 LEFT JOIN ZNOTEBODY as b ON b.ZNOTE = n.Z_PK
 LEFT JOIN ZATTACHMENT as att ON att.ZNOTE = n.Z_PK
 LEFT JOIN ZACCOUNT as ac ON ac.Z_PK = DirectoryParent'''))
 
 SELECT *, 
 if(condition=UploadFiles,then=if(condition=AttachmentLocation, then=upload(file=AttachmentLocation))) AS Upload
 FROM foreach(row=NotesList, query=NotesDetails)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.Safari.Downloads</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.safari.downloads/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.safari.downloads/</guid><description>&lt;p&gt;Parses Safari downloads for all standard macOS users&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: By default Safari download history is only retained for 24 hours&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.Safari.Downloads
description: |
 Parses Safari downloads for all standard macOS users
 
 **NOTE**: By default Safari download history is only retained for 24 hours

author: Deepak Sharma - @rxurien

type: CLIENT

precondition: SELECT OS From info() where OS = 'darwin'

parameters:
 - name: DownloadsPath
 default: /Users/*/Library/Safari/Downloads.plist
 - name: UserRegex
 default: .
 - name: UploadFile
 description: Upload Downloads.plist File
 type: bool

sources:
 - name: Downloads
 query: |
 LET DownloadsGlob = SELECT
 parse_string_with_regex(regex="/Users/(?P&amp;lt;User&amp;gt;[^/]+)", string=FullPath).User AS User,
 FullPath, Mtime, plist(file=FullPath) AS Content from glob(globs=DownloadsPath)
 
 SELECT * FROM foreach(row=DownloadsGlob, 
 query={
 SELECT * FROM foreach(row=Content.DownloadHistory, query={SELECT DownloadEntryDateAddedKey AS StartTime, DownloadEntryDateFinishedKey AS EndTime, User, DownloadEntryPath AS DownloadPath, DownloadEntryURL AS URL, DownloadEntryProgressBytesSoFar AS BytesDownloaded, DownloadEntryProgressTotalToLoad AS BytesTotal, DownloadEntryRemoveWhenDoneKey AS IncognitoDownload, FullPath AS FilePath from scope()})
 })
 
 - name: Upload
 query: |
 SELECT * FROM if(condition=UploadFile,
 then={
 SELECT User, FullPath AS FilePath,
 upload(file=FullPath) AS FileDetails 
 FROM DownloadsGlob
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.Safari.History</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.safari.history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.safari.history/</guid><description>&lt;p&gt;Parses Safari history database&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.Safari.History
description: |
 Parses Safari history database

author: Deepak Sharma - @rxurien

type: CLIENT

precondition: SELECT OS From info() where OS = 'darwin'

parameters:
 - name: HistoryPath
 default: /Users/*/Library/Safari/History.db
 - name: SQLQuery
 default: |
 SELECT * FROM history_visits INNER JOIN history_items ON history_items.id = history_visits.history_item;
 - name: UserRegex
 default: .
 - name: UploadFile
 description: Upload History.db File
 type: bool

sources:
 - name: History
 query: |
 LET history_db = SELECT
 parse_string_with_regex(regex="/Users/(?P&amp;lt;User&amp;gt;[^/]+)", string=FullPath).User AS User,
 FullPath
 FROM glob(globs=HistoryPath)

 SELECT * FROM foreach(row=history_db,
 query={
 SELECT timestamp(cocoatime=visit_time) AS VisitTime, User, title AS PageTitle, url AS URL, domain_expansion AS Domain, visit_count AS VisitCount, load_successful AS IsLoadSuccessful, FullPath AS FilePath
 FROM sqlite(
 file=FullPath,
 query=SQLQuery)
 })
 
 - name: Upload
 query: |
 SELECT * FROM if(condition=UploadFile,
 then={
 SELECT User, FullPath AS FilePath,
 upload(file=FullPath) AS FileDetails 
 FROM history_db
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Applications.SavedState</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.savedstate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.applications.savedstate/</guid><description>&lt;p&gt;On macOS, certain application state is saved in &lt;code&gt;/Users/*/Library/Saved Application State/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can check these files to determine the last time an application was opened, the title of the application window, and when the application/window was later restored, such as after login or reboot.&lt;/p&gt;
&lt;p&gt;In general, the following has been observed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;lsquo;SavedState&amp;rsquo; files are created when the application is started.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SavedState&lt;/code&gt; directory - &lt;code&gt;Btime&lt;/code&gt; - Last time the application was opened by the user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SavedState&lt;/code&gt; directory - &lt;code&gt;ModTime&lt;/code&gt; - When the application state was last restored (such as after login/reboot).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.data&lt;/code&gt; files - the actual data within the app, such as the scrollback for a &lt;code&gt;Terminal&lt;/code&gt; window. The data within can be an (AES-128-CBC) encrypted blob. This data can be decrypted using the appropriate &lt;code&gt;NSDataKey&lt;/code&gt; value found in &lt;code&gt;windows.plist&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.data&lt;/code&gt; - &lt;code&gt;ModTime&lt;/code&gt; - changes when new data is added to the state, for example, when interacting with the Terminal application.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;windows.plist&lt;/code&gt; &amp;ndash; contains the name of application windows (NSTitle, as well as other information such as:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NSDataKey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NSDockMenu.name&lt;/code&gt; &amp;ndash; names respective to the user&amp;rsquo;s dock/etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NSWindowID&lt;/code&gt; &amp;ndash; can be used to link the &lt;code&gt;NSDataKey&lt;/code&gt; to the &lt;code&gt;PersistentUIRecord&lt;/code&gt; value in the &lt;code&gt;data.data&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;windows.plist&lt;/code&gt; - &lt;code&gt;BTime&lt;/code&gt; - last time application was restored&lt;/li&gt;
&lt;li&gt;&lt;code&gt;windows.plist&lt;/code&gt; - &lt;code&gt;ModTime&lt;/code&gt; - changes when new data is added to the state, for example, when interacting with the Terminal application.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Applications.SavedState
description: |
 On macOS, certain application state is saved in `/Users/*/Library/Saved Application State/`. 
 
 We can check these files to determine the last time an application was opened, the title of the application window, and when the application/window was later restored, such as after login or reboot.
 
 In general, the following has been observed:
 
 - The 'SavedState' files are created when the application is started.
 - `SavedState` directory - `Btime` - Last time the application was opened by the user.
 - `SavedState` directory - `ModTime` - When the application state was last restored (such as after login/reboot).
 - `data.data` files - the actual data within the app, such as the scrollback for a `Terminal` window. The data within can be an (AES-128-CBC) encrypted blob. This data can be decrypted using the appropriate `NSDataKey` value found in `windows.plist`.
 - `data.data` - `ModTime` - changes when new data is added to the state, for example, when interacting with the Terminal application.
 - `windows.plist` -- contains the name of application windows (NSTitle, as well as other information such as:
 - `NSDataKey` 
 - `NSDockMenu.name` -- names respective to the user's dock/etc.
 - `NSWindowID` -- can be used to link the `NSDataKey` to the `PersistentUIRecord` value in the `data.data` file. 
 - `windows.plist` - `BTime` - last time application was restored
 - `windows.plist` - `ModTime` - changes when new data is added to the state, for example, when interacting with the Terminal application.
reference:
 - https://www.sans.org/blog/osx-lion-user-interface-preservation-analysis/
 - https://www.crowdstrike.com/blog/reconstructing-command-line-activity-on-macos/
type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: SavedStateGlob
 default: /Users/*/Library/Saved Application State/com.apple.**
- name: NameFilter
 default: .
 description: Filter used for targeting results by application name
- name: UserFilter
 default: .
 description: Filter used for targeting results by user name
precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET SavedStateList = SELECT ModTime,
 Btime,
 OSPath,
 regex_replace(source=OSPath[4], replace="", re=".savedState") AS Name,
 OSPath[1] AS _User
 FROM glob(globs=split(string=SavedStateGlob, sep=","))
 SELECT *,
 if(condition = OSPath =~ "windows.plist", then=items(item=plist(file=OSPath))._value.NSDockMenu.name)[0][0] AS DockMenuName,
 if(condition = OSPath =~ "windows.plist", then=items(item=plist(file=OSPath))._value.NSTitle)[0] AS WindowTitle,
 if(condition = OSPath =~ "windows.plist", then=plist(file=OSPath)) AS _WindowDetails
 FROM foreach(row=SavedStateList)
 WHERE Name =~ NameFilter
 AND _User =~ UserFilter

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Collection.Aftermath</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.collection.aftermath/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.collection.aftermath/</guid><description>&lt;p&gt;This is a simple artifact that leverages Afermath to collect many different forensic artifacts from a macOS host, then uploads the results to the Velociraptor server.&lt;/p&gt;
&lt;p&gt;From the project&amp;rsquo;s description:&lt;/p&gt;
&lt;p&gt;Aftermath is a Swift-based, open-source incident response framework.&lt;/p&gt;
&lt;p&gt;Aftermath can be leveraged by defenders in order to collect and subsequently analyze the data from the compromised host. Aftermath can be deployed from an MDM (ideally), but it can also run independently from the infected user&amp;rsquo;s command line.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jamf/aftermath" target="_blank" &gt;https://github.com/jamf/aftermath&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Collection.Aftermath
author: Wes Lambert -- @therealwlambert
description: |
 This is a simple artifact that leverages Afermath to collect many different forensic artifacts from a macOS host, then uploads the results to the Velociraptor server.

 From the project's description:

 Aftermath is a Swift-based, open-source incident response framework.

 Aftermath can be leveraged by defenders in order to collect and subsequently analyze the data from the compromised host. Aftermath can be deployed from an MDM (ideally), but it can also run independently from the infected user's command line.

 https://github.com/jamf/aftermath
 
tools:
 - name: Aftermath
 url: https://github.com/Velocidex/Tools/raw/main/Aftermath/aftermath
 serve_locally: true
parameters:
 - name: Analyze
 description: Analyze the collected data using the native --analyze option. This produces a ZIP file with summary information based on the analysis. If not chosen, the raw data will be uploaded.
 default: F
 type: bool
 
precondition: SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET AM &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Aftermath", IsExecutable=TRUE)
 LET TmpDir &amp;lt;= tempdir(remove_last=TRUE)
 Let RunIt = SELECT *
 FROM execve(argv=[
 AM.FullPath[0],
 "-o", TmpDir, 
 "--deep"
 ])
 LET AnalyzeIt = SELECT *
 FROM execve(argv=[
 AM.FullPath[0], "--analyze", grok(data=RunIt.Stdout,grok=["Aftermath archive moved to %{DATA:File}.zip"]).File + '.zip'
 ]) 
 SELECT upload(accessor="file", file=grok(data=Stdout,grok=["Aftermath archive moved to %{DATA:File}.zip"]).File + '.zip') AS Upload FROM if(condition=Analyze, then=AnalyzeIt, else=RunIt)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Files.FileMonitor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.files.filemonitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.files.filemonitor/</guid><description>&lt;p&gt;This artifact parses Objective-See&amp;rsquo;s FileMonitor log.&lt;/p&gt;
&lt;p&gt;More information about Objective-See and FileMonitor can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://objective-see.org/products/utilities.html" target="_blank" &gt;https://objective-see.org/products/utilities.html&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Files.FileMonitor
author: Wes Lambert -- @therealwlambert
description: |
 This artifact parses Objective-See's FileMonitor log.
 
 More information about Objective-See and FileMonitor can be found here:
 
 https://objective-see.org/products/utilities.html

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: JSONLGlob
 default:
 - name: FileRegex
 description: "Filter on file name"
 default: .
 type: regex
 - name: PathRegex
 description: "Filter on path name"
 default: .
 type: regex
 - name: ProcessRegex
 description: "Filter on process name"
 default: .
 type: regex
 - name: UserIdRegex
 description: "Filter on user ID"
 default: .
 type: regex
 
sources:

 - precondition:
 SELECT OS From info() where OS = 'windows' OR OS = 'linux' OR OS = 'darwin'

 query: |
 LET FileMonitorLogs &amp;lt;= SELECT FullPath FROM glob(globs=JSONLGlob)
 
 
 SELECT * FROM foreach(row={ 
 SELECT * FROM parse_jsonl(filename=FileMonitorLogs.FullPath)}, query={
 SELECT 
 timestamp(string=timestamp) AS Time,
 event AS Event,
 file.destination AS File,
 file.process.pid AS PID,
 file.process.name AS Process,
 file.process.path AS Path,
 file.process.uid AS UID,
 file.process.arguments AS Arguments,
 file.process.ppid AS `Parent PID`,
 file.process.ancestors AS Ancestors,
 file.process.`signing info (reported)` AS `Signing Info (Reported)`,
 file.process.`signing info (computed)` AS `Signing Info (Computed)`,
 file AS _Content
 FROM scope()
 WHERE File =~ FileRegex
 AND Path =~ PathRegex
 AND Process =~ ProcessRegex
 AND str(str=UID) =~ UserIdRegex
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Forensics.ASL</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.forensics.asl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.forensics.asl/</guid><description>&lt;p&gt;This artifact parses the ASL (Apple System Log) v2 files located at
/private/var/log/asl/*.asl&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Forensics.ASL

author: Yogesh Khatri (@swiftforensics), CyberCX

description: | 
 This artifact parses the ASL (Apple System Log) v2 files located at 
 /private/var/log/asl/*.asl

reference:
- https://github.com/apple-oss-distributions/Libc/blob/Libc-825.25/gen/asl_file.h

type: CLIENT

parameters:
 - name: GlobTable
 type: csv
 default: |
 Glob
 /private/var/log/asl/*.asl
 - name: PathRegex
 description: Filter the path by this regexp
 default: .
 - name: SenderRegex
 description: Filter the Sender by this regexp
 default: .
 - name: MessageRegex
 description: Filter the Message by this regexp
 default: .
 - name: KeyValueRegex
 description: Filter the Keys and Values by this regexp
 default: .
 - name: DateAfter
 type: timestamp
 description: "fetch logs after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: DateBefore
 type: timestamp
 description: "fetch logs before this date. YYYY-MM-DDTmm:hh:ssZ"

export: |
 LET AslProfile = '''[
 ["Header", 0, [
 ["Cookie", 0, "String", {
 "length": 12
 }],
 ["Version", 12, "uint32b"],
 ["First", 16, "uint64b"],
 ["Time", 24, "Timestamp", {
 type: "uint64b"
 }],
 ["Last", 37, "uint64b"],
 ["Items", "x=&amp;gt;x.First", "Array", {
 count: 10000,
 max_count: 10000,
 type: Message,
 sentinel: "x=&amp;gt;x.Last = x.StartOf",
 }],
 ]],
 ["Message", "x=&amp;gt;x.Next - x.StartOf", [
 ["Zero", 0, "uint16b"],
 ["Len", 2, "uint32b"],
 ["Next", 6, "uint64b"],
 ["ID", 14, "uint64b"],
 ["Time", 22, "Timestamp", {
 type: "uint64b"
 }],
 ["Nano", 30, "uint32b"],
 ["Level", 34, "Enumeration", {
 "type": "uint16b",
 "map": {
 "Emergency" : 0x00000000,
 "Alert" : 0x00000001, 
 "Critical" : 0x00000002, 
 "Error" : 0x00000003, 
 "Warning" : 0x00000004, 
 "Notice" : 0x00000005, 
 "Info" : 0x00000006, 
 "Debug" : 0x00000007,
 }
 }],
 ["Flags", 36, "uint16b"],
 ["PID", 38, "int32b"],
 ["UID", 42, "int32b"],
 ["GID", 46, "int32b"],
 ["RUID", 50, "int32b"],
 ["RGID", 54, "int32b"],
 ["RefPID", 58, "uint32b"],
 ["KVCount", 62, "uint32b"],
 ["Host", 66, "AslString"],
 ["Sender", 74, "AslString"],
 ["Facility", 82, "AslString"],
 ["Message", 90, "AslString"],
 ["RefProc", 98, "AslString"],
 ["Session", 106, "AslString"],
 ["KeyValues", 114, "Array", {
 count: "x=&amp;gt;x.KVCount/2",
 max_count: 25,
 type: KeyValuePair,
 }],
 ]],
 ["KeyValuePair", 16, [
 ["Key", 0, "AslString"],
 ["Val", 8, "AslString"],
 ["Pair", 0, "Value", { 
 "value": "x=&amp;gt;format(format='{%s:%s}', args=[x.Key.Info.str, x.Val.Info.str])",
 }],
 ]],
 ["AslString", 8, [
 ["z", 0, "int64b"],
 ["s", 0, "Value", { "value": "x=&amp;gt;if(condition=(x.z &amp;lt; 0), 
 then='INTERNAL', 
 else='EXTERNAL' )"
 }],
 ["Info", 0, "Union", {
 selector: "x=&amp;gt;x.s",
 choices: {
 "INTERNAL": "IntString",
 "EXTERNAL": "ExtString",
 }
 }],
 ]],
 ["IntString", 8, [
 ["z", 0, "uint8b"],
 ["actuallen", 0, "Value", { "value": "x=&amp;gt;if(condition=(x.z=0), 
 then=0, 
 else=x.z - 128)"
 }],
 ["str", 1, "String", { encoding: "utf8", length: "x=&amp;gt;x.actuallen" }],
 ]],
 ["ExtString", 8, [
 ["Offset", 0, "uint64b"],
 ["Str", 0, "Profile", {
 type: "ExtString2",
 offset: "x=&amp;gt;x.Offset",
 }],
 ["str", 0, "Value", { "value": "x=&amp;gt;x.Str.str" }],
 ]],
 ["ExtString2", "x=&amp;gt;x.len + 6", [
 ["one", 0, "uint16b"],
 ["len", 2, "uint32b"],
 ["str", 6, "String", { encoding: "utf8", length: "x=&amp;gt;x.len" }],
 ]],
 ]'''

precondition: SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET files = SELECT OSPath, Mtime, Btime
 FROM glob(globs=GlobTable.Glob)
 WHERE log(message=OSPath)

 SELECT * FROM foreach(row=files,
 query={
 SELECT ID, Time, Level, PID, UID, GID, RUID, RGID, RefPID, //KVCount, 
 Host.Info.str as Host, 
 Sender.Info.str as Sender,
 Facility.Info.str as Facility,
 Message.Info.str as Message,
 RefProc.Info.str as RefProc,
 Session.Info.str as Session,
 KeyValues.Pair as KeyValues,
 OSPath as SourcePath
 //OSPath.Basename as SourceFile
 FROM 
 foreach(row=parse_binary(
 filename=read_file(filename=OSPath, length=1000000),
 accessor="data",
 profile=AslProfile, struct="Header").Items)
 WHERE if(condition=DateAfter, then= Time &amp;gt; DateAfter, else= True )
 AND if(condition=DateBefore, then= Time &amp;lt; DateBefore, else= True )
 })
 WHERE EntryPath =~ PathRegex
 AND Sender =~ SenderRegex
 AND Message =~ MessageRegex
 AND KeyValues =~ KeyValueRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Forensics.KnockKnock</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/knockknock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/knockknock/</guid><description>&lt;p&gt;This artifact will run Knocknock to collect autorun output.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Forensics.KnockKnock
author: Matt Green - @mgreen27
description: |
 This artifact will run Knocknock to collect autorun output.

reference:
 - https://objective-see.org/products/knockknock.html

required_permissions:
 - EXECVE

tools:
 - name: KnockKnock
 url: https://github.com/objective-see/KnockKnock/releases/download/v2.5.0/KnockKnock_2.5.0.zip
 expected_hash: 1ba31195a8312b97c40955db3c554947b261a82c319d29cface4619fa50f3daa
 version: 2.5.0
 serve_locally: true
 

precondition: SELECT OS From info() where OS = 'darwin'

parameters:
 - name: IncludeAppleItems
 description: Include apple/system items.
 type: bool
 - name: QueryVT
 description: If Selected will query VirusTotal. Using this switch is not reccomended - enrich server side instead.
 type: bool

sources:
 - name: Authorization Plugins
 query: |
 LET tool &amp;lt;= SELECT *
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="KnockKnock", IsExecutable='N')
 LET tempfolder &amp;lt;= tempdir()
 
 LET bin &amp;lt;= SELECT * FROM unzip(filename=tool.OSPath[0],output_directory=tempfolder)
 
 LET other_commands = if(condition=IncludeAppleItems AND QueryVT,
 then= ['-apple'],
 else = if(condition=IncludeAppleItems AND NOT QueryVT,
 then= ['-apple','-skipVT'],
 else = if(condition= NOT IncludeAppleItems AND NOT QueryVT,
 then= ['-skipVT'],
 else= '')))
 
 LET results &amp;lt;= SELECT parse_json(data=Stdout) as KnockKnockResults 
 FROM execve(argv=[tempfolder + '/KnockKnock.app/Contents/MacOS/KnockKnock','-whosthere',other_commands],length=10000000)

 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Authorization Plugins`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Browser Extensions
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Browser Extensions`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Background Managed Tasks
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Background Managed Tasks`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Cron Jobs
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Cron Jobs`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Dir. Services Plugins
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Dir. Services Plugins`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Dock Tiles Plugins
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Dock Tiles Plugins`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Event Rules
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Event Rules`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Extensions and Widgets
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Extensions and Widgets`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Kernel Extensions
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Kernel Extensions`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Launch Items
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Launch Items`,
 query={SELECT * FROM foreach(row=_value)} )

 - name: Library Inserts
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Library Inserts`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Library Proxies
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Library Proxies`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Login Items
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Login Items`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Login/Logout Hooks
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Login/Logout Hooks`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Periodic Scripts
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Periodic Scripts`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Quicklook Plugins
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Quicklook Plugins`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Library Inserts
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Library Inserts`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Spotlight Importers
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Spotlight Importers`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: Startup Scripts
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`Startup Scripts`,
 query={SELECT * FROM foreach(row=_value)} )
 
 - name: System Extensions
 query: |
 SELECT * FROM foreach(
 row=results.KnockKnockResults.`System Extensions`,
 query={SELECT * FROM foreach(row=_value)} )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Logs.MacMonitor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.logs.macmonitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.logs.macmonitor/</guid><description>&lt;p&gt;This artifact parses JSONL-formatted logs generated by MacMonitor.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Logs.MacMonitor
description: |
 This artifact parses JSONL-formatted logs generated by MacMonitor.
reference:
 - https://github.com/redcanaryco/mac-monitor 
parameters:
 - name: JSONLGlob
 default:
 - name: ProcessRegex
 description: "Filter on process name"
 default: .
 type: regex
 - name: InitiatingProcessRegex
 description: "Filter on initiating process name"
 default: .
 type: regex

sources:
 - query: |
 LET MacMonitorLogs &amp;lt;= SELECT FullPath FROM glob(globs=JSONLGlob)
 SELECT 
 activity_at_ts AS Timestamp,
 substr(start=14, str=es_event_type) AS EventType,
 target AS ProcessName,
 initiating_process_path AS InitiatingProcessPath,
 initiating_process_name AS InitiatingProcessName,
 initiating_pid AS InitiatingPID,
 initiating_process_signing_id AS InitiatingProcessSigningID,
 initiating_ruid_human AS InitiatingUser,
 initiating_euid_human AS InitiatingEffectiveUser,
 initiating_ruid AS InitiatingUserId,
 initiating_ruid AS InitiatingEffectiveUserId,
 initiating_process_group_id AS InitiatingProcessGID,
 initiating_process_file_quarantine_type AS InitiatingProcessQuarantineType,
 initiating_process_cdhash AS InitiatingProcessCDHash,
 audit_token AS AuditToken,
 responsible_audit_token AS ResponseAuditToken,
 parent_audit_token AS ParentAuditToken,
 macOS AS OSVersion,
 sensor_id AS SensorId,
 path_is_truncated AS PathIsTruncated//,
 //fork_event AS ForkEvent
 FROM parse_jsonl(accessor="file", filename=MacMonitorLogs.FullPath)
 WHERE ProcessName =~ ProcessRegex AND 
 InitiatingProcessName =~ InitiatingProcessRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Network.ApplicationLayerFirewall</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.applicationlayerfirewall/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.applicationlayerfirewall/</guid><description>&lt;p&gt;This artifact provides information around the configuration of the application firewall for a macOS host.&lt;/p&gt;
&lt;p&gt;This can be useful for auditing to ensure compliance, overall safety, or to identify tampering with allowed application connections or firewall-related restrictions.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Network.ApplicationLayerFirewall
description: |
 This artifact provides information around the configuration of the application firewall for a macOS host. 
 
 This can be useful for auditing to ensure compliance, overall safety, or to identify tampering with allowed application connections or firewall-related restrictions.
 
type: CLIENT

author: Wes Lambert - @therealwlambert

precondition: SELECT OS FROM info() WHERE OS =~ 'darwin'

parameters:
 - name: ALFGlob
 default: /Library/Preferences/com.apple.alf.plist

sources:
 - query: |
 SELECT 
 if(condition=globalstate, then="Enabled", else="Disabled") AS GlobalState,
 if(condition=allowsignedenabled, then="Yes", else="No") AS AllowSigned,
 if(condition=allowdownloadsignedenabled, then="Yes", else="No") AS AllowDLSigned,
 if(condition=loggingenabled, then="Yes", else="No") AS LoggingEnabled,
 if(condition=stealthenabled, then="Yes", else="No") AS StealthEnabled,
 version AS Version,
 explicitauths.id AS ExplicitAuths,
 firewall AS Applications
 FROM plist(file=ALFGlob)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Network.Bluetooth</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.bluetooth/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.bluetooth/</guid><description>&lt;p&gt;Collect information about connected or paired Bluetooth-enabled devices.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Network.Bluetooth

type: CLIENT

author: Wes Lambert - @therealwlambert

description: |
 Collect information about connected or paired Bluetooth-enabled devices.

parameters:
 - name: BluetoothGlob
 default: /Library/Bluetooth/Library/Preferences/com.apple.MobileBluetooth.devices.plist

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET BluetoothLocation = SELECT OSPath from glob(globs=BluetoothGlob)
 LET BluetoothDevices = SELECT plist(file=OSPath) AS BD FROM BluetoothLocation
 SELECT * from foreach(
 row=BluetoothDevices,
 query={
 SELECT _value.Name AS Name,
 timestamp(epoch=_value.LastSeenTime) AS LastSeen,
 _value.DefaultName AS Description,
 base64decode(string=_value.DeviceClass) AS _DeviceClass,
 _value.DeviceIdProduct AS DeviceIDProduct,
 _value.DeviceIdVendor AS DeviceIdVendor,
 _value.DeviceIdVendorSource AS DeviceIdVendorSource,
 _value.DeviceIdVersion AS DeviceIdVersion,
 _value.SerialPort AS SerialPort,
 _value.ServiceRemote AS SerialRemote,
 _value.initiateSDPMirroringState AS SDPMirroring,
 _key AS MACAddress,
 _value.DevicePrimaryHash AS DevicePrimaryHash,
 _value AS _Value
 FROM items(item=BD)
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Network.DHCP</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.dhcp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.dhcp/</guid><description>&lt;p&gt;It can be useful to view DHCP lease information on an endpoint. If the &lt;code&gt;LeaseLength&lt;/code&gt;, &lt;code&gt;RouterIPAddress&lt;/code&gt;, &lt;code&gt;SSID&lt;/code&gt;, or other values are not as expected, it could potentially indicate a rogue DHCP server on the network, or just misconfiguration.&lt;/p&gt;
&lt;p&gt;Either way, the information provided by this artifact can be used to help defenders find unexpected DHCP lease configuration.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Network.DHCP
description: |
 It can be useful to view DHCP lease information on an endpoint. If the `LeaseLength`, `RouterIPAddress`, `SSID`, or other values are not as expected, it could potentially indicate a rogue DHCP server on the network, or just misconfiguration.
 
 Either way, the information provided by this artifact can be used to help defenders find unexpected DHCP lease configuration.
reference:
 - https://attack.mitre.org/techniques/T1557/003/
type: CLIENT
author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange
parameters:
- name: LeaseGlob
 default: /private/var/db/dhcpclient/leases/*.plist
- name: UploadFiles
 default: 
 type: bool 
precondition:
 SELECT OS From info() where OS = 'darwin'
sources:
 - query: |
 LET LeaseList = SELECT Mtime, OSPath
 FROM glob(globs=split(string=LeaseGlob, sep=","))
 
 SELECT * FROM foreach(row=LeaseList,
 query={
 SELECT Mtime,
 OSPath,
 regex_replace(re='''.plist''', replace='', source=basename(path=OSPath)) AS Interface,
 RouterIPAddress,
 SSID,	
 ClientIdentifier AS _ClientIdentifier,	
 IPAddress,	
 LeaseLength,	
 LeaseStartDate,	
 PacketData AS _PacketData,	
 RouterHardwareAddress AS _RouterHardwareAddress,
 OSPath AS _FullPath
 FROM plist(file=OSPath)})
 - name: Upload
 query: |
 -- if configured upload DHCP lease files
 SELECT * FROM if(condition=UploadFiles,
 then={
 SELECT
 upload(file=OSPath) as DHCPLeaseFile
 FROM LeaseList
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Network.LittleSnitch</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.littlesnitch/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.littlesnitch/</guid><description>&lt;p&gt;This is artifact parses Little Snitch&amp;rsquo;s network traffic log.&lt;/p&gt;
&lt;p&gt;More information about Little Snitch can be found here:
&lt;a href="https://www.obdev.at/products/littlesnitch/index.html" target="_blank" &gt;https://www.obdev.at/products/littlesnitch/index.html&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Network.LittleSnitch
author: Wes Lambert -- @therealwlambert
description: |
 This is artifact parses Little Snitch's network traffic log.
 
 More information about Little Snitch can be found here:
 https://www.obdev.at/products/littlesnitch/index.html

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: CSVGlob
 default:
 - name: ExecutableRegex
 description: "Filter on executable name"
 default: .
 type: regex
 - name: IPRegex
 description: "Filter on IP address"
 default: .
 type: regex
 - name: ParentRegex
 description: "Filter on parent exectuable"
 default: .
 type: regex
 - name: RemoteHostnameRegex
 description: "Filter on IP remote hostname"
 default: .
 type: regex
 
sources:

 - precondition:
 SELECT OS From info() where OS = 'windows' OR OS = 'linux' OR OS = 'darwin'

 query: |
 LET LittleSnitchLogs &amp;lt;= SELECT FullPath FROM glob(globs=CSVGlob)
 LET ProtocolTable &amp;lt;= SELECT * from parse_csv(accessor="data", filename='''
 Number,ProtocolName
 1,ICMP
 6,TCP
 17,UDP
 ''')
 SELECT * FROM foreach(row={ 
 SELECT
 timestamp(string=date) AS Time,
 direction AS Direction,
 uid AS UID,
 ipAddress AS `IP Address`,
 remoteHostname AS `Remote Hostname`,
 if(condition=ProtocolTable.ProtocolName[0], then=ProtocolTable.ProtocolName[0], else=protocol) AS Protocol,
 port AS Port,
 connectCount AS `Connect Count`,
 denyCount AS `Deny Count`,
 byteCountIn AS `Bytes In`,
 byteCountOut AS `Bytes Out`,
 connectingExecutable AS `Executable`,
 parentAppExecutable AS `Parent`
 FROM parse_csv(filename=LittleSnitchLogs.FullPath)})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Network.RecentWifiNetworks</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.recentwifinetworks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.network.recentwifinetworks/</guid><description>&lt;p&gt;This artifact looks for recent Wifi networks to which a host has joined. This can be useful in determining where a machine has been, or if a user has joined an illegitimate or unauthorized wireless network.
*Tested on macOS Monterey&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Network.RecentWifiNetworks

description: 
 This artifact looks for recent Wifi networks to which a host has joined. This can be useful in determining where a machine has been, or if a user has joined an illegitimate or unauthorized wireless network.
 
 *Tested on macOS Monterey

type: CLIENT

author: Wes Lambert - @therealwlambert

parameters:
 - name: RecentWifiNetworksGlob
 default: /Library/Logs/com.apple.wifi.recent-networks.json

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET RecentNetworksLocation = SELECT OSPath from glob(globs=RecentWifiNetworksGlob)
 LET RecentNetworks = SELECT parse_json(data=read_file(filename=OSPath)) AS RN FROM RecentNetworksLocation
 LET EachNetwork = SELECT * from foreach(
 row=RecentNetworks,
 query={
 SELECT _key AS Network, _value AS Value
 FROM items(item=RN)
 }
 )
 SELECT Network AS Network,
 base64decode(string=Value.SSID) AS SSID,
 Value.AddReason AS AddReason,
 Value.AddedAt AS AddedAt,
 Value.UpdatedAt AS UpdatedAt,
 Value.JoinedByUserAt AS JoinedByUserAt,
 Value.JoinedBySystemAt AS JoinedBySystemAt,
 Value.SupportedSecurityTypes AS SupportedSecurityTypes,
 Value.Hidden AS Hidden,
 Value.SystemMode AS SystemMode,
 Value.CaptiveProfile.CaptiveNetwork AS CaptiveNetwork,
 Value.__OSSpecific__.ChannelHistory AS ChannelHistory,
 Value.__OSSpecific__.CollocatedGroup AS _CollocatedGroup,
 Value.PasspointSPRoamingEnabled AS _PasspointSPRoamingEnabled,
 Value AS _Data
 FROM EachNetwork

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.ParallelsVM.SuspendedMemory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.parallelsvm.suspendedmemory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.parallelsvm.suspendedmemory/</guid><description>&lt;p&gt;Looks for suspended Parallels VM owned by any user on a MacOS system. Can automatically upload the virtual memory files if found.&lt;/p&gt;
&lt;p&gt;If a &amp;ldquo;*.mem.sh&amp;rdquo; file exists, that VM is running and not suspended.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Uploading the Parallels memory file can take a while due to the size.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.ParallelsVM.SuspendedMemory
description: |
 Looks for suspended Parallels VM owned by any user on a MacOS system. Can automatically upload the virtual memory files if found.
 
 If a "*.mem.sh" file exists, that VM is running and not suspended.
 
 **NOTE:** Uploading the Parallels memory file can take a while due to the size.

type: CLIENT

author: Brady Semm - @btsemm

precondition: SELECT OS From info() where OS = 'darwin'

parameters:
 - name: ParallelsMemoryPath
 default: "/Users/*/Parallels/*.pvm/{*.mem,*.mem.sh}"
 - name: UploadFiles
 type: bool

sources:
 - name: ParallelsMemoryFiles
 query: |
 LET ParallelsMemoryFiles &amp;lt;= SELECT parse_string_with_regex(regex="/Users/(?P&amp;lt;User&amp;gt;[^/]+)", string=FullPath).User AS User,
 parse_string_with_regex(regex="/Users/[^/]+/Parallels/(?P&amp;lt;VMName&amp;gt;[^\.]+).pvm", string=FullPath).VMName AS VMName,
 FullPath, File, Mtime, Size
 FROM glob(globs=ParallelsMemoryPath)
 
 SELECT User, VMName, Mtime, Size, FullPath
 FROM ParallelsMemoryFiles
 
 - name: Uploads
 query: |
 SELECT * FROM if(condition=UploadFiles,
 then={
 SELECT FullPath, User, VMName, Mtime,
 upload(file=FullPath) as FileDetails
 FROM ParallelsMemoryFiles
 WHERE FullPath =~ ".*\.mem$"
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Sys.Automator</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.sys.automator/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.sys.automator/</guid><description>&lt;p&gt;This artifact collects information about Automator actions and workflows.&lt;/p&gt;
&lt;p&gt;It can be used to identify malicious actions inserted into common/default workflows, or non-standard workflows.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Sys.Automator
description: |
 This artifact collects information about Automator actions and workflows. 
 
 It can be used to identify malicious actions inserted into common/default workflows, or non-standard workflows.
 
reference:
 - https://support.apple.com/en-ae/guide/automator/welcome/mac
 
type: CLIENT

author: Wes Lambert - @therealwlambert

precondition: SELECT OS FROM info() WHERE OS =~ 'darwin'

parameters:
 - name: ActionGlob
 default: /System/Library/Automator/*/Contents/Info.plist 
 - name: WorkflowGlob
 default: /Library/Application Support/Apple/Automator/Workflows/*/Contents/*.wflow
 - name: UploadActions
 default: N
 type: bool
 - name: UploadWorkflows
 default: N
 type: bool
 
sources:
 - name: Actions
 query: 
 LET ActionLocation = SELECT * from glob(globs=ActionGlob)
 LET Actions = SELECT OSPath, Mtime, Atime, Ctime, Btime, plist(file=OSPath) AS AMAction FROM ActionLocation
 SELECT * from foreach(
 row=Actions,
 query={
 SELECT Mtime AS Timestamp,
 get(field="AMName") AS Name,
 get(field="AMApplication") AS Application,
 get(field="AMIconName") AS IconName,
 get(field="CFBundleExecutable") AS ExecutableName,
 get(field="NSPrincipalClass") AS PrincipalClass,
 get(field="CFBundleIdentifier") AS BundleIdentifier,
 get(field="AMDefaultParameters") AS DefaultParameters,
 get(field="NSHumanReadableCopyright") AS Copyright,
 get(field="AMDescription") AS Description,
 if(condition=UploadActions,
 then=upload(file=OSPath,
 mtime=Mtime,
 atime=Atime,
 ctime=Ctime,
 btime=Btime)) AS Upload,
 AMAction AS _Content
 FROM AMAction
 }
 )
 
 - name: Workflows
 query: |
 LET WorkflowLocation = SELECT * from glob(globs=WorkflowGlob)
 LET Workflows = SELECT OSPath, Mtime, Atime, Ctime, Btime, plist(file=OSPath) AS AMWorkflow FROM WorkflowLocation
 SELECT * from foreach(
 row=Workflows,
 query={
 SELECT
 Mtime AS Timestamp, 
 OSPath AS Name,
 get(member="actions.action.ActionName") AS Actions, 
 get(field="state") AS State,
 get(field="WorkflowIsShared") AS Shared,
 get(field="workflowMetaData") AS WorkflowMetadata,
 get(field="connectors") AS Connectors,
 if(condition=UploadWorkflows,
 then=upload(file=OSPath,
 mtime=Mtime,
 atime=Atime,
 ctime=Ctime,
 btime=Btime)) AS Upload,
 AMWorkflow AS _Content
 FROM AMWorkflow
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.Sys.BashHistory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.sys.bashhistory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.sys.bashhistory/</guid><description>&lt;p&gt;This artifact is a modified version of the Linux.Sys.BashHistory artifact that enables grep of Bash and alternate shell history and &lt;em&gt;session&lt;/em&gt; files.&lt;/p&gt;
&lt;p&gt;Session files can be helpful in determining an approximate timeframe in which certain commands were run (the session start/end time), as traditional history files do not provide this information.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.swiftforensics.com/2018/05/bash-sessions-in-macos.html" target="_blank" &gt;http://www.swiftforensics.com/2018/05/bash-sessions-in-macos.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can also be used to target other files located in the user profile such as
&lt;em&gt;_profile and &lt;em&gt;rc files.
shell history: /{root,home/&lt;/em&gt;}/.&lt;/em&gt;_history
profile: /{root,home/&lt;em&gt;}/.&lt;/em&gt;_profile
&lt;em&gt;rc file: /{root,home/&lt;/em&gt;}/.*rc&lt;/p&gt;
&lt;p&gt;tags: .bash_history .bash_profile .bashrc&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.Sys.BashHistory
author: Wes Lambert - @therealwlambert
description: |
 This artifact is a modified version of the Linux.Sys.BashHistory artifact that enables grep of Bash and alternate shell history and *session* files.

 Session files can be helpful in determining an approximate timeframe in which certain commands were run (the session start/end time), as traditional history files do not provide this information. 
 
 http://www.swiftforensics.com/2018/05/bash-sessions-in-macos.html

 This artifact can also be used to target other files located in the user profile such as
 *_profile and *rc files.
 shell history: /{root,home/*}/.*_history
 profile: /{root,home/*}/.*_profile
 *rc file: /{root,home/*}/.*rc

 tags: .bash_history .bash_profile .bashrc

reference:
 - http://www.swiftforensics.com/2018/05/bash-sessions-in-macos.html

parameters:
 - name: HistoryGlob
 default: /Users/*/.*_history
 - name: SessionsGlob
 default: /Users/*/.{bash,zsh}_sessions/*.history
 - name: SearchRegex
 type: regex
 description: "Regex of strings to search in line."
 default: '.'
 - name: WhitelistRegex
 type: regex
 description: "Regex of strings to leave out of output."
 default:

sources:
 - name: History
 query: |
 SELECT * FROM Artifact.Linux.Sys.BashHistory(TargetGlob=HistoryGlob,SearchRegex=SearchRegex,WhitelistRegex=WhitelistRegex)
 
 - name: Sessions
 query: |
 LET files = SELECT FullPath, Btime FROM glob(globs=SessionsGlob)
 SELECT * FROM foreach(row=files,
 query={
 SELECT Line,
 {SELECT Btime FROM glob(globs=FullPath + 'new')} AS SessionStarted, 
 Btime AS SessionEnded,
 timestamp(
 string=grok(
 data=read_file(
 filename=split(
 string=FullPath, 
 sep='''\.history''')[0] + '.session'), grok='''echo Restored session: "\$\(/bin/date -r %{DATA:date}\)"''').date) AS SessionResumed,
 FullPath 
 FROM parse_lines(filename=FullPath)
 WHERE Line =~ SearchRegex 
 AND NOT if(condition= WhitelistRegex, then= Line =~ WhitelistRegex, else= FALSE)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.System.LocationServices</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.locationservices/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.locationservices/</guid><description>&lt;p&gt;This artifact looks for applications that are registered and allowed for use of location services by checking the plist file in &lt;code&gt;/var/db/locationd/clients.plist&lt;/code&gt;.&lt;br&gt;
This can be useful to help determine if these settings have been modified by an attacker to perform location tracking.&lt;/p&gt;
&lt;p&gt;For more information about how location services could be abused, see the following:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://medium.com/@slyd0g/where-in-the-world-is-carmen-sandiego-abusing-location-services-on-macos-10e9f4eefb71" target="_blank" &gt;https://medium.com/@slyd0g/where-in-the-world-is-carmen-sandiego-abusing-location-services-on-macos-10e9f4eefb71&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.System.LocationServices
description: |
 This artifact looks for applications that are registered and allowed for use of location services by checking the plist file in `/var/db/locationd/clients.plist`. 
 This can be useful to help determine if these settings have been modified by an attacker to perform location tracking.
 
 For more information about how location services could be abused, see the following:
 
 https://medium.com/@slyd0g/where-in-the-world-is-carmen-sandiego-abusing-location-services-on-macos-10e9f4eefb71

type: CLIENT

author: Wes Lambert - @therealwlambert

parameters:
 - name: LocationPath
 default: /var/db/locationd/clients.plist

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET LocGlob &amp;lt;= SELECT FullPath FROM glob(globs=LocationPath)
 LET LocationPlist = SELECT * FROM plist(file=LocGlob.FullPath)
 LET SepApps = SELECT * FROM foreach(row={SELECT _value AS Apps FROM items(item=LocationPlist)}, query={SELECT _value AS App FROM items(item=Apps)})
 SELECT
 App.BundleId AS BundleId,
 App.BundlePath As BundlePath,
 App.Whitelisted AS Whitelisted,
 App.Authorized AS Authorized,
 App.Hide AS Hide,
 App.Registered As Registered,
 App.Requirement AS Requirement,
 App AS _Data
 FROM SepApps

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.System.Man</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.man/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.man/</guid><description>&lt;p&gt;&lt;code&gt;man&lt;/code&gt; is typically used to provide information about how to use various commands. It&amp;rsquo;s configuration file is located at &lt;code&gt;/private/etc/man.conf&lt;/code&gt; on most macOS systems.&lt;/p&gt;
&lt;p&gt;While root access is required to do so, this configuration could be modified by an adversary to stealthily achieve persistence in an environment.&lt;/p&gt;
&lt;p&gt;This artifact collects any entries in &lt;code&gt;man.conf&lt;/code&gt; which appear to specify a non-default binary for use with &lt;code&gt;man&lt;/code&gt; or &lt;code&gt;whatis&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.System.Man

type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

description: |
 `man` is typically used to provide information about how to use various commands. It's configuration file is located at `/private/etc/man.conf` on most macOS systems.
 
 While root access is required to do so, this configuration could be modified by an adversary to stealthily achieve persistence in an environment. 
 
 This artifact collects any entries in `man.conf` which appear to specify a non-default binary for use with `man` or `whatis`.

reference:
 - https://theevilbit.github.io/beyond/beyond_0030
 - https://www.youtube.com/watch?v=teq6r7XbBug

parameters:
 - name: ManGlob
 default: /private/etc/man.conf
 description: Default file path for `man` configuration.

precondition:
 SELECT OS From info() where OS = 'darwin'

sources:
 - query: |
 LET ManList = SELECT OSPath, Mtime FROM glob(globs=split(string=ManGlob, sep=","))
 SELECT * FROM foreach(
 row=ManList, 
 query={ 
 SELECT 
 OSPath, 
 Mtime, 
 Line 
 FROM parse_lines(filename=OSPath) 
 WHERE Line =~ '^(MAN|WHATIS||)PAGER' 
 AND NOT Line =~ "/usr/bin/less|/usr/bin/more" })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.System.MountedDiskImages</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.mounteddiskimages/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.system.mounteddiskimages/</guid><description>&lt;p&gt;This artifact checks for mounted disk images using the &lt;code&gt;hdiutil&lt;/code&gt; command.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.System.MountedDiskImages
description: |
 This artifact checks for mounted disk images using the `hdiutil` command.
author: Wes Lambert -- @therealwlambert|@weslambert@infosec.exchange
required_permissions:
 - EXECVE
sources:
 - query: |
 LET MountedDMGs &amp;lt;= SELECT * FROM execve(argv=['/usr/bin/hdiutil', 'info', '-plist'])
 SELECT _value.`image-path` AS Image,
 _value.`system-entities`.`mount-point`[0] AS MountPoint,
 _value AS ImageDetails
 FROM items(item=plist(accessor="data", file=MountedDMGs.Stdout).images)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.UnifiedLogHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedloghunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedloghunter/</guid><description>&lt;p&gt;This artifact allows for live hunting through Apple&amp;rsquo;s Unified Logs using the native &lt;code&gt;log&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;The Unified Logs can be a great resource for learning about system events. There are many logging subsystems that can provide a wealth of data for investigators.&lt;/p&gt;
&lt;p&gt;However, users should ensure their searches are scoped appropriately (date/time/event type/etc), as a lot of data can be returned, which could affect the ability to review the collected data or potentially impact client performance.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Predicate&lt;/code&gt; parameter can be used to filter logs. Example filters are included as artifact parameters.&lt;/p&gt;
&lt;p&gt;Users may need to adjust the &lt;code&gt;Length&lt;/code&gt; parameter to accomodate a large number of events being returned.&lt;/p&gt;
&lt;p&gt;If you would like to perform an offline collection, or only care about collecting the raw files associated with this data, consider using &lt;a href="https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedlogparser/" target="_blank" &gt;Exchange.MacOS.UnifiedLogParser&lt;/a&gt;
.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.UnifiedLogHunter
description: |
 This artifact allows for live hunting through Apple's Unified Logs using the native `log` command.

 The Unified Logs can be a great resource for learning about system events. There are many logging subsystems that can provide a wealth of data for investigators.

 However, users should ensure their searches are scoped appropriately (date/time/event type/etc), as a lot of data can be returned, which could affect the ability to review the collected data or potentially impact client performance.

 The `Predicate` parameter can be used to filter logs. Example filters are included as artifact parameters.

 Users may need to adjust the `Length` parameter to accomodate a large number of events being returned.

 If you would like to perform an offline collection, or only care about collecting the raw files associated with this data, consider using [Exchange.MacOS.UnifiedLogParser](https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedlogparser/).
reference:
 - https://github.com/jamf/jamfprotect/tree/main/unified_log_filters
 - https://www.mandiant.com/resources/blog/reviewing-macos-unified-logs
 - https://skartek.dev/2022/05/04/unified-logging-for-macos-an-introduction/
 - https://www.crowdstrike.com/blog/how-to-leverage-apple-unified-log-for-incident-response/
 - https://devstreaming-cdn.apple.com/videos/wwdc/2016/721wh2etddp4ghxhpcg/721/721_unified_logging_and_activity_tracing.pdf
type: CLIENT
author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange
parameters:
 - name: StartDate
 type: timestamp
 - name: EndDate
 default:
 type: timestamp
 - name: Predicate
 description: Use a custom filter
 default:
 type: string
 - name: RunAllQueries
 description: Run all preconfigured filters. You may need to increase the default timeout of 600s.
 type: bool
 - name: Configuration Profile - Manual Install
 description: Look for manual install of a configuration profile
 type: bool
 - name: Configuration Profile - Manual Removal
 description: Look for anual removal of a configuration profile
 type: bool
 - name: DNS configuration changes
 description: Look for modifications made to host DNS settings
 type: bool
 - name: Failed Lock Screen Unlock
 description: Look for failures to unlock the lock screen
 type: bool
 - name: Failed Local Password Login
 description: Look for failures for local logins using a password
 type: bool
 - name: Successful Local Password Login
 description: Look for successful logins using a password
 type: bool
 - name: Failed Local TouchID Login
 description: Look for local TouchID logins
 type: bool
 - name: Failed sudo access
 description: Look for failed usage of 'sudo'
 type: bool
 - name: Gatekeeper File Access Rejections and User Bypasses
 description: Look for Gatekeeper file access rejections and user bypasses
 type: bool
 - name: Gatekeeper File Access Scan Activity
 description: Look for Gatekeeper file access scan activity
 type: bool
 - name: Inbound screen sharing
 description: Look for inbound screen sharing
 type: bool
 - name: Kernel Extension Additions
 description: Look for changes made to kernel extensions
 type: bool
 - name: Keychain DB Unlock
 description: Look for keychain database unlock attempts
 type: bool
 - name: Permissions and Access Violations
 description: Looks for TCC permisssions and access violations
 type: bool
 - name: Session Creation and Destruction
 description: Looks for session creation and Destruction
 type: bool
 - name: SSH Login Activity
 description: Look for SSH login failures and successes
 type: bool
 - name: Successful Local TouchID Login
 description: Look for successful TouchID logins
 type: bool
 - name: Sudo access
 type: bool
 description: Look for general 'sudo' usage
 - name: MDM Profile - Manual Removal
 type: bool
 description: Look for the removal of MDM profiles
 - name: Network server connection attempts inbound
 type: bool
 description: Look for inbound network connection attempts
 - name: Root user enabled or password changed
 type: bool
 description: Look for changes to the root user configuration
 - name: XProtect Remediator scanning activity
 type: bool
 description: Look for XProtect scanning activity
 - name: Length
 type: int
 default: 10000000
required_permissions:
 - EXECVE
precondition: SELECT OS From info() where OS = 'darwin' AND StartDate AND EndDate
sources:
 - query: |
 LET QueryTable = SELECT * FROM parse_csv(accessor="data", filename='''
 QueryName,Q
 Airdrop Transfer Outbound,subsystem == "com.apple.sharing" AND process == "AirDrop" AND processImagePath BEGINSWITH "/System/Library" AND eventMessage BEGINSWITH "Successfully issued sandbox extension for"
 Application Firewall Logging,subsystem == "com.apple.alf"
 Configuration Profile - Manual Install,subsystem == "com.apple.ManagedClient" AND process == "mdmclient" AND category == "MDMDaemon" and eventMessage CONTAINS "Installed configuration profile:" AND eventMessage CONTAINS "Source: Manual"
 Configuration Profile - Manual Removal,subsystem == "com.apple.ManagedClient" AND process == "mdmclient" AND category == "MDMDaemon" and eventMessage CONTAINS "Removed configuration profile:" AND eventMessage CONTAINS "Source: Manual"
 DNS configuration changes,subsystem == "com.apple.networkextension" and process == "nehelper" and eventMessage CONTAINS "DNS settings are enabled" OR subsystem == "com.apple.networkextension" and process == "nesessionmanager" and eventMessage contains "status changed to disconnected, last stop reason Configuration was disabled"'
 Gatekeeper File Access Rejections and User Bypasses,subsystem == "com.apple.launchservices" AND process == "CoreServicesUIAgent" AND category == "uiagent" AND (eventMessage BEGINSWITH "Saving rejection record:" OR eventMessage CONTAINS "Gatekeeper rejection record")
 Gatekeeper File Access Scan Activity,subsystem == "com.apple.syspolicy.exec" AND process == "syspolicyd" AND category == "default"
 Failed Lock Screen Unlock,processImagePath BEGINSWITH "/System/Library/CoreServices" AND process == "loginwindow" AND eventMessage CONTAINS[c] "INCORRECT"
 Failed Local Password Login,processImagePath BEGINSWITH "/System/" AND process == "SecurityAgent" AND subsystem == "com.apple.loginwindow" AND eventMessage CONTAINS "Authentication failure"
 Failed Local TouchID Login,process == "loginwindow" AND eventMessage CONTAINS[c] "APEventTouchIDNoMatch"
 Failed Local User Password Change,subsystem == "com.apple.opendirectoryd" AND process == "opendirectoryd" AND category == "auth" AND eventMessage CONTAINS "Failed to change password"
 Failed sudo access,process == "sudo" AND eventMessage CONTAINS[c] "TTY" AND eventMessage CONTAINS[c] "3 incorrect password attempts"
 Inbound screen sharing,process == "screensharingd" AND eventMessage BEGINSWITH "Authentication: "
 Kernel Extension Additions,process == "kextd" &amp;amp;&amp;amp; sender == "IOKit"
 Keychain DB Unlock,process == "loginwindow" &amp;amp;&amp;amp; sender == "Security"
 MDM Profile - Manual Removal,subsystem == "com.apple.ManagedClient" AND eventMessage CONTAINS "Removed configuration profile: MDM Profile" AND eventMessage CONTAINS "Source: Manual"
 Network server connection attempts inbound,process == "NetAuthSysAgent" AND subsystem == "com.apple.NetAuthAgent" AND category == "IPC" AND eventMessage BEGINSWITH "URL = "
 Permissions and Access Violations,process == "tccd"
 Root user enabled or password changed,processImagePath == "/usr/libexec/opendirectoryd" AND process == "opendirectoryd" AND subsystem == "com.apple.opendirectoryd" AND eventMessage CONTAINS "Password changed for root"
 Session Creation and Destruction,process == "securityd" &amp;amp;&amp;amp; eventMessage CONTAINS "Session" &amp;amp;&amp;amp; subsystem == "com.apple.securityd"
 SSH Login Activity,process == "sshd"
 Successful Local Password Login,processImagePath BEGINSWITH "/System/Library/CoreServices" AND process == "loginwindow" AND subsystem == "com.apple.loginwindow.logging" AND eventMessage CONTAINS "[Login1 doLogin] | shortUsername"
 Successful Local TouchID Login,process == "loginwindow" AND eventMessage CONTAINS[c] "APEventTouchIDMatch"
 Successful Local User Password Change,subsystem == "com.apple.opendirectoryd" AND process == "opendirectoryd" AND category == "auth" AND eventMessage CONTAINS "Password changed for"
 XProtect Remediator scanning activity,subsystem == "com.apple.XProtectFramework.PluginAPI" &amp;amp;&amp;amp; category == "XPEvent.structured"''')

 LET QueriesToRun &amp;lt;= SELECT Q FROM QueryTable WHERE if(condition=RunAllQueries, then=QueryName, else=get(field=QueryName))

 LET Raw &amp;lt;= SELECT * FROM foreach(row={ SELECT * FROM chain( a=QueriesToRun, b=if(condition=Predicate, then={ SELECT Predicate AS Q FROM scope()}))},
 query={ SELECT Stdout FROM execve(
 length=Length,
 argv=[
 "log",
 "show",
 "--start",
 grok(grok="%{TIMESTAMP_ISO8601:Date}", data=StartDate).Date,
 "--end",
 grok(grok="%{TIMESTAMP_ISO8601:Date}", data=EndDate).Date,
 "--predicate",
 Q,
 "--style",
 "json"])}, async=TRUE) WHERE NOT Stdout = "[]"
 SELECT
 timestamp(string=get(member="timestamp")) AS EventTime,
 get(member="machTimestamp") AS _TimeSinceBoot,
 get(member="traceID") AS _TraceID,
 get(member="eventMessage") AS EventMessage,
 get(member="eventType") AS EventType,
 get(member="messageType") AS MessageType,
 get(member="category") AS Category,
 get(member="subsystem") AS Subsystem,
 get(member="processID") AS PID,
 get(member="processImagePath") AS ProcessImagePath,
 get(member="processImageUUID") AS ProcessImageUUID,
 get(member="senderImagePath") AS SenderImagePath,
 get(member="senderImageUUID") AS SenderImageUUID,
 get(member="senderProgramCounter") AS SenderProgramCounter,
 get(member="source") AS _Source,
 get(member="formatString") AS _FormatString,
 get(member="activityIdentifier") AS ActivityID,
 get(member="parentActivityIdentifier") AS ParentActivityID,
 get(member="threadID") AS _ThreadID,
 get(member="backtrace") AS _Backtrace,
 get(member="bootUUID") AS _BootUUID,
 get(member="timezoneName") AS _TimezoneName
 FROM foreach(row=Raw.Stdout, query={SELECT * FROM parse_json_array(data=_value)})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MacOS.UnifiedLogParser</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedlogparser/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macos.unifiedlogparser/</guid><description>&lt;p&gt;This is a simple, un-optimized artifact that leverages Mandiant&amp;rsquo;s &lt;code&gt;macos-unifiedlogs&lt;/code&gt;/&lt;code&gt;unifiedlog_parser&lt;/code&gt; to obtain parsed log information from macOS&amp;rsquo;s Unified Log.&lt;/p&gt;
&lt;p&gt;From the project&amp;rsquo;s description:&lt;/p&gt;
&lt;p&gt;A simple Rust library that can help parse the macOS Unified Log files.&lt;/p&gt;
&lt;p&gt;Unified Logs were introduced in macOS version 10.12 (Sierra, 2016). Part of Apple&amp;rsquo;s goal to create a unified log format for all Apple products. They exist on macOS, iOS, watchOS, tvOS. The Unified Logs replace many of the old log formats Apple used. This simple library can be used to parse files.&lt;/p&gt;
&lt;p&gt;Additional information: &lt;a href="https://github.com/mandiant/macos-UnifiedLogs" target="_blank" &gt;https://github.com/mandiant/macos-UnifiedLogs&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: MacOS.UnifiedLogParser
description: |

 This is a simple, un-optimized artifact that leverages Mandiant's `macos-unifiedlogs`/`unifiedlog_parser` to obtain parsed log information from macOS's Unified Log.

 From the project's description:
 
 A simple Rust library that can help parse the macOS Unified Log files.

 Unified Logs were introduced in macOS version 10.12 (Sierra, 2016). Part of Apple's goal to create a unified log format for all Apple products. They exist on macOS, iOS, watchOS, tvOS. The Unified Logs replace many of the old log formats Apple used. This simple library can be used to parse files.

 Additional information: https://github.com/mandiant/macos-UnifiedLogs

author: Wes Lambert - @therealwlambert

reference:
 - https://www.mandiant.com/resources/blog/reviewing-macos-unified-logs

required_permissions:
 - EXECVE

precondition: SELECT OS From info() where OS = 'darwin'

tools:
 - name: UnifiedLogParser
 url: https://github.com/mandiant/macos-UnifiedLogs/releases/download/v1.0.0/unifiedlog_parser

sources:
 - query: |
 LET ULP &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="UnifiedLogParser")
 LET RunULP &amp;lt;= SELECT * FROM execve(argv=["./" + basename(path=ULP.FullPath[0])], cwd=dirname(path=ULP.FullPath[0]))
 SELECT * FROM parse_csv(accessor="file", filename=dirname(path=ULP.FullPath[0]) + "/output.csv")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Notebooks.Admin.Flows</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/notebooks.admin.flows/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/notebooks.admin.flows/</guid><description>&lt;p&gt;This notebooks lists all recent flows/collections across all orgs on the
platform. It may be used for auditing or as a means of finding a collection
previously scheduled.&lt;/p&gt;
&lt;p&gt;By default it will only look for the last five flows per client, and return a
maximum of 50 flows altogether. Adjust the LIMITs as needed. Hunts are ignored
by default, but may be included by setting IgnoreHunts to True.&lt;/p&gt;
&lt;p&gt;Links are created for clients and flows, but in order for these to work, you
need to set the &lt;a href="https://docs.velociraptor.app/app/index.html?org_id=root#/host/server" &gt;server metadata&lt;/a&gt;

field &amp;ldquo;VelociraptorServerURL&amp;rdquo;. If not set, https://127.0.0.1:8889 is used.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Notebooks.Admin.Flows
author: Andreas Misje – @misje
description: |
 This notebooks lists all recent flows/collections across all orgs on the
 platform. It may be used for auditing or as a means of finding a collection
 previously scheduled.

 By default it will only look for the last five flows per client, and return a
 maximum of 50 flows altogether. Adjust the LIMITs as needed. Hunts are ignored
 by default, but may be included by setting IgnoreHunts to True.

 Links are created for clients and flows, but in order for these to work, you
 need to set the [server metadata](/app/index.html?org_id=root#/host/server)
 field "VelociraptorServerURL". If not set, https://127.0.0.1:8889 is used.

type: NOTEBOOK

sources:
 - notebook:
 - type: markdown
 template: |
 # Recent flows (all orgs)

 - type: vql
 output: |
 &amp;lt;&amp;lt; Latest flows: Click here to customise and calculate &amp;gt;&amp;gt;
 template: |
 LET ColumnTypes = dict(`Client`='url', `Flow`='url')

 LET IgnoreHunts = True

 -- In order to create links to clients and flows, the server URL is needed
 -- (relative links do not work when specifying org ID). The server metadata
 -- field "VelociraptorServerURL", used by some other artifacts, is used for
 -- this:
 LET ServerURL = get(
 item=server_metadata(),
 field='VelociraptorServerURL',
 default='https://127.0.0.1:8889')

 /*
 Last refreshed at {{ Get ( Query "SELECT timestamp(epoch=now()) AS Refreshed FROM scope()" | Expand ) "0.Refreshed" }}
 */

 SELECT *
 FROM foreach(
 row={
 SELECT Name,
 OrgId
 FROM orgs()
 },
 query={
 SELECT
 Name AS Org,
 *
 FROM query(
 org_id=OrgId,
 -- Pass these variables to the scope:
 env=dict(IgnoreHunts=IgnoreHunts, ServerURL=ServerURL),
 query={
 SELECT *
 FROM foreach(
 row={
 SELECT client_id,
 os_info.hostname AS Hostname,
 timestamp(epoch=first_seen_at) AS FirstSeenAt
 FROM clients()
 },
 query={
 SELECT
 format(
 format='[%v](%v/app/index.html?org_id="%v"#/host/%v)',
 args=[Hostname, ServerURL, org().id, client_id]) AS Client,
 -- It may be useful to know whether the collection was run
 -- because the client was new at the time:
 timestamp(
 epoch=start_time).Unix - FirstSeenAt.Unix &amp;lt; 60 AS _NewClient,
 format(
 format='[%v](%v/app/index.html?org_id="%v"#/collected/%v/%v)',
 -- Use the first artifact name (capped to 30 chars) as link name:
 args=[request.artifacts[0][:30] + '…', ServerURL, org().id, client_id, session_id]) AS Flow,
 session_id =~ '.H$' AS _IsHunt,
 timestamp(
 epoch=create_time) AS Created,
 timestamp(
 epoch=active_time) AS LastActive,
 request.creator AS Creator,
 state AS State,
 status AS Status,
 -- Create a more readable dict with artifact parameters arguments,
 -- using the artifact name as key, and as value, a dict with parameter
 -- name and values):
 to_dict(
 item={
 SELECT
 artifact AS _key,
 to_dict(
 item={
 SELECT
 key AS _key,
 value AS _value
 FROM foreach(
 row=parameters.env)
 }) AS _value
 FROM foreach(
 row=request.specs)
 }) AS _Requested,
 artifacts_with_results AS WithResults,
 format(
 format='%.1f',
 args=[execution_duration / 1000000000.0]) AS _Duration,
 total_collected_rows AS _Rows,
 total_uploaded_files AS _FilesUploaded
 FROM flows(client_id=client_id)
 WHERE NOT IgnoreHunts OR NOT session_id =~ '.H$'
 ORDER BY Created DESC
 LIMIT 5
 },
 -- This query is ideal for parallel execution (it is also necessary):
 workers=50)
 })
 })
 ORDER BY Created DESC
 LIMIT 50


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>PSList.VTLookup</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/pslist.vtlookup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/pslist.vtlookup/</guid><description>&lt;p&gt;Combination of PSList with Virus Total reputation lookup using the Virus Total Server Enrichment Artifact by Wes Lambert.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: PSList.VTLookup
description: |
 Combination of PSList with Virus Total reputation lookup using the Virus Total Server Enrichment Artifact by Wes Lambert.

type: CLIENT

author: Chris Jones - CPIRT

parameters:
 - name: VTKey
 default: VTKey

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

 query: |
 LET Key &amp;lt;= VTKey

 LET Results = SELECT Name,Pid,Ppid,Username,{
 Select Name FROM pslist(pid=Ppid)
 } AS ParentName,hash(path=Exe).SHA1 AS SHA1,
 CommandLine, Exe FROM pslist()

 SELECT *, {SELECT VTRating FROM Artifact.Server.Enrichment.Virustotal(VirustotalKey=VTKey,Hash=SHA1)} AS VTResults
 FROM foreach(row=Results)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Alerts.GenericMonitor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/genericmonitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/genericmonitor/</guid><description>&lt;p&gt;This is a template artifact to allow alerting on a monitoring artifact.&lt;/p&gt;
&lt;p&gt;Simply enter ArtifactName and modify VQL as desired.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Alerts.GenericMonitor
description: |
 This is a template artifact to allow alerting on a monitoring artifact.
 
 Simply enter ArtifactName and modify VQL as desired.
 
 
type: SERVER_EVENT

parameters:
 - name: ArtifactName
 default: Windows.ETW.ETWSessions

sources:
 - query: |
 SELECT * from watch_monitoring(artifact=ArtifactName)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Alerts.IRIS.Case.Create</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.iris.case.create/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.iris.case.create/</guid><description>&lt;p&gt;Create an IRIS case when monitored artifacts complete with results. Adds the ClientId, FlowId as tags to the case. Adds the FQDN as an asset.&lt;/p&gt;
&lt;p&gt;Learn more about IRIS, here: &lt;a href="https://dfir-iris.org/" target="_blank" &gt;https://dfir-iris.org/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;It is recommended to use the Server Metadata section to store credentials, instead of having to store directly inside the artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Alerts.IRIS.Case.Create
description: |
 Create an IRIS case when monitored artifacts complete with results. Adds the ClientId, FlowId as tags to the case. Adds the FQDN as an asset.
 
 Learn more about IRIS, here: https://dfir-iris.org/
 
 It is recommended to use the Server Metadata section to store credentials, instead of having to store directly inside the artifact.

type: SERVER_EVENT

author: Wes Lambert - @therealwlambert

parameters:
 - name: IrisURL
 default:
 - name: IrisKey
 type: string
 description: API key for DFIR-IRIS. Leave blank here if using server metadata store.
 default:
 - name: ArtifactsToAlertOn
 default: .
 type: regex
 - name: DisableSSLVerify
 type: bool
 default: true
 - name: Customer
 default: 1
 - name: SOCId
 default: soc_id_demo
 
sources:
 - query: |
 LET URL &amp;lt;= if(
 condition=IrisURL,
 then=IrisURL,
 else=server_metadata().IrisURL)
 LET Creds = if(
 condition=IrisKey,
 then=IrisKey,
 else=server_metadata().IrisKey)
 LET FlowInfo = SELECT timestamp(epoch=Timestamp) AS Timestamp,
 client_info(client_id=ClientId).os_info.fqdn AS FQDN,
 ClientId, FlowId, Flow.artifacts_with_results[0] AS FlowResults
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ ArtifactsToAlertOn

 LET Cases = SELECT * FROM foreach(row=FlowInfo,
 query={
 SELECT ClientId, FlowId, FQDN, parse_json(data=Content).data.case_id AS CaseID FROM http_client(
 data=serialize(item=dict(
 case_name=format(format="Hit on %v for %v", args=[FlowResults, FQDN]), case_soc_id="soc_id_demo", case_customer=1, case_description=format(format="ClientId: %v\n\nFlowID: %v\n\nURL: %v//app/index.html?#/collected/%v/%v", args=[ClientId, FlowId, config.server_urls[0], ClientId, FlowId,])), format="json"),
 headers=dict(`Content-Type`="application/json", `Authorization`=format(format="Bearer %v", args=[Creds])),
 disable_ssl_security=DisableSSLVerify,
 method="POST",
 url=format(format="%v/manage/cases/add", args=[URL]))
 })
 
 SELECT * from foreach(row=Cases,
 query={
 SELECT * FROM http_client(
 data=serialize(
 item=dict(
 asset_name=FQDN, 
 asset_type_id=9, 
 analysis_status_id=1, 
 cid=CaseID, 
 asset_tags=format(format="%v,%v", args=[ClientId, FlowId])
 )
 ,format="json"
 ),
 headers=dict(`Content-Type`="application/json", `Authorization`=format(format="Bearer %v", args=[Creds])),
 disable_ssl_security=DisableSSLVerify,
 method="POST",
 url=format(format="%v/case/assets/add", args=[URL]))
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Alerts.Mattermost</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.mattermost/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.mattermost/</guid><description>&lt;p&gt;Create a Slack/Mattermost notification when a client Flow (with artifacts of interest) has finished. Cancelled collections and collections with artifacts that don&amp;rsquo;t satisfy preconditions do not create notifications when they are stopped.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Alerts.Mattermost
description: |
 Create a Slack/Mattermost notification when a client Flow (with artifacts of interest) has finished. Cancelled collections and collections with artifacts that don't satisfy preconditions do not create notifications when they are stopped.

type: SERVER_EVENT

author: Andreas Misje – @misje

parameters:
 - name: WebhookURL
 description: |
 Webhook used to for posting the notification. If empty, the server metadata variable "MattermostWebhookURL" will be used.
 - name: VelociraptorServerURL
 description: |
 The Velociraptor server URL, e.g. "https://velociraptor.example.org", used to build links to flows and clients in the notification payload. If empty, the server metadata variable "VelociraptorServerURL" is used. If that variable is also empty, no links will be created.
 - name: Decorate
 description: |
 Whether the notification payload should be "decorated" using the legacy "secondary attachments" format, supported by both Slack and Mattermost. If false, a single string will be sent.
 type: bool
 default: Y
 - name: ArtifactsToAlertOn
 description: |
 Notifications will only be created for finished flows with artifact names matching this regex.
 default: .
 type: regex
 - name: ArtifactsToIgnore
 description: |
 Notifications will not be created for finished flows with artifact names matching this regex.
 default: ^Generic.Client.Info
 - name: NotifyHunts
 description: |
 Create notifications for finished flows that are part of a hunt. This may produce a lot of notifications, depending on the number of clients that will take part in the hunt.
 type: bool
 - name: DelayThreshold
 description: |
 Only create notifications if the flow has not finished within a certain number of seconds since it was created.
 default: 10

sources:
 - query: |
 LET NotifyUrl = if(
 condition=WebhookURL,
 then=WebhookURL,
 else=server_metadata().MattermostWebhookURL
 )
 Let ServerUrl = if(
 condition=VelociraptorServerURL,
 then=VelociraptorServerURL,
 else=server_metadata().VelociraptorServerURL
 )
 
 // Get basic information about completed flows: 
 LET CompletedFlows = SELECT timestamp(epoch=Timestamp) AS FlowFinished,
 ClientId,
 FlowId
 FROM watch_monitoring(artifact='System.Flow.Completion')
 WHERE Flow.artifacts_with_results
 AND ClientId != 'server'
 AND NOT Flow.artifacts_with_results =~ ArtifactsToIgnore
 AND Flow.artifacts_with_results =~ ArtifactsToAlertOn
 
 // Look up more details about the flows using flows(), since the data returned by watch_monitoring() may be incomplete (like the create_time field):
 LET FlowInfo = SELECT ClientId,
 client_info(client_id=ClientId).os_info.fqdn AS FQDN,
 FlowId,
 timestamp(epoch=create_time) AS FlowCreated,
 timestamp(epoch=start_time) AS FlowStarted,
 FlowFinished,
 execution_duration/1000000000 AS Duration,
 join(array=artifacts_with_results, sep=', ') AS FlowResults,
 total_collected_rows AS CollectedRows,
 total_uploaded_files AS UploadedFiles,
 total_uploaded_bytes AS UploadedBytes,
 state='FINISHED' AS Success,
 status AS Error
 FROM flows(client_id=ClientId, flow_id=FlowId)
 // Filter out flows part of hunts (if enabled) by the trailing ".H" in the ID:
 WHERE if(condition=NotifyHunts, then=true, else=not FlowId=~'\.H$')
 // Notifications aren't necessarily useful if collections complete close to immediately:
 AND FlowFinished.Unix - timestamp(epoch=create_time).Unix &amp;gt;= atoi(string=DelayThreshold)
 
 LET Results = SELECT *
 FROM foreach(row=CompletedFlows, query=FlowInfo)
 
 // If ServerUrl is provided, create Markdown links to the client, flows and hunt:
 LET ClientLink = if(condition=ServerUrl,
 then=format(format='[%v](%v/app/index.html#/host/%v)', args=[
 FQDN, ServerUrl, ClientId
 ]),
 else=FQDN
 )
 LET FlowUrl = format(format='%v/app/index.html#/collected/%v/%v/notebook', args=[
 ServerUrl, ClientId, FlowId
 ])
 LET FlowLink = if(condition=ServerUrl,
 then=format(format='[%v](%v)', args=[
 FlowId, FlowUrl
 ]),
 else=str(str=FlowId)
 )
 // The HuntId has to be fetched by looking for the FlowId in all hunts:
 LET AllHunts = SELECT hunt_id AS HuntId,
 hunt_description AS HuntDesc
 FROM hunts()
 LET OurHunt(Fid) = SELECT *
 FROM foreach(
 row=AllHunts,
 query={SELECT HuntId, HuntDesc FROM hunt_flows(hunt_id=HuntId) WHERE FlowId=Fid}
 )
 LET HuntLink_ = SELECT HuntDesc, HuntId
 FROM OurHunt(Fid=FlowId)
 LET HuntLink = if(
 condition=ServerUrl AND HuntLink_.HuntId,
 then=format(format='[%v](%v/app/index.html#/hunts/%v)', args=[
 // There should only ever be one hunt for this flow:
 HuntLink_[0].HuntDesc, HuntLink_[0].ServerUrl, HuntLink_[0].HuntId 
 ]),
 else=if(condition=HuntLink_.HuntId, then=str(str=HuntLink_[0].HuntId), else='–')
 )
 LET StateString = if(condition=Success, then='finished collecting', else='FAILED to collect')
 LET Message = format(format='Client %v has %v the artifact(s) %v, started at %v, in flow %v', args=[
 ClientLink, StateString, FlowResults, FlowStarted.String, FlowLink
 ])
 // Create a more readable notification by using the formatting option called "secondary attachments". It's deemed a legacy format by Slack, but it works in Mattermost (whereas newer formatting options in Slack does not):
 LET Decorated = dict(
 attachments=[dict(
 mrkdwn_in=['text'],
 // Use a green colour if the collection succeeded, and red if it failed. The third state "RUNNING" should never be present in flows in this query:
 color=if(condition=Success, then='#36a64f', else='#e40303'),
 pretext=Message,
 title=format(format='Client collection %v', args=[if(condition=Success, then='FINISHED', else='FAILED')]),
 title_link=if(condition=ServerUrl, then=FlowUrl, else=null),
 fields=[
 dict(
 title='Collection created',
 value=FlowCreated.String,
 short=true
 ),
 dict(
 title='Collection started',
 value=FlowStarted.String,
 short=true
 ),
 dict(
 title='Error',
 value=if(condition=Error, then=Error, else='–'),
 short=true
 ),
 dict(
 title='Hunt',
 value=if(condition=HuntLink, then=HuntLink, else='–'),
 short=true
 ),
 dict(
 title='Duration',
 value=format(format='%.1f s', args=[Duration]),
 short=true
 ),
 dict(
 title='Collected rows',
 value=CollectedRows,
 short=true
 ),
 dict(
 title='Uploaded files',
 value=UploadedFiles,
 short=true
 ),
 dict(
 title='Uploaded bytes',
 value=UploadedBytes,
 short=true
 ),
 ]
 ),]
 )
 LET Payload = if(condition=Decorate, then=Decorated, else=Message)
 
 LET Notify = SELECT Response, Content
 FROM http_client(
 data=serialize(item=Payload, format='json'),
 headers=dict(`Content-Type`='application/json'),
 method='POST',
 url=NotifyUrl
 )
 WHERE NotifyUrl
 AND if(condition=Response=200,
 then=log(level='INFO', message='Notification sent'),
 else=log(level='WARN', message=format(format='Failed to send notification: Reponse: %v', args=[Response]))
 )

 SELECT * FROM foreach(row=Results, query=Notify)
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Alerts.Monitor.IRIS</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.monitor.iris/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.monitor.iris/</guid><description>&lt;p&gt;Create an IRIS alert when monitored artifacts complete with results. Alerts are available starting in version 2.1.0 of IRIS.
&lt;a href="https://github.com/dfir-iris/iris-web/releases/tag/v2.1.0" target="_blank" &gt;https://github.com/dfir-iris/iris-web/releases/tag/v2.1.0&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Learn more about IRIS, here: &lt;a href="https://dfir-iris.org/" target="_blank" &gt;https://dfir-iris.org/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;It is recommended to use the Server Metadata section to store credentials, instead of having to store directly inside the artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Alerts.Monitor.IRIS
description: |
 Create an IRIS alert when monitored artifacts complete with results. Alerts are available starting in version 2.1.0 of IRIS.
 https://github.com/dfir-iris/iris-web/releases/tag/v2.1.0
 
 Learn more about IRIS, here: https://dfir-iris.org/
 
 It is recommended to use the Server Metadata section to store credentials, instead of having to store directly inside the artifact.

type: SERVER_EVENT

author: Wes Lambert - @therealwlambert

parameters:
 - name: IrisURL
 default: 
 - name: IrisKey
 type: string
 description: API key for DFIR-IRIS. Leave blank here if using server metadata store.
 default:
 - name: VeloServerURL
 default: 
 - name: ArtifactsToAlertOn
 default: .
 type: regex
 - name: DisableSSLVerify
 type: bool
 default: true
 - name: Customer
 default: 1
 - name: Severity 
 default: 1
 - name: Status 
 default: 1
 
sources:
 - query: |
 LET URL &amp;lt;= if(
 condition=IrisURL,
 then=IrisURL,
 else=server_metadata().IrisURL)
 LET Creds = if(
 condition=IrisKey,
 then=IrisKey,
 else=server_metadata().IrisKey)
 LET FlowInfo = SELECT timestamp(epoch=Timestamp) AS Timestamp,
 client_info(client_id=ClientId).os_info.fqdn AS FQDN,
 ClientId, FlowId, Flow.artifacts_with_results[0] AS FlowResults
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ ArtifactsToAlertOn
 
 SELECT * from foreach(row=FlowInfo,
 query={
 SELECT ClientId, FlowId, FQDN, parse_json(data=Content).data.alert_title AS Alert, parse_json(data=Content).data.alert_id AS AlertID 
 FROM http_client(
 data=serialize(item=dict(
 alert_title=format(format="Hit on %v for %v", args=[FlowResults, FQDN]), 
 alert_description=format(format="ClientId: %v\n\nFlowID: %v\n\nURL: %v//app/index.html?#/collected/%v/%v", args=[ClientId, FlowId, config.server_urls[0], ClientId, FlowId,]),
 alert_severity_id=Severity,
 alert_status_id=Status,
 alert_customer_id=Customer)),
 headers=dict(`Content-Type`="application/json", `Authorization`=format(format="Bearer %v", args=[Creds])),
 disable_ssl_security=DisableSSLVerify,
 method="POST",
 url=format(format="%v/alerts/add", args=[URL]))})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Alerts.TrackNetworkConnections</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.tracknetworkconnections/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.alerts.tracknetworkconnections/</guid><description>&lt;p&gt;This artifact alerts on network connections tracked by Velociraptor on clients.
Requires the client_event artifact &amp;lsquo;Generic.Events.TrackNetworkConnections&amp;rsquo; to be enabled.&lt;/p&gt;
&lt;p&gt;You can filter alerts based on FQDN of the client, process name, remote ip and remote port.
Only created network connections are alerted on (meaning you don&amp;rsquo;t get an alert when the system removes the connection).
You should use those filters, else there be spam to be had :D&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Alerts.TrackNetworkConnections
author: Herbert Bärschneider @SEC Consult
description: |
 This artifact alerts on network connections tracked by Velociraptor on clients.
 Requires the client_event artifact 'Generic.Events.TrackNetworkConnections' to be enabled.
 
 You can filter alerts based on FQDN of the client, process name, remote ip and remote port.
 Only created network connections are alerted on (meaning you don't get an alert when the system removes the connection).
 You should use those filters, else there be spam to be had :D

type: SERVER_EVENT

parameters:
 - name: WebHook
 description: The token URL obtained from Slack/Teams/Discord (or basicly any communication-service that supports webhooks). Leave blank to use server metadata. e.g. https://hooks.slack.com/services/XXXX/YYYY/ZZZZ
 - name: ClientRegex
 type: regex
 description: Regex for filtering on the client fqdn name
 - name: ProcessNameRegex
 type: regex
 description: Regex for filtering on the process name - does not cover full path of the process image
 - name: RemoteIpRegex
 type: regex
 description: Regex for filtering on the remote ip connected to
 - name: RemotePortRegex
 type: regex
 description: Regex for filtering on the remote port connected to

sources:
 - query: |
 SELECT * FROM foreach(
 row={
 SELECT *, client_info(client_id=ClientId).os_info.fqdn AS Fqdn from watch_monitoring(artifact='Exchange.Generic.Events.TrackNetworkConnections')
 WHERE Fqdn =~ ClientRegex AND ProcInfo.Data.Name =~ ProcessNameRegex AND Raddr.IP =~ RemoteIpRegex AND format(format="%v", args=Raddr.Port) =~ RemotePortRegex
 AND Diff =~ "added"
 },
 query={
 SELECT * FROM http_client(
 data=serialize(item=dict(
 text=format(format="client %v has process %v communicate to remote ip %v on remote port %v",
 args=[Fqdn, ProcInfo.Data.Name, Raddr.IP, Raddr.Port])),
 format="json"),
 headers=dict(`Content-Type`="application/json"),
 method="POST",
 url=WebHook)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Analysis.CyberChefServer</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/cyberchefserver/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/cyberchefserver/</guid><description>&lt;p&gt;Analyze/transform data with CyberChef-server.&lt;/p&gt;
&lt;p&gt;Note that this requires an accessible Cyberchef-server instance to
work.&lt;/p&gt;
&lt;p&gt;If you prefer not to run a local instance, you might consider
altering the artifact to leverage something like
&lt;a href="https://prod.apifor.io" target="_blank" &gt;https://prod.apifor.io&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;: &lt;a href="https://github.com/gchq/CyberChef-server" target="_blank" &gt;https://github.com/gchq/CyberChef-server&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact to
analyze/transform the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Exchange.Analysis.CyberchefServer(Input=$YOURDATA,Recipe=$YOURRECIPE)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If a default recipe is used, only the input will need to be passed, like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Exchange.Analysis.CyberchefServer(Input=$YOURDATA)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The server metadata store can be used to store the URL of
Cyberchef-server (with a key value of &lt;code&gt;CyberChefServerURL&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Examples of recipes can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/mattnotmax/cyberchef-recipes" target="_blank" &gt;https://github.com/mattnotmax/cyberchef-recipes&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Analysis.CyberChefServer
author: Wes Lambert -- @therealwlambert
description: |
 Analyze/transform data with CyberChef-server.

 Note that this requires an accessible Cyberchef-server instance to
 work.

 If you prefer not to run a local instance, you might consider
 altering the artifact to leverage something like
 https://prod.apifor.io.

 **Reference**: https://github.com/gchq/CyberChef-server

 **Examples**:

 This artifact can be called from within another artifact to
 analyze/transform the data made available by that artifact.

 `SELECT * from Artifact.Exchange.Analysis.CyberchefServer(Input=$YOURDATA,Recipe=$YOURRECIPE)`

 If a default recipe is used, only the input will need to be passed, like so:

 `SELECT * from Artifact.Exchange.Analysis.CyberchefServer(Input=$YOURDATA)`


 The server metadata store can be used to store the URL of
 Cyberchef-server (with a key value of `CyberChefServerURL`).

 Examples of recipes can be found here:

 https://github.com/mattnotmax/cyberchef-recipes

type: server

parameters:
 - name: Url
 description: URL of CyberChef-server
 default: https://mycyberchefserver
 - name: Input
 type: string
 default:
 description: The data to send to Cyberchef-server.
 - name: Recipe
 type: string
 description: CyberChef recipe to use for processing data.
 default:
 - name: DisableSSLVerify
 type: bool
 default: True

sources:
 - queries:
 - |
 LET CCS_Url = if(
 condition=Url,
 then=Url,
 else=server_metadata().CyberChefServerURL)
 - |
 LET BakedData = SELECT parse_json(data=Content).value AS TransformedValue from http_client(url=CCS_Url + "/bake", method='POST', headers=dict(`Content-Type`='application/json'), data=dict(`input`=Input, `recipe`=parse_json_array(data=Recipe)), disable_ssl_security=DisableSSLVerify)
 - |
 SELECT * FROM BakedData

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.AI.Anthropic</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/anthropic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/anthropic/</guid><description>&lt;p&gt;Query Anthropic AI for analysis of data.&lt;/p&gt;
&lt;p&gt;Paramaters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PrePrompt&lt;/code&gt; - Added as preprompt. Default is:
&amp;ldquo;You are a Cyber Incident Responder and need to analyze data. You have an eye
for detail and like to use short precise technical language. Analyze the
following data and provide summary analysis:&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prompt&lt;/code&gt; - Is User prompt as string: When pushing a dict object via
PromtData good practice is add some strings related to the type of data for
analysis or artifact name to provide context.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PromptData&lt;/code&gt; - add optional object to be serialized and added to the User prompt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Model&lt;/code&gt; - Model to use for your request. Default is claude-3-7-sonnet-20250219&lt;/li&gt;
&lt;li&gt;AnthropicVersion - anthropic-version header&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxTokens&lt;/code&gt; - Set max token size default 64000&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking
for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.AI.Anthropic
author: Matt Green - @mgreen27
description: |
 Query Anthropic AI for analysis of data.
 
 Paramaters:
 
 * `PrePrompt` - Added as preprompt. Default is: 
 "You are a Cyber Incident Responder and need to analyze data. You have an eye 
 for detail and like to use short precise technical language. Analyze the 
 following data and provide summary analysis:"
 * `Prompt` - Is User prompt as string: When pushing a dict object via 
 PromtData good practice is add some strings related to the type of data for 
 analysis or artifact name to provide context.
 * `PromptData` - add optional object to be serialized and added to the User prompt.
 * `Model` - Model to use for your request. Default is claude-3-7-sonnet-20250219
 * AnthropicVersion - anthropic-version header
 * `MaxTokens` - Set max token size default 64000
 
 This artifact can be called from within another artifact (such as one looking 
 for files) to enrich the data made available by that artifact.
 
type: SERVER

parameters:
 - name: PrePrompt
 type: string
 description: |
 Prompt to send with data. For example, when asking 
 a question, then providing data separately
 default: |
 You are a Cyber Incident responder and need to analyse forensic 
 collections. You have an eye for detail and like to use short precise 
 technical language. Your PRIMARY goal is to analyse the following data 
 and provide summary analysis:
 - name: Prompt
 type: string
 default: Can you list 10 Windows persistance items in bullet points?
 - name: PromptData
 type: string
 description: The data sent to Anthropic - this data is serialised and added to the prompt
 - name: Model
 type: string
 description: The model used for processing the prompt
 default: claude-3-7-sonnet-20250219
 - name: AnthropicVersion
 type: string
 description: anthropic-version header
 default: "2023-06-01"
 - name: AnthropicToken
 type: string
 description: Token for Anthropic. Leave blank here if using server metadata store.
 - name: MaxTokens
 type: int
 default: 64000

sources:
 - query: |
 LET Creds &amp;lt;= if(
 condition=AnthropicToken,
 then=AnthropicToken,
 else=server_metadata().AnthropicToken)
 LET messages = if(condition=PromptData,
 then = dict(role='user',content=PrePrompt + Prompt + ' ' + serialize(item=PromptData)) ,
 else= dict(role='user',content=PrePrompt + Prompt) )
 LET Data = if(condition=MaxTokens,
 then= dict(model=Model, messages=[messages,],max_tokens=MaxTokens),
 else= dict(model=Model, messages=[messages,]) 
 )

 SELECT
 messages.content as UserPrompt,
 parse_json(data=Content).content[0].text AS ResponseText,
 parse_json(data=Content) AS ResponseDetails
 FROM http_client(
 url='https://api.anthropic.com/v1/messages',
 headers=dict(
 `x-api-key`=Creds, 
 `Content-Type`="application/json", 
 `anthropic-version`=AnthropicVersion
 ),
 method="POST",
 data=Data )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.AI.Gemini</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/gemini/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/gemini/</guid><description>&lt;p&gt;Query Gemini AI for analysis of data.&lt;/p&gt;
&lt;p&gt;Paramaters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PrePrompt&lt;/code&gt; - Added as preprompt. Default is:
&amp;ldquo;You are a Cyber Incident Responder and need to analyze data. You have an eye
for detail and like to use short precise technical language. Analyze the
following data and provide summary analysis:&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prompt&lt;/code&gt; - Is User prompt as string: When pushing a dict object via
PromtData good practice is add some strings related to the type of data for
analysis or artifact name to provide context.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PromptData&lt;/code&gt; - add optional object to be serialized and added to the User prompt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Model&lt;/code&gt; - Model to use for your request. Default is gemini-2.0-flash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxTokens&lt;/code&gt; - Set max token size default 64000&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking
for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;e.g&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LET results = SELECT field1, field2, field3.... FROM source() WHERE ...&lt;/code&gt;&lt;br&gt;
&lt;code&gt;SELECT * FROM Artifact.Server.Enrichment.AI.Gemini(Prompt=&amp;quot;Review Autoruns data:&amp;quot;,PromptData=results)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;NOTE: there appears to be a bug in serialize() that is causing some issues in some large collections.
If you run into issues try reducing token size and filtering unnecessary data.
This is resolved in head 0.74.2 commit:99dba70 and full 1000000 tokens can be used&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.AI.Gemini
author: Matt Green - @mgreen27
description: |
 Query Gemini AI for analysis of data.
 
 Paramaters:
 
 * `PrePrompt` - Added as preprompt. Default is: 
 "You are a Cyber Incident Responder and need to analyze data. You have an eye 
 for detail and like to use short precise technical language. Analyze the 
 following data and provide summary analysis:"
 * `Prompt` - Is User prompt as string: When pushing a dict object via 
 PromtData good practice is add some strings related to the type of data for 
 analysis or artifact name to provide context.
 * `PromptData` - add optional object to be serialized and added to the User prompt.
 * `Model` - Model to use for your request. Default is gemini-2.0-flash
 * `MaxTokens` - Set max token size default 64000
 
 This artifact can be called from within another artifact (such as one looking 
 for files) to enrich the data made available by that artifact.
 
 e.g
 
 `LET results = SELECT field1, field2, field3.... FROM source() WHERE ...` 
 `SELECT * FROM Artifact.Server.Enrichment.AI.Gemini(Prompt="Review Autoruns data:",PromptData=results)`

 NOTE: there appears to be a bug in serialize() that is causing some issues in some large collections. 
 If you run into issues try reducing token size and filtering unnecessary data. 
 This is resolved in head 0.74.2 commit:99dba70 and full 1000000 tokens can be used
 
type: SERVER

parameters:
 - name: PrePrompt
 type: string
 description: |
 Prompt to send with data. For example, when asking 
 a question, then providing data separately
 default: |
 You are a Cyber Incident responder and need to analyse forensic 
 collections. You have an eye for detail and like to use short precise 
 technical language. Your PRIMARY goal is to analyse the following data 
 and provide summary analysis:
 - name: Prompt
 type: string
 default: what is prefetch?
 - name: PromptData
 type: string
 description: The data sent to Google - this data is serialised and added to the prompt
 - name: Model
 type: string
 description: The model used for processing the prompt
 default: gemini-2.0-flash
 - name: GeminiApiKey
 type: string
 description: Token for Gemini. Leave blank here if using server metadata store.
 - name: MaxTokens
 type: int
 default: 100000

sources:
 - query: |
 LET Creds &amp;lt;= if(
 condition=GeminiApiKey,
 then=GeminiApiKey,
 else=server_metadata().GeminiApiKey)
 LET parts = if(condition=PromptData,
 then= dict(text=PrePrompt + Prompt + serialize(item=PromptData)),
 else= dict(text=PrePrompt + Prompt)
 )
 LET Data = dict(contents=dict(parts=[parts,]))

 SELECT
 parts.text as UserPrompt,
 parse_json(data=Content).candidates[0].content.parts[0].text AS ResponseText,
 parse_json(data=Content) AS ResponseDetails
 FROM http_client(
 url='https://generativelanguage.googleapis.com/v1beta/models/' + Model + ':generateContent?key=' + Creds,
 headers=dict(`Content-Type`="application/json"),
 method="POST",
 data=Data
 )

column_types:
 - name: ResponseText
 type: nobreak

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.AI.Ollama</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ollama/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ollama/</guid><description>&lt;p&gt;This artifact allows enrichment using Ollama AI.&lt;/p&gt;
&lt;p&gt;Paramaters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PrePrompt&lt;/code&gt; - Is initial prompt default is: &amp;ldquo;You are a Cyber Incident
Responder and need to analyze data. You have an eye for detail and like to use
short precise technical language. Analyze the following data and provide
summary analysis:&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prompt&lt;/code&gt; - Is secondary prompt, good practice is add some strings related to
the type of data for analysis or artifact name to provide context.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PromptData&lt;/code&gt; - add object to be serialized and added to the prompt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Model&lt;/code&gt; - Model to use for your request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TargetUri&lt;/code&gt; - Ollama target URI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxPromptSize&lt;/code&gt; - If set will cut the final prompt to this size in bytes to
assist maintaining context limits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking
for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.AI.Ollama
author: Matt Green - @mgreen27
description: |
 This artifact allows enrichment using Ollama AI. 
 
 Paramaters:
 
 * `PrePrompt` - Is initial prompt default is: "You are a Cyber Incident 
 Responder and need to analyze data. You have an eye for detail and like to use 
 short precise technical language. Analyze the following data and provide 
 summary analysis:" 
 * `Prompt` - Is secondary prompt, good practice is add some strings related to 
 the type of data for analysis or artifact name to provide context.
 * `PromptData` - add object to be serialized and added to the prompt.
 * `Model` - Model to use for your request.
 * `TargetUri` - Ollama target URI
 * `MaxPromptSize` - If set will cut the final prompt to this size in bytes to 
 assist maintaining context limits
 
 This artifact can be called from within another artifact (such as one looking 
 for files) to enrich the data made available by that artifact.

type: SERVER

parameters:
 - name: PrePrompt
 type: string
 description: A prefix to be used with the prompt. For example, when asking a question, then providing data separately
 default: 'You are a Cyber Incident Responder and need to analyze data. You have an eye for detail and like to use short precise technical language. Analyze the following data and provide summary analysis: '
 - name: Prompt
 type: string
 description: A prompt - added to the middle of an AI request.
 default: "Add name of data here - e.g Windows.Forensics.Prefetch"
 - name: PromptData
 type: string
 description: The data sent to Ollama - this data is serialised and added to the prompt
 - name: Model
 type: string
 description: The model used for processing the prompt
 default: 'mistral'
 - name: TargetUri
 type: string
 description: TargetUri to send request
 default: "http://127.0.0.1:11434/api/generate"
 - name: MaxPromptSize
 type: int
 description: Will limit your prompt to this size in bytes. Helps maintain context sizes.


sources:
 - query: |
 LET FinalPrompt = if(condition= MaxPromptSize, 
 then = (PrePrompt + " " + Prompt + " " + serialize(item=PromptData))[:MaxPromptSize],
 else= PrePrompt + " " + Prompt + " " + serialize(item=PromptData) )
 
 SELECT FinalPrompt AS Prompt, 
 parse_json(data=Content).response AS ResponseText,
 parse_json(data=Content) AS ResponseDetails
 FROM http_client(
 url=TargetUri,
 headers=dict(`Content-Type`="application/json"),
 method="POST",
 data=dict(model=Model, prompt=FinalPrompt, stream=false)
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.AI.OpenAI</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.openai/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.openai/</guid><description>&lt;p&gt;Query OpenAI for analysis of data.&lt;/p&gt;
&lt;p&gt;Paramaters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PrePrompt&lt;/code&gt; - Is System prompt default is: &amp;ldquo;You are a Cyber Incident
Responder and need to analyze data. You have an eye for detail and like to use
short precise technical language. Analyze the following data and provide
summary analysis:&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prompt&lt;/code&gt; - Is User prompt as string. When pushing a dict object via PromtData
good practice is add some strings related to the type of data for analysis or
artifact name to provide context.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PromptData&lt;/code&gt; - add optional object to be serialized and added to the User prompt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Model&lt;/code&gt; - Model to use for your request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxPromptSize&lt;/code&gt; - If set will cut the final prompt to this size in bytes to
assist maintaining context limits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking
for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.AI.OpenAI
author: Matt Green - @mgreen27 refactored orginal from Wes Lambert - @therealwlambert|@weslambert@infosec.exchange
description: |
 Query OpenAI for analysis of data.
 
 Paramaters:
 
 * `PrePrompt` - Is System prompt default is: "You are a Cyber Incident 
 Responder and need to analyze data. You have an eye for detail and like to use 
 short precise technical language. Analyze the following data and provide 
 summary analysis:" 
 * `Prompt` - Is User prompt as string. When pushing a dict object via PromtData 
 good practice is add some strings related to the type of data for analysis or 
 artifact name to provide context.
 * `PromptData` - add optional object to be serialized and added to the User prompt.
 * `Model` - Model to use for your request.
 * `MaxPromptSize` - If set will cut the final prompt to this size in bytes to 
 assist maintaining context limits
 
 This artifact can be called from within another artifact (such as one looking 
 for files) to enrich the data made available by that artifact.
 
type: SERVER

parameters:
 - name: PrePrompt
 type: string
 description: |
 A prefix to be used with the prompt. For example, when asking 
 a question, then providing data separately
 default: |
 You are a Cyber Incident responder and need to analyse forensic 
 collections. You have an eye for detail and like to use short precise 
 technical language. Your PRIMARY goal is to analyse the following data 
 and provide summary analysis -
 - name: Prompt
 type: string
 description: The data sent to OpenAI
 default: "what is prefetch?"
 - name: PromptData
 type: string
 description: The data sent to OpenAI - this data is serialised and added to the prompt
 - name: Model
 type: string
 description: The model used for processing the prompt
 default: gpt-4o
 - name: TargetUrl
 description: Target Url
 default: https://api.openai.com/v1/chat/completions
 - name: OpenAIToken
 type: string
 description: Token for OpenAI. Leave blank here if using server metadata store.
 - name: MaxPromptSize
 type: int
 description: Will limit your prompt to this size in bytes. Helps maintain context sizes.

sources:
 - query: |
 LET Creds &amp;lt;= if(
 condition=OpenAIToken,
 then=OpenAIToken,
 else=server_metadata().OpenAIToken)
 
 LET UserPrompt = if(condition= MaxPromptSize, 
 then = (Prompt + " " + serialize(item=PromptData))[:MaxPromptSize],
 else = Prompt + " " + serialize(item=PromptData) )
 LET messages = (dict(role="system",content=PrePrompt), dict(role='user',content=UserPrompt))
 LET headers = dict(`Authorization`='Bearer ' + Creds, `Content-Type`="application/json")

 SELECT 
 PrePrompt as SystemPrompt,
 UserPrompt,
 parse_json(data=Content).choices[0].message.content AS ResponseText,
 parse_json(data=Content) AS ResponseDetails
 FROM http_client(
 url=TargetUrl,
 headers=headers,
 method="POST",
 data=dict(model=Model, messages=messages)
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.EchoTrail</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.echotrail/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.echotrail/</guid><description>&lt;p&gt;This is a process execution enrichment artifact that can be called from within another artifact (such as one looking at running processes) to enrich the
data made available by that artifact. We are calling the EchoTrail v2 API which is still in beta.&lt;/p&gt;
&lt;p&gt;NOTE: The EchoTrail free API is limited to 25 queries per day which is very low for most use cases. This artifact may send more than 25 queries at the API!&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.EchoTrail(lookup_image='C:\Windows\system32\svchost.exe', lookup_parent_image='C:\Windows\explorer.exe')&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Additional lookup parameters that can be passed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lookup_hostname&lt;/code&gt;: The hostname which the execution occurred on (for host-specific prevelance metrics)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lookup_image_hash&lt;/code&gt;: The SHA256 hash of the process image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lookup_parent_image_hash&lt;/code&gt;: The SHA256 hash of the process parent image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lookup_commandline&lt;/code&gt;: Command line arguments of the process&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.EchoTrail
author: Eric Capuano - @eric_capuano
description: |
 
 This is a process execution enrichment artifact that can be called from within another artifact (such as one looking at running processes) to enrich the 
 data made available by that artifact. We are calling the EchoTrail v2 API which is still in beta. 
 
 NOTE: The EchoTrail free API is limited to 25 queries per day which is very low for most use cases. This artifact may send more than 25 queries at the API!

 Ex.

 `SELECT * from Artifact.Server.Enrichment.EchoTrail(lookup_image='C:\Windows\system32\svchost.exe', lookup_parent_image='C:\Windows\explorer.exe')`

 Additional lookup parameters that can be passed:

 - `lookup_hostname`: The hostname which the execution occurred on (for host-specific prevelance metrics)
 - `lookup_image_hash`: The SHA256 hash of the process image 
 - `lookup_parent_image_hash`: The SHA256 hash of the process parent image
 - `lookup_commandline`: Command line arguments of the process

type: SERVER

parameters:
 - name: EchoTrailKey
 type: string
 description: API key for EchoTrail. Leave blank here if using server metadata store.
 default:
 - name: lookup_hostname
 type: string
 description: The hostname which the execution occurred on
 default:
 - name: lookup_image
 type: string
 description: The full path to the process image 
 default:
 - name: lookup_image_hash
 type: string
 description: The SHA256 hash of the process image 
 default:
 - name: lookup_parent_image
 type: string
 description: The full path to the process parent image
 default:
 - name: lookup_parent_image_hash
 type: string
 description: The SHA256 hash of the process parent image 
 default:
 - name: lookup_commandline
 type: string
 description: Command line arguments of the process
 default:
 - name: lookup_include_scores
 type: bool
 description: 
 default: true
 - name: lookup_include_description
 type: bool
 description: 
 default: true
 - name: lookup_include_detections
 type: bool
 description: 
 default: true
 - name: record_this_execution
 type: bool
 description: Record this as an actual execution in the EchoTrail database to contribute statistics
 default: false

sources:
 - query: |

 LET Creds = if(
 condition=EchoTrailKey,
 then=EchoTrailKey,
 else=server_metadata().EchoTrailKey)

 LET URL &amp;lt;= 'https://api.echotrail.io/v2/process_execution'

 LET Data = SELECT parse_json(data=Content) AS EchoTrailLookup
 FROM http_client(url=URL,
 headers=dict(
 `Accept`="application/json",
 `x-api-key`=Creds,
 `Content-Type`="application/json"),
 method='POST',
 data=serialize(item=dict(
 hostname=lookup_hostname,
 image=lookup_image, 
 hash=lookup_image_hash,
 parent_image=lookup_parent_image, 
 parent_hash=lookup_parent_image_hash,
 commandline=lookup_commandline, 
 include_scores=lookup_include_scores,
 include_description=lookup_include_description,
 include_detections=lookup_include_detections,
 record_execution=record_this_execution
 )
 )
 )

 SELECT
 EchoTrailLookup.description AS Description,
 EchoTrailLookup.echotrail_score AS EchoTrailScore,
 EchoTrailLookup.global.rank AS GlobalRank,
 EchoTrailLookup.global.host_prev AS HostPrevalence,
 EchoTrailLookup.global.path_score AS PathScore,
 EchoTrailLookup.global.parent_score AS ParentScore,
 EchoTrailLookup.global.overall_score AS OverallScore,
 EchoTrailLookup AS EchoTrailLookup
 FROM Data

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.IRIS.IOCLookup</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.iris.ioclookup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.iris.ioclookup/</guid><description>&lt;p&gt;Query an IRIS instance for an indicator.&lt;/p&gt;
&lt;p&gt;To learn more about IRIS, see: &lt;a href="https://dfir-iris.org/" target="_blank" &gt;https://dfir-iris.org/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;NOTE: This artifact queries for all IOCs, and does not associate IOCs to first-order cases. This will be improved in the future.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.IRIS.IOCLookup(IOC=$YOURIOC)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.IRIS.IOCLookup
description: |
 Query an IRIS instance for an indicator.

 To learn more about IRIS, see: https://dfir-iris.org/

 This artifact can be called from within another artifact to enrich the data made available by that artifact.
 
 NOTE: This artifact queries for all IOCs, and does not associate IOCs to first-order cases. This will be improved in the future.

 Ex.

 `SELECT * from Artifact.Server.IRIS.IOCLookup(IOC=$YOURIOC)`

type: SERVER

parameters:
 - name: IOC
 default:
 - name: IrisURL
 default: https://myiris
 - name: IrisKey
 type: string
 description: API key for DFIR-IRIS. Leave blank here if using server metadata store.
 default:
sources:
 - query: |
 LET URL = if(
 condition=IrisURL,
 then=IrisURL,
 else=server_metadata().IrisURL)
 
 LET Creds = if(
 condition=IrisKey,
 then=IrisKey,
 else=server_metadata().IrisKey)
 
 LET Data = SELECT parse_json(data=Content).data.ioc AS IOCs FROM http_client(
 method="GET", 
 url=URL + '''/case/ioc/list''',
 headers=dict(`Content-Type`="application/json", `Authorization`='''Bearer ''' + Creds),
 disable_ssl_security=true
 )
 
 LET EachIOC = SELECT * from foreach(
 row=Data,
 query={
 SELECT _value.ioc_value AS IOCValue,
 _value.ioc_description AS Description,
 _value.tlp_name AS TLP,
 _value.link AS `Linked Cases`,
 _value AS _Content
 FROM items(item=IOCs)
 })
 
 SELECT * FROM EachIOC WHERE IOCValue =~ IOC


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.MalwareBazaar</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.malwarebazaar/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.malwarebazaar/</guid><description>&lt;p&gt;Query MalwareBazaar for a hash.&lt;/p&gt;
&lt;p&gt;To learn more about MalwareBazaar, see: &lt;a href="https://bazaar.abuse.ch/" target="_blank" &gt;https://bazaar.abuse.ch/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`SELECT * from Artifact.Server.Enrichment.MalwareBazaar(Hash=$YourMD5OrSHA1OrSHA256)`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If querying for an alternate hash, specify the hash type, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`SELECT * from Artifact.Server.Enrichment.MalwareBazaar(Hash=$YOURHASH, HashType=$YourGimphashOrImphash)`
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.MalwareBazaar
description: |
 Query MalwareBazaar for a hash.
 
 To learn more about MalwareBazaar, see: https://bazaar.abuse.ch/
 
 This artifact can be called from within another artifact to enrich the data made available by that artifact.

 Ex.

 `SELECT * from Artifact.Server.Enrichment.MalwareBazaar(Hash=$YourMD5OrSHA1OrSHA256)`

 If querying for an alternate hash, specify the hash type, like so:
 
 `SELECT * from Artifact.Server.Enrichment.MalwareBazaar(Hash=$YOURHASH, HashType=$YourGimphashOrImphash)`

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: SERVER

parameters:
 - name: Hash
 default:
 - name: HashType
 default:
 type: choices
 choices:
 - 
 - MD5
 - SHA1
 - SHA256
 - Gimphash
 - Imphash

sources:
 - query: |
 LET QueryTable &amp;lt;= SELECT * FROM parse_csv(accessor="data", filename='''
 Type,Query,SearchValue
 Gimphash,get_gimphash,gimphash
 Imphash,get_imphash,imphash
 MD5,get_info,hash
 SHA1,get_info,hash
 SHA256,get_info,hash
 Telfhash,get_telfhash,telfhash
 TLSH,get_tlsh,tlsh
 '''
 )
 
 LET MBURL &amp;lt;= "https://mb-api.abuse.ch/api/v1/"
 LET QueryName = SELECT Query FROM QueryTable WHERE HashType=Type
 LET SearchName = SELECT SearchValue FROM QueryTable WHERE HashType=Type
 LET Boundary &amp;lt;= "-----------------------------9051914041544843365972754266"
 LET Data(Name, Value) = format(
 format='--%s\nContent-Disposition: form-data; name="%v"\n\n%s\n',
 args=[Boundary, Name, Value])
 LET END = format(format="--%s--\n", args=Boundary)
 
 LET MBSubmission = SELECT 
 parse_json(data=Content).data.file_name[0] as `Filename`,
 parse_json(data=Content).data.first_seen[0] as `First Seen`,
 parse_json(data=Content).data.last_seen[0] as `Last Seen`,
 parse_json(data=Content).data.reporter[0] as Reporter,
 parse_json(data=Content).data.tags[0] as Tags,
 parse_json(data=Content).data.intelligence[0] as Intelligence,
 parse_json(data=Content) AS _Content
 FROM http_client(
 method="POST",
 url=MBURL,
 headers=dict(`Content-Type`="multipart/form-data; boundary=" + Boundary),
 data=Data(Name="query", Value=if(condition=QueryName.Query[0], then=QueryName.Query[0], else="get_info")) + Data(Name=if(condition=SearchName.SearchValue[0], then=SearchName.SearchValue[0], else="hash"), Value=Hash) + END)
 SELECT * FROM MBSubmission

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.SecureAnnex</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.secureannex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.secureannex/</guid><description>&lt;p&gt;Submit an extension to the Secure Annex API.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://app.secureannex.com/settings/api" target="_blank" &gt;https://app.secureannex.com/settings/api&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact, like one looking for installed Chrome extensions, to enrich the data coming back with vulnerability information from Secure Annex.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.SecureAnnex(ExtensionId=$EXTENSION_ID,ExtensionVersion=$EXTENSION_VERSION,ApiKey=$API_KEY)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.SecureAnnex
author: Whitney Champion -- bsky.app/profile/whit.zip
description: |
 Submit an extension to the Secure Annex API.

 https://app.secureannex.com/settings/api

 This artifact can be called from within another artifact, like one looking for installed Chrome extensions, to enrich the data coming back with vulnerability information from Secure Annex.
 
 Ex.

 `SELECT * from Artifact.Server.Enrichment.SecureAnnex(ExtensionId=$EXTENSION_ID,ExtensionVersion=$EXTENSION_VERSION,ApiKey=$API_KEY)`


type: SERVER

parameters:
 - name: ExtensionId
 type: string
 description: The extension ID to submit to SecureAnnex
 - name: ExtensionVersion
 type: string
 description: The extension version to submit to SecureAnnex
 - name: ApiKey
 type: string
 description: The API key to submit to SecureAnnex
 default: 
 - name: ApiURL
 type: string
 description: The SecureAnnex API URL
 default: https://api.secureannex.com/api/v0/vulnerabilities

sources:
 - query: |
 // Get the JSON response from the API call
 LET Response = SELECT parse_json(data=Content).result AS Vulnerabilities
 FROM http_client(url=ApiURL, 
 headers=dict(`x-api-key`=ApiKey), 
 params=dict(`extension_id`=ExtensionId,`version`=ExtensionVersion,`page`=1,`page_size`=100),
 method='GET')

 SELECT * FROM foreach(
 row=Response,
 query={
 SELECT
 name as Name,
 version as Version,
 vulnerability.severity AS VulnerabilitySeverity,
 component AS Component,
 detection AS Detection,
 extension_id AS ExtensionID,
 file_path AS FilePath,
 npmname AS NPMName,
 vuln_version AS VulnVersion,
 vulnerability.atOrAbove AS VulnerabilityAtOrAbove,
 vulnerability.below AS VulnerabilityBelow,
 vulnerability.identifiers AS VulnerabilityIdentifiers,
 vulnerability.info AS VulnerabilityInfo
 FROM foreach(row=Vulnerabilities)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.Strelka.FileScan</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.strelka.filescan/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.strelka.filescan/</guid><description>&lt;p&gt;Submit a file to Strelka for analysis using &lt;code&gt;strelka-oneshot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For more information about Strelka and &lt;code&gt;strelka-oneshot&lt;/code&gt;, see:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://target.github.io/strelka/#/?id=strelka-oneshot" target="_blank" &gt;https://target.github.io/strelka/#/?id=strelka-oneshot&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.Strelka.FileScan(FileToScan=$YOURFILE)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;NOTE: The default time to wait for scan results is set to 60 seconds. This timeout can be changed by altering the value for the &lt;code&gt;StrelkaTimeout&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.Strelka.FileScan
author: Wes Lambert -- @therealwlambert, @weslambert@infosec.exchange
description: | 
 Submit a file to Strelka for analysis using `strelka-oneshot`.
 
 For more information about Strelka and `strelka-oneshot`, see:
 
 https://target.github.io/strelka/#/?id=strelka-oneshot
 
 This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.
 
 Ex.
 
 `SELECT * from Artifact.Server.Enrichment.Strelka.FileScan(FileToScan=$YOURFILE)`
 
 NOTE: The default time to wait for scan results is set to 60 seconds. This timeout can be changed by altering the value for the `StrelkaTimeout` variable.
 
type: SERVER

tools:
 - name: StrelkaOneshot
 url: https://github.com/target/strelka/releases/download/0.21.5.17/strelka-oneshot-linux

parameters:
 - name: FileToScan
 type: string
 description: The file to submit to Strelka
 default: 
 - name: StrelkaURL
 type: string
 description: String comprised of `host + ':' + port` of Strelka frontend
 default: StrelkaFrontend:57314
 - name: StrelkaCerticatePath
 description: Path of certificate to use for authentication
 default:
 - name: StrelkaTimeout
 description: Timeout for file scanning
 type: int 
 default: 60

sources:
 - query:
 LET StrelkaFrontend = if(
 condition=StrelkaURL,
 then=StrelkaURL,
 else=server_metadata().StrelkaURL)
 
 LET CertPath = if(
 condition=StrelkaCerticatePath, 
 then=StrelkaCerticatePath, 
 else=if(condition=server_metadata().StrelkaCertificatePath, then=server_metadata().StrelkaCertificatePath, else=""))
 
 LET StrelkaOneshot &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="StrelkaOneshot", IsExecutable=TRUE)
 
 LET ScanResults = SELECT *, parse_json(data=Stdout) AS Content 
 FROM execve(argv=[ 
 StrelkaOneshot.FullPath[0], 
 "-f", FileToScan, 
 "-s", StrelkaFrontend,
 "-c", CertPath,
 "-l", "-",
 "-t", StrelkaTimeout])
 
 SELECT 
 { SELECT Mtime FROM stat(filename=FileToScan)} AS Mtime,
 FileToScan AS File,
 Content.file as FileDetails, 
 Content.request as RequestDetails, 
 Content.scan as ScanResults 
 FROM ScanResults

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.Sublime.EmailAnalysis</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.sublime.emailanalysis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.sublime.emailanalysis/</guid><description>&lt;p&gt;Submit an email to Sublime for analysis.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://sublime.security/" target="_blank" &gt;https://sublime.security/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;By default, this artifact returns matches for active detection rules.&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.Sublime(Message=$YourBase64EncodedMessage)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.Sublime.EmailAnalysis
author: Wes Lambert -- @therealwlambert, @weslambert@infosec.exchange
description: |
 Submit an email to Sublime for analysis.
 
 https://sublime.security/
 
 By default, this artifact returns matches for active detection rules.

 This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.

 Ex.

 `SELECT * from Artifact.Server.Enrichment.Sublime(Message=$YourBase64EncodedMessage)`

type: SERVER

parameters:
 - name: Message
 type: string
 description: The message to submit to Sublime.
 default:

 - name: SublimeKey
 type: string
 description: API key for Sublime. Leave blank here if using server metadata store.
 default:
 
sources:
 - query: |
 LET Creds = if(
 condition=SublimeKey,
 then=SublimeKey,
 else=server_metadata().SublimeKey)

 LET URL &amp;lt;= 'https://api.platform.sublimesecurity.com/v0/messages/analyze'
 
 LET Response = SELECT parse_json(data=Content) AS Content
 FROM http_client(
 url=URL,
 headers=dict(`Authorization`=format(format="Bearer %v", args=[Creds]), `Content-Type`="application/json"),
 data=serialize(item=dict(`raw_message`=Message, `run_active_detection_rules`=true)),
 method='POST')

 LET ResultsQuery = SELECT * FROM foreach(
 row=Response, 
 query={
 SELECT 
 rule.name AS Name, 
 rule.source AS Source, 
 rule.id AS ID, success AS Success, 
 error AS Error, 
 execution_time AS ExecutionTime
 FROM Content.rule_results WHERE matched = true
 }
 )
 
 SELECT * FROM foreach(
 row=if(condition=Response.Content.rule_results, 
 then=ResultsQuery, 
 else=Response.Content))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.ThreatFox</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.threatfox/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.threatfox/</guid><description>&lt;p&gt;Query ThreatFox for an indicator.&lt;/p&gt;
&lt;p&gt;To learn more about ThreatFox, see: &lt;a href="https://threatfox.abuse.ch" target="_blank" &gt;https://threatfox.abuse.ch&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.ThreatFox(AuthKey=$YOURKEY,IOC=$YOURIOC)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If querying for an MD5 or SHA256 hash, specify the IOC type, like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.ThreatFox(AuthKey=$YOURKEY,IOCType=Hash)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.ThreatFox
description: |
 Query ThreatFox for an indicator.

 To learn more about ThreatFox, see: https://threatfox.abuse.ch

 This artifact can be called from within another artifact to enrich the data made available by that artifact.

 Ex.

 `SELECT * from Artifact.Server.Enrichment.ThreatFox(AuthKey=$YOURKEY,IOC=$YOURIOC)`

 If querying for an MD5 or SHA256 hash, specify the IOC type, like so:
 
 `SELECT * from Artifact.Server.Enrichment.ThreatFox(AuthKey=$YOURKEY,IOCType=Hash)`

type: SERVER

parameters:
 - name: AuthKey
 default:
 - name: IOC
 default:
 - name: IOCType
 default:
 type: choices
 choices:
 - 
 - IOC
 - Hash

sources:
 - query: |
 LET TFURL &amp;lt;= "https://threatfox-api.abuse.ch/api/v1/"
 LET TFIOC = 
 SELECT *
 FROM http_client(
 method="POST",
 url=TFURL,
 headers=dict(`Auth-Key`=AuthKey),
 data=serialize(item=dict(`query`="search_ioc",`search_term`=IOC))
 )
 
 LET TFHash = 
 SELECT *
 FROM http_client(
 method="POST",
 url=TFURL,
 headers=dict(`Auth-Key`=AuthKey),
 data=serialize(item=dict(`query`="search_hash", `hash`=IOC))
 )
 
 SELECT 
 parse_json(data=Content).data[0].ioc AS `IOC`,
 parse_json(data=Content).data[0].malware AS `Malware`,
 parse_json(data=Content).data[0].confidence_level AS `Confidence Level`,
 parse_json(data=Content).data[0].threat_type AS `Threat Type`,
 parse_json(data=Content).data[0].first_seen AS `First Seen`,
 parse_json(data=Content).data[0].last_seen AS `Last Seen`,
 parse_json(data=Content).data[0].reporter AS `Reporter`,
 parse_json(data=Content).data[0].tags AS `Tags`,
 parse_json(data=Content).data[0] As _Content 
 FROM if(condition= IOCType=~"Hash",then=TFHash,else=TFIOC)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Enrichment.Virustotal.FileScan</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.virustotal.filescan/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.enrichment.virustotal.filescan/</guid><description>&lt;p&gt;Submit a file to Virustotal for analysis.&lt;/p&gt;
&lt;p&gt;This artifact is based on the multipart/form-data example here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.velociraptor.app/knowledge_base/tips/multiparts_uploads/" target="_blank" &gt;https://docs.velociraptor.app/knowledge_base/tips/multiparts_uploads/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Enrichment.Virustotal.FileScan(FileToScan=$YOURFILE)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;NOTE: The default time to wait for scan results is set to 60 seconds. In the future, this artifact will be optimized to poll for result status instead of using a static wait interval.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Enrichment.Virustotal.FileScan
author: Wes Lambert -- @therealwlambert
description: | 
 Submit a file to Virustotal for analysis. 
 
 This artifact is based on the multipart/form-data example here:
 
 https://docs.velociraptor.app/knowledge_base/tips/multiparts_uploads/
 
 This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.
 
 Ex.
 
 `SELECT * from Artifact.Server.Enrichment.Virustotal.FileScan(FileToScan=$YOURFILE)`
 
 NOTE: The default time to wait for scan results is set to 60 seconds. In the future, this artifact will be optimized to poll for result status instead of using a static wait interval.
 
type: SERVER

parameters:
 - name: FileToScan
 type: string
 description: The file to submit to Virustotal (this refers to the file's actual path on disk).
 default: 
 - name: TimeToWait
 type: int
 description: Time to wait before attempting to pull results for the file submission.
 default: 60
 - name: VirustotalKey
 type: string
 description: API key for Virustotal. Leave blank here if using server metadata store.
 default:

sources:
 - queries:
 - |
 LET Creds = if(
 condition=VirustotalKey,
 then=VirustotalKey,
 else=server_metadata().VirustotalKey)
 - |
 LET Url &amp;lt;= 'https://www.virustotal.com/api/v3/'
 
 - |
 LET Boundary &amp;lt;= "-----------------------------9051914041544843365972754266"
 
 - | 
 LET File(Filename, ParameterName, Data) = format(
 format='--%s\nContent-Disposition: form-data; name="%s"; filename="%v"\nContent-Type: text/plain\n\n%s\n',
 args=[Boundary, ParameterName, Filename, Data])

 - |
 LET END = format(format="--%s--\n", args=Boundary)

 - | 
 LET Submission = SELECT * FROM chain(
 a={SELECT parse_json(data=Content).data.id AS SubmissionId FROM http_client(
 method="POST",
 url=Url + 'files',
 headers=dict(`x-apikey`=Creds, `Content-Type`="multipart/form-data; boundary=" + Boundary),
 data=File(Filename=path_split(path=FileToScan)[1], ParameterName="file", Data=read_file(filename=FileToScan)) + END)},
 b={SELECT sleep(time=TimeToWait) FROM scope()}
 )

 - | 
 LET Analysis = SELECT parse_json(data=Content) AS Content FROM http_client(
 method="GET",
 url=Url + 'analyses/' + Submission.SubmissionId[0],
 headers=dict(`x-apikey`=Creds))

 - |
 SELECT path_split(path=FileToScan)[1] AS Filename, 
 Content.data.attributes.stats AS Stats, 
 Content.data.attributes.results AS Results, 
 Content.meta.file_info AS _FileInfo, 
 Content AS _Data 
 FROM Analysis

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Findflows</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/findflows/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/findflows/</guid><description>&lt;p&gt;This artifact enables searching over client flow results with regex
and returns a link to the Flow for followup.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Findflows
author: Matt Green - @mgreen27
description: |
 This artifact enables searching over client flow results with regex
 and returns a link to the Flow for followup.

type: SERVER
parameters:
 - name: ClientData
 description: Glob for client data - may need to modify for non default installation
 default: /opt/velociraptor/clients/**
 - name: DateAfter
 type: timestamp
 description: "search for flow data after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: DateBefore
 type: timestamp
 description: "search for flow data before this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: Workers
 type: int
 default: 100
 description: Number of concurrent workers
 - name: SearchRegex
 type: regex
 description: Second option Yara choice is a Velociraptor shorthand Yara rule
 default:
 - name: FindKeywordTemplate
 type: hidden
 default: |
 rule findregex {
 strings:
 $regex = /(REPLACEME)/i

 condition:
 $regex
 }

sources:
 - query: |
 -- create regex yara for search performance
 LET FinderYara = regex_replace(source=FindKeywordTemplate,re='REPLACEME',replace=SearchRegex)

 -- time testing
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))


 -- first find all matching glob
 LET files &amp;lt;= SELECT FinderYara,FullPath, Name, Size, Mtime, Atime, Ctime, Btime
 FROM glob(globs=ClientData,nosymlink='True')
 WHERE FullPath =~ '/F\\.[^\\./]+\\.json$'
 AND NOT IsDir AND NOT IsLink
 AND
 ( time_test(stamp=Mtime)
 OR time_test(stamp=Atime)
 OR time_test(stamp=Ctime) )


 -- scan files
 LET hits &amp;lt;= SELECT * FROM foreach(row=files,
 query={
 SELECT
 FileName as FullPath,
 File.Size AS Size,Mtime,
 str(str=String.Data) AS HitContext
 FROM yara(rules=FinderYara,files=FullPath)
 LIMIT 1
 },workers=Workers)


 -- find configuration information
 LET find_hostname(ClientId) = SELECT os_info.hostname as Hostname FROM clients() WHERE client_id = ClientId
 

 -- enrich results
 LET flows = SELECT *,
 { SELECT HitContext FROM hits WHERE FullPath = FullPath GROUP BY lowcase(string=HitContext) } as HitContext, Mtime, FullPath,
 parse_string_with_regex(string=FullPath,regex='clients/(?P&amp;lt;ClientId&amp;gt;C\\.[^/]+)/artifacts').ClientId as ClientId,
 parse_string_with_regex(string=FullPath,regex='/(?P&amp;lt;FlowId&amp;gt;F\\.[^\\.]+)\\.json$').FlowId as FlowId
 FROM hits
 WHERE ClientId AND FlowId
 GROUP BY FullPath


 -- output rows
 SELECT
 find_hostname(ClientId=ClientId)[0].Hostname as Hostname,
 HitContext,
 Mtime as FlowModTime,
 '#/collected/' + ClientId + '/' + FlowId + '/notebook' as FlowNotebook,
 ClientId,FlowId
 FROM flows


column_types:
 - name: FlowModTime
 type: timestamp
 - name: FlowNotebook
 type: url

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Hunt.Comparison</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.hunt.comparison/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.hunt.comparison/</guid><description>&lt;p&gt;This artifact is used to compare other artifacts from two different hunts. The basic idea is that a baseline (Hunt 1) is created from selected artifacts before an attack. A second hunt (Hunt 2) can then be carried out after the attack using the same artifacts. Now, using this script, artifacts from both hunts can be compared. This allows legitimate activities to be filtered out and makes it easier to identify malicious activities in Hunt2.&lt;/p&gt;
&lt;p&gt;Furthermore, when comparing artifacts, it is necessary to select columns (here the identifying_column) that should be used for the comparison in both artifacts, since a comparison of complete data sets leads to errors. Because many artifacts contain timestamps that update. The use of values such as hashes therefore makes sense.&lt;/p&gt;
&lt;p&gt;For example, the following artifacts and their identifying columns can be used to compare to a baseline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows.System.Pslist - Hash&lt;/li&gt;
&lt;li&gt;Windows.Forensics.Prefetch - Hash&lt;/li&gt;
&lt;li&gt;Windows.Sysinternals.Autoruns - SHA-256&lt;/li&gt;
&lt;li&gt;Windows.Sys.AllUsers - Name&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Hunt.Comparison
author: Denis Kiffer

description: |
 This artifact is used to compare other artifacts from two different hunts. The basic idea is that a baseline (Hunt 1) is created from selected artifacts before an attack. A second hunt (Hunt 2) can then be carried out after the attack using the same artifacts. Now, using this script, artifacts from both hunts can be compared. This allows legitimate activities to be filtered out and makes it easier to identify malicious activities in Hunt2.
 
 Furthermore, when comparing artifacts, it is necessary to select columns (here the identifying_column) that should be used for the comparison in both artifacts, since a comparison of complete data sets leads to errors. Because many artifacts contain timestamps that update. The use of values such as hashes therefore makes sense.
 
 For example, the following artifacts and their identifying columns can be used to compare to a baseline:
 
 - Windows.System.Pslist - Hash
 - Windows.Forensics.Prefetch - Hash
 - Windows.Sysinternals.Autoruns - SHA-256
 - Windows.Sys.AllUsers - Name
 
reference:
 - https://www.sans.org/white-papers/37192/

type: SERVER

parameters:
 - name: Baseline_Hunt_1_id
 description: id of the hunt that was executed before an attack
 - name: Hunt_2_id
 description: id of hunt that was executed during or after an attack and is supposed to be compared to the Baseline_Hunt_1
 - name: Artifact_name
 description: This is the artefact that should be compared and which was executed in the Baseline_Hunt_1 and Hunt_2
 - name: Identifying_column
 description: column of the selected artefact that should be compared

sources:
 - query: |
 --Select baseline hunt
 Let Baseline = SELECT *,"Baseline" AS Sourcehunt FROM hunt_results(
 artifact=Artifact_name,
 hunt_id=Baseline_Hunt_1_id) 

 --Select second hunt to compare 
 Let Hunt2 = SELECT *, "Hunt2" AS Sourcehunt FROM hunt_results(
 artifact=Artifact_name,
 hunt_id=Hunt_2_id)

 --Get List of systems to compare to each other 
 Let Systems = SELECT Fqdn FROM Baseline GROUP BY Fqdn

 --Fuse both hunts 
 Let Hunts_fused = SELECT * FROM chain(
 a={SELECT * FROM Hunt2},
 b={SELECT * FROM Baseline},async=TRUE)

 --Loop through each system and count how many appearances of the value from the selected identifying_column there are 
 Let CountallRows = SELECT * FROM foreach(
 row=Systems.Fqdn,
 query={SELECT *, count() AS TotalCount FROM Hunts_fused WHERE Fqdn=_value GROUP BY get(member=Identifying_column)})

 --Show all lines where the value in the identifying_column only appears once
 SELECT * FROM CountallRows WHERE TotalCount=1

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Import.DetectRaptor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/detectraptor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/detectraptor/</guid><description>&lt;p&gt;DetectRaptor is a collection of publicly availible Velociraptor detection content.
Most content is managed by a series of csv files and artifacts are automatically updated.&lt;/p&gt;
&lt;p&gt;This artifact will import the latest DetectRaptor bundle into the current server.&lt;/p&gt;
&lt;p&gt;A SHA1 of the imported DetectRaptor collection is stored in server metadata
for versioning.&lt;br&gt;
A SHA1 of each artifact is generated on import to enable versioning confirmation.&lt;/p&gt;
&lt;p&gt;Last updated: 2026-01-23.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Import.DetectRaptor
author: Matt Green - @mgreen27
description: |
 DetectRaptor is a collection of publicly availible Velociraptor detection content. 
 Most content is managed by a series of csv files and artifacts are automatically updated.
 
 This artifact will import the latest DetectRaptor bundle into the current server.
 
 A SHA1 of the imported DetectRaptor collection is stored in server metadata 
 for versioning. 
 A SHA1 of each artifact is generated on import to enable versioning confirmation.
 
 Last updated: 2026-01-23.

reference:
 - https://github.com/mgreen27/DetectRaptor
 - https://github.com/svch0stz/velociraptor-detections
 - https://github.com/SigmaHQ/sigma

type: SERVER

required_permissions:
- SERVER_ADMIN

parameters:
 - name: ReleaseURL
 default: https://api.github.com/repos/mgreen27/DetectRaptor/releases
 - name: Tag
 default: DetectRaptor
 description: Prefix to append to all imported artifacts.
 - name: UpdateAnyway
 type: bool
 description: Import all artifacts even if previous version matches

sources:
 - query: |
 -- first check for version timestamp and find zip url
 LET content &amp;lt;= SELECT parse_json_array(data=Content)[0].assets[0] as Content 
 FROM http_client(url=ReleaseURL, headers=dict(`User-Agent`="Velociraptor - DetectRaptor"))
 LET check_version = SELECT Content.browser_download_url as TargetUrl,
 Content.updated_at as ZipTimestamp,
 if(condition= server_metadata().DetectRaptor,
 then= parse_json(data=server_metadata().DetectRaptor).Timestamp
 ) as InstalledTimestamp
 FROM content
 WHERE UpdateAnyway 
 OR NOT server_metadata().DetectRaptor
 OR NOT InstalledTimestamp 
 OR InstalledTimestamp &amp;lt; ZipTimestamp
 
 -- get content return a row if new content or UpdateAnyway
 LET get_content = SELECT ZipPath,ZipTimestamp,ZipSHA1
 FROM foreach(row= check_version,
 query={ 
 SELECT Content as ZipPath, 
 ZipTimestamp,
 hash(path=Content,hashselect='SHA1').SHA1 as ZipSHA1 ,
 if(condition= server_metadata().DetectRaptor,
 then= parse_json(data=server_metadata().DetectRaptor).SHA1
 ) as InstalledZipSHA1
 FROM http_client(remove_last=TRUE, 
 tempfile_extension=".zip", url=TargetUrl,
 headers=dict(`User-Agent`="Velociraptor - DetectRaptor"))
 WHERE NOT if(condition= UpdateAnyway,
 then= False,
 else= ZipSHA1 = InstalledZipSHA1 )
 })
 
 -- extract and set artifacts
 LET set_artifacts &amp;lt;= SELECT 
 artifact_set(tags=Tag, definition=Definition) AS Definition,
 SHA1,
 ZipTimestamp,ZipSHA1
 FROM foreach(row=get_content, 
 query={
 SELECT read_file(accessor="zip", filename=OSPath) AS Definition,
 hash(path=OSPath,accessor='zip',hashselect='SHA1').SHA1 as SHA1,
 ZipTimestamp,ZipSHA1
 FROM glob(
 globs='/**/*.yaml',
 root=pathspec(
 DelegateAccessor="auto",
 DelegatePath=ZipPath),
 accessor="zip")
 })
 
 -- Add new sha1 if set_artifacts
 LET add_new_metadata &amp;lt;= SELECT ZipSHA1,ZipTimestamp,
 server_set_metadata(
 metadata=dict(DetectRaptor=dict(
 Timestamp=ZipTimestamp,
 SHA1=ZipSHA1 ))) as SetMeta
 FROM set_artifacts
 WHERE log(level='INFO',
 message='DetectRaptor Server MetaData added: Timestamp=%v,SHA1=%v',
 args=[ZipTimestamp,ZipSHA1] )
 GROUP BY ZipSHA1

 SELECT Definition.name AS Name,
 Definition.description AS Description,
 Definition.author AS Author,
 SHA1
 FROM set_artifacts

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Import.WatchLocalDirectory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.import.watchlocaldirectory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.import.watchlocaldirectory/</guid><description>&lt;p&gt;This is an artifact that will monitor a local path for collections,
which it will then ingest.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Import.WatchLocalDirectory
description: |
 This is an artifact that will monitor a local path for collections, 
 which it will then ingest. 

type: SERVER_EVENT

parameters:
 - name: WatchDir
 default: "/tmp/watch/*.zip"

sources:
 - query: |
 SELECT * FROM foreach(
 row={
 SELECT * FROM diff(
 query={
 SELECT OSPath FROM glob(globs=WatchDir)
 }, period=3, key="OSPath"
 )
 WHERE Diff =~ "added"
 }, query={
 SELECT *, import_collection(filename=OSPath), OSPath 
 FROM scope()
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Import.WatchS3Directory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.import.watchs3directory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.import.watchs3directory/</guid><description>&lt;p&gt;This is an artifact that will monitor an S3 path for collections,
which it will then ingest.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Import.WatchS3Directory
description: |
 This is an artifact that will monitor an S3 path for collections, 
 which it will then ingest. 

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: SERVER_EVENT

parameters:
 - name: WatchDir
 default: "/velociraptor/*.zip"

 - name: Endpoint
 default: 'http://127.0.0.1:9000/'
 
 - name: Key
 default: 'admin'
 
 - name: Secret
 default: 'password'
 
 - name: Region
 default: 'us-east-1'

sources:
 - query: |
 LET S3_CREDENTIALS &amp;lt;= dict(
 endpoint=Endpoint, 
 credentials_key=Key, 
 credentials_secret=Secret,
 region=Region,
 no_verify_cert=1)
 SELECT * FROM foreach(
 row={
 SELECT * FROM diff(
 query={
 SELECT OSPath FROM glob(globs=WatchDir, accessor="s3")
 }, period=3, key="OSPath"
 )
 WHERE Diff =~ "added"
 }, query={
 SELECT *, import_collection(
 filename=OSPath,
 accessor="s3"
 ), OSPath 
 FROM scope()
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Monitor.Autolabeling.Clients</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.monitor.autolabeling.clients/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.monitor.autolabeling.clients/</guid><description>&lt;p&gt;This server side event monitoring artifact watches for new client enrollments and automatically labels them according to their domain roles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standalone &amp;amp; Member Workstations will get the label &lt;code&gt;Workstation&lt;/code&gt; assigned.&lt;/li&gt;
&lt;li&gt;Standalone &amp;amp; Member Servers will get the label &lt;code&gt;Server&lt;/code&gt; assigned.&lt;/li&gt;
&lt;li&gt;Primary &amp;amp; Backup Domain Controller will get the label &lt;code&gt;Domain Controller&lt;/code&gt; assigned.&lt;/li&gt;
&lt;li&gt;Linux Systems will get the label &lt;code&gt;Linux&lt;/code&gt; assigned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Relabeling of all clients even after they were enrolled can be achieved by starting a hunt for &lt;code&gt;Generic.Client.Info&lt;/code&gt;. The labels are either Set or Cleared so it is fine to re-apply the label many times. See &lt;a href="https://docs.velociraptor.app/knowledge_base/tips/automating_labels/" target="_blank" &gt;https://docs.velociraptor.app/knowledge_base/tips/automating_labels/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Monitor.Autolabeling.Clients
author: Stephan Mikiss @StephMikiss
description: |
 This server side event monitoring artifact watches for new client enrollments and automatically labels them according to their domain roles.
 
 * Standalone &amp;amp; Member Workstations will get the label `Workstation` assigned.
 * Standalone &amp;amp; Member Servers will get the label `Server` assigned.
 * Primary &amp;amp; Backup Domain Controller will get the label `Domain Controller` assigned.
 * Linux Systems will get the label `Linux` assigned.
 
 Relabeling of all clients even after they were enrolled can be achieved by starting a hunt for `Generic.Client.Info`. The labels are either Set or Cleared so it is fine to re-apply the label many times. See https://docs.velociraptor.app/knowledge_base/tips/automating_labels/
 
type: SERVER_EVENT
sources:
- query: |
 
 LET interrogations = SELECT *
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ "Generic.Client.Info/WindowsInfo|Generic.Client.Info/BasicInformation"
 
 LET matches = SELECT * FROM switch(
 z={SELECT *,label(client_id=ClientId, labels="Linux", op="set") FROM source(
 artifact="Generic.Client.Info/BasicInformation") WHERE OS =~ "linux"},
 a={SELECT *,label(client_id=ClientId, labels="Workstation", op="set") FROM source(
 artifact="Generic.Client.Info/WindowsInfo") WHERE `Computer Info`.DomainRole =~"Workstation"},
 b={SELECT *,label(client_id=ClientId, labels="Server", op="set") FROM source(
 artifact="Generic.Client.Info/WindowsInfo") WHERE `Computer Info`.DomainRole =~"Server"},
 c={SELECT *,label(client_id=ClientId, labels="Domain Controller", op="set") FROM source(
 artifact="Generic.Client.Info/WindowsInfo") WHERE `Computer Info`.DomainRole =~"Domain Controller"}
 )
 
 SELECT * FROM foreach(row=interrogations, query=matches)
 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Notification.Mastodon</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.notification.mastodon/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.notification.mastodon/</guid><description>&lt;p&gt;Create a post on a Mastodon server. This could be used for automated alerting purposes, sharing IOCs, etc.&lt;/p&gt;
&lt;p&gt;This artifact can be called from within another artifact to include data from the artifact results in the message/status.&lt;/p&gt;
&lt;p&gt;This could also be turned into a server event artifact to send a notification or post to Mastodon when a particular event occurs.&lt;/p&gt;
&lt;p&gt;Ex.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT * from Artifact.Server.Notification.Mastodon(Status=YourMessage/Status)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Notification.Mastodon
author: Wes Lambert -- @therealwlambert
description: |
 Create a post on a Mastodon server. This could be used for automated alerting purposes, sharing IOCs, etc.

 This artifact can be called from within another artifact to include data from the artifact results in the message/status.
 
 This could also be turned into a server event artifact to send a notification or post to Mastodon when a particular event occurs.

 Ex.

 `SELECT * from Artifact.Server.Notification.Mastodon(Status=YourMessage/Status)`

type: SERVER

parameters:
 - name: Status
 type: string
 description: The message/status to be posted to Mastodon.
 default:
 
 - name: MastodonServer
 type: string
 description: Mastodon server. Leave blank here if using server metadata store.
 default:

 - name: MastodonToken
 type: string
 description: Token for Mastodon. Leave blank here if using server metadata store.
 default:

sources:
 - query: |
 LET Creds &amp;lt;= if(
 condition=MastodonToken,
 then=MastodonToken,
 else=server_metadata().MastodonToken)
 
 LET Server &amp;lt;= if(
 condition=MastodonServer,
 then=MastodonServer,
 else=server_metadata().MastodonServer)

 SELECT * FROM http_client(
 url='https://'+ Server +'/api/v1/statuses',
 headers=dict(`Authorization`='Bearer ' + Creds, `Content-Type`="application/json"),
 method="POST",
 data=dict(`status`=Status)
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Notification.Mattermost</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.notification.mattermost/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.notification.mattermost/</guid><description>&lt;p&gt;Send notification via Mattermost webhook as described in &lt;a href="https://developers.mattermost.com/integrate/webhooks/incoming/" target="_blank" &gt;https://developers.mattermost.com/integrate/webhooks/incoming/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Notification.Mattermost
author: Hilko Bengen &amp;lt;bengen@hilluzination.de&amp;gt;
description: |
 Send notification via Mattermost webhook as described in &amp;lt;https://developers.mattermost.com/integrate/webhooks/incoming/&amp;gt;

type: SERVER
parameters:
 - name: url
 description: Webhook URL
 
 - name: text
 description: Markdown-formatted message to display in the post.
 
 - name: channel
 description: Overrides the channel the message posts in.

 - name: username
 description: Overrides the username the message posts as.

 - name: icon_url
 description: Overrides the profile picture the message posts with.
 
 - name: icon_emoji
 description: Overrides the profile picture and icon_url parameter.

sources:
 - query: |
 LET url &amp;lt;= if(
 condition=url,
 then=url,
 else=server_metadata().MattermostWebhookURL)
 LET post_body &amp;lt;= dict(
 text=text,
 format="json")
 LET _ &amp;lt;= if(
 condition=channel,
 then=set(item=post_body, field="channel", value=channel))
 LET _ &amp;lt;= if(
 condition=username,
 then=set(item=post_body, field="username", value=username))
 LET _ &amp;lt;= if(
 condition=icon_url,
 then=set(item=post_body, field="icon_url", value=icon_url))
 LET _ &amp;lt;= if(
 condition=icon_emoji,
 then=set(item=post_body, field="icon_emoji", value=icon_emoji))
 SELECT * from http_client(
 data=serialize(item=post_body),
 headers=dict(`Content-Type`="application/json"),
 method="POST",
 url=url)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.PostProcess.FluentBit</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/fluentbit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/fluentbit/</guid><description>&lt;p&gt;Post-process collection results using &lt;a href="https://fluentbit.io/" target="_blank" &gt;Fluent Bit&lt;/a&gt;
.&lt;/p&gt;

&lt;div class="mynotices warning"&gt;
 &lt;div heading="warning"&gt;&lt;p&gt;Since v0.75 this artifact will no longer work since it reads files directly
from the datastore, which are now
&lt;a href="https://docs.velociraptor.app/blog/2025/2025-08-30-release-notes-0.75/#storing-compressed-data" target="_blank" &gt;compressed using zlib by default&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;It is possible to disable compresion globally using the
&lt;code&gt;Datastore.compression&lt;/code&gt; config setting, but then you will lose the
space-saving benefits of the new compression feature, which are likely to be
significant in most deployments.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Fluent Bit will read the JSONL-formattted results file for each completed
client collection, which can then be modified, filtered, and forwarded to
any of it&amp;rsquo;s large number of supported
&lt;a href="https://docs.fluentbit.io/manual/pipeline/outputs" target="_blank" &gt;outputs&lt;/a&gt;
.
The specific outputs used here are just for demonstration purposes, and you
can easily change the Fluent Bit pipeline config to use a different one.&lt;/p&gt;
&lt;p&gt;The processed data is &lt;em&gt;not&lt;/em&gt; returned to Velociraptor - it is shipped to
external destinations. Although it is possible to read back the data from
stdout it&amp;rsquo;s pointless to do so, unless perhaps you&amp;rsquo;re testing something new
or troubleshooting some issue.&lt;/p&gt;
&lt;h4 id="how-it-works"&gt;How it works&lt;/h4&gt;
&lt;p&gt;Results files are processed individually, per artifact or
artifact/namedsource.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a collection consists of multiple artifacts, only the ones specified in
&lt;code&gt;ClientArtifactsToWatch&lt;/code&gt; will be processed.&lt;/li&gt;
&lt;li&gt;If an artifact contains multiple named sources, then only the ones
designated in &lt;code&gt;ClientArtifactsToWatch&lt;/code&gt; will be processed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enrichments and transformations can be added to Fluent Bit&amp;rsquo;s pipeline via
its Processors and Filters, or alternatively (and probably more easily) such
things can be done on the receiving end.&lt;/p&gt;
&lt;p&gt;This artifact configures Fluent Bit via a YAML config file. This config file
contains the pipeline definition, parser definitions, and other config
options. This is easier to work with rather than specifying everything on
the command line, especially if you want to define more complex pipelines.&lt;/p&gt;
&lt;p&gt;Velociraptor&amp;rsquo;s &lt;code&gt;execve()&lt;/code&gt; plugin runs programs in an isolated environment,
into which some of env variables are injected via the &lt;code&gt;env&lt;/code&gt; argument. The
data in these variables augments the flow data: &lt;code&gt;ClientId&lt;/code&gt;, &lt;code&gt;FlowId&lt;/code&gt;, and
&lt;code&gt;ArtifactName&lt;/code&gt; are added to the processed records for downstream tracking
purposes, but you may choose not to do so. The artifact injects these into
the execve environment and the Fluent config specifies the var =&amp;gt; field
mapping to retrieve them.&lt;/p&gt;
&lt;p&gt;To avoid unnecessarily exposing credentials for the external systems
(outputs) we store these in environment variables so that they aren&amp;rsquo;t
written to any logs. In the Fluent Bit config we specify which env vars to
retrieve the values from using the &lt;code&gt;${VARIABLE}&lt;/code&gt; notation.&lt;/p&gt;
&lt;p&gt;These sensitive variables are defined in text files, to which access will be
restricted. A utility program called &lt;code&gt;envdir&lt;/code&gt; is used to read and populate
the environment with these variables. This program is available in the
official repos for most Linux distributions, and can be installed as
follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo apt install daemontools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The files containing the sensitive env vars can be created as follows (as
root):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;mkdir /etc/opensearch_creds
echo &amp;quot;192.168.1.104&amp;quot; &amp;gt; /etc/opensearch_creds/OPENSEARCH_HOST
echo &amp;quot;9200&amp;quot; &amp;gt; /etc/opensearch_creds/OPENSEARCH_PORT
echo &amp;quot;admin&amp;quot; &amp;gt; /etc/opensearch_creds/OPENSEARCH_USER
echo &amp;quot;ONEtwo333$$$&amp;quot; &amp;gt; /etc/opensearch_creds/OPENSEARCH_PASSWD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your Velociraptor is running as a service then only the &lt;code&gt;velociraptor&lt;/code&gt;
service account needs access to the credential files, and in that case set
permissions on them so that only that specific user has access:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;chown -v velociraptor:velociraptor /etc/opensearch_creds/*
chmod -v 600 /etc/opensearch_creds/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extra fields - &lt;code&gt;ClientId&lt;/code&gt;, &lt;code&gt;FlowId&lt;/code&gt;, and &lt;code&gt;ArtifactName&lt;/code&gt; - are added to the
processed records for downstream tracking purposes, but you may choose not
to do so, or to add other fields. The artifact injects these into the execve
environment and the Fluent config specifies the var -&amp;gt; field mapping to
retrieve them.&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t parse any timestamp from the data because Velociraptor doesn&amp;rsquo;t have
a primary timestamp field, nor even require any timestamps in results.&lt;/p&gt;
&lt;h4 id="server-preparation-checklist"&gt;Server preparation checklist&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Fluent Bit should be installed on the server. It&amp;rsquo;s best to install it
&lt;a href="https://docs.fluentbit.io/manual/installation/linux" target="_blank" &gt;from the official repos&lt;/a&gt;

in which case the binary should be located at
&lt;code&gt;/opt/fluent-bit/bin/fluent-bit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;envdir&lt;/code&gt; utility via the &lt;code&gt;daemontools&lt;/code&gt; package, as described
above.&lt;/li&gt;
&lt;li&gt;Create and secure the sensitive environment variable files, as described
above.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="other-command-line-data-processors"&gt;Other command line data processors&lt;/h4&gt;
&lt;p&gt;Other log forwarders such as Logstash and Filebeats work similarly, in
principle, to Fluent Bit. So this artifact could be used as the basis for
other forwarders or any other command line applications that consume JSONL
format. Any other CLI apps that read and process JSONL data could be used in
the same way using the basic processing logic contained in this artifact.
However, fast startup time is a critical aspect because the application
needs to be launched for each targeted flow, so bloated apps such as
Logstash are likely to be impractical when used this way. Fluent Bit is
lightweight and fast!&lt;/p&gt;
&lt;p&gt;This artifact could also be easily modified to watch for server collection
completions instead of client collections.&lt;/p&gt;
&lt;h4 id="tested-with"&gt;Tested with&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Fluent Bit v4.0.3&lt;/li&gt;
&lt;li&gt;Velociraptor v0.74.5&lt;/li&gt;
&lt;li&gt;Opensearch v3.1.0&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Tags: #post-processing #Elasticsearch #OpenSearch #Splunk #Graylog #BigQuery
#Chronicle #CloudWatch #Amazon #S3 #Azure #Datadog #Dynatrace #InfluxDB
#Kafka #LogDNA #Loki #Oracle #PostgreSQL&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.PostProcess.FluentBit

author: |
 @predictiple - 2025-07-13

description: |
 Post-process collection results using [Fluent Bit](https://fluentbit.io/).

 
&lt;div class="mynotices warning"&gt;
 &lt;div heading="warning"&gt;&lt;pre&gt;&lt;code&gt;Since v0.75 this artifact will no longer work since it reads files directly
from the datastore, which are now
[compressed using zlib by default](https://docs.velociraptor.app/blog/2025/2025-08-30-release-notes-0.75/#storing-compressed-data).

It is possible to disable compresion globally using the
`Datastore.compression` config setting, but then you will lose the
space-saving benefits of the new compression feature, which are likely to be
significant in most deployments.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;



 Fluent Bit will read the JSONL-formattted results file for each completed
 client collection, which can then be modified, filtered, and forwarded to
 any of it's large number of supported
 [outputs](https://docs.fluentbit.io/manual/pipeline/outputs).
 The specific outputs used here are just for demonstration purposes, and you
 can easily change the Fluent Bit pipeline config to use a different one.

 The processed data is _not_ returned to Velociraptor - it is shipped to
 external destinations. Although it is possible to read back the data from
 stdout it's pointless to do so, unless perhaps you're testing something new
 or troubleshooting some issue.

 #### How it works

 Results files are processed individually, per artifact or
 artifact/namedsource.

 - If a collection consists of multiple artifacts, only the ones specified in
 `ClientArtifactsToWatch` will be processed.
 - If an artifact contains multiple named sources, then only the ones
 designated in `ClientArtifactsToWatch` will be processed.

 Enrichments and transformations can be added to Fluent Bit's pipeline via
 its Processors and Filters, or alternatively (and probably more easily) such
 things can be done on the receiving end.

 This artifact configures Fluent Bit via a YAML config file. This config file
 contains the pipeline definition, parser definitions, and other config
 options. This is easier to work with rather than specifying everything on
 the command line, especially if you want to define more complex pipelines.

 Velociraptor's `execve()` plugin runs programs in an isolated environment,
 into which some of env variables are injected via the `env` argument. The
 data in these variables augments the flow data: `ClientId`, `FlowId`, and
 `ArtifactName` are added to the processed records for downstream tracking
 purposes, but you may choose not to do so. The artifact injects these into
 the execve environment and the Fluent config specifies the var =&amp;gt; field
 mapping to retrieve them.

 To avoid unnecessarily exposing credentials for the external systems
 (outputs) we store these in environment variables so that they aren't
 written to any logs. In the Fluent Bit config we specify which env vars to
 retrieve the values from using the `${VARIABLE}` notation.

 These sensitive variables are defined in text files, to which access will be
 restricted. A utility program called `envdir` is used to read and populate
 the environment with these variables. This program is available in the
 official repos for most Linux distributions, and can be installed as
 follows:

 ```sh
 sudo apt install daemontools
 ```

 The files containing the sensitive env vars can be created as follows (as
 root):

 ```sh
 mkdir /etc/opensearch_creds
 echo "192.168.1.104" &amp;gt; /etc/opensearch_creds/OPENSEARCH_HOST
 echo "9200" &amp;gt; /etc/opensearch_creds/OPENSEARCH_PORT
 echo "admin" &amp;gt; /etc/opensearch_creds/OPENSEARCH_USER
 echo "ONEtwo333$$$" &amp;gt; /etc/opensearch_creds/OPENSEARCH_PASSWD
 ```

 If your Velociraptor is running as a service then only the `velociraptor`
 service account needs access to the credential files, and in that case set
 permissions on them so that only that specific user has access:

 ```sh
 chown -v velociraptor:velociraptor /etc/opensearch_creds/*
 chmod -v 600 /etc/opensearch_creds/*
 ```

 Extra fields - `ClientId`, `FlowId`, and `ArtifactName` - are added to the
 processed records for downstream tracking purposes, but you may choose not
 to do so, or to add other fields. The artifact injects these into the execve
 environment and the Fluent config specifies the var -&amp;gt; field mapping to
 retrieve them.

 We don't parse any timestamp from the data because Velociraptor doesn't have
 a primary timestamp field, nor even require any timestamps in results.

 #### Server preparation checklist

 1. Fluent Bit should be installed on the server. It's best to install it
 [from the official repos](https://docs.fluentbit.io/manual/installation/linux)
 in which case the binary should be located at
 `/opt/fluent-bit/bin/fluent-bit`.
 2. Install the `envdir` utility via the `daemontools` package, as described
 above.
 3. Create and secure the sensitive environment variable files, as described
 above.

 #### Other command line data processors

 Other log forwarders such as Logstash and Filebeats work similarly, in
 principle, to Fluent Bit. So this artifact could be used as the basis for
 other forwarders or any other command line applications that consume JSONL
 format. Any other CLI apps that read and process JSONL data could be used in
 the same way using the basic processing logic contained in this artifact.
 However, fast startup time is a critical aspect because the application
 needs to be launched for each targeted flow, so bloated apps such as
 Logstash are likely to be impractical when used this way. Fluent Bit is
 lightweight and fast!

 This artifact could also be easily modified to watch for server collection
 completions instead of client collections.

 #### Tested with

 - Fluent Bit v4.0.3
 - Velociraptor v0.74.5
 - Opensearch v3.1.0

 ---

 Tags: #post-processing #Elasticsearch #OpenSearch #Splunk #Graylog #BigQuery
 #Chronicle #CloudWatch #Amazon #S3 #Azure #Datadog #Dynatrace #InfluxDB
 #Kafka #LogDNA #Loki #Oracle #PostgreSQL

reference:
 - https://docs.fluentbit.io/manual
 - https://fluentbit.io/
 - https://manpages.ubuntu.com/manpages/jammy/man8/envdir.8.html

type: SERVER_EVENT

precondition: SELECT OS From info() where OS = "linux"

required_permissions:
 - EXECVE

parameters:

 - name: ClientArtifactsToWatch
 description: Select the client artifacts to be watched for completions
 type: artifactset
 artifact_type: CLIENT
 sources: TRUE
 default: |
 Artifact
 Windows.Registry.AppCompatCache
 Windows.Forensics.SRUM/Execution Stats

 - name: FluentBinary
 description: The Fluent Bit binary
 type: string
 default: /opt/fluent-bit/bin/fluent-bit

 - name: FluentConfig
 description: The Fluent configuration in YAML format
 type: string
 default: |
 parsers:
 - name: json
 format: json
 service:
 flush: 1
 pipeline:
 inputs:
 - name: tail
 path: ${RESULTSPATH}
 parser: json
 tag: velociraptor
 read_from_head: true
 threaded: false
 exit_on_eof: true
 inotify_watcher: false
 mem_buf_limit: 10mb
 buffer_chunk_size: 128kb
 buffer_max_size: 128kb
 storage.type: memory
 processors:
 logs:
 - name: content_modifier
 action: insert
 key: client_id
 value: ${CLIENTID}
 - name: content_modifier
 action: insert
 key: flow_id
 value: ${FLOWID}
 - name: content_modifier
 action: insert
 key: artifact_name
 value: ${ARTIFACTNAME}

 outputs:
 # we generate this is for the Velociraptor monitoring GUI
 - name: counter
 match: velociraptor

 # uncomment for testing
 # - name: stdout
 # match: velociraptor
 # format: json_lines

 # uncomment if you want to write to a file (for testing)
 # - name: file
 # match: velociraptor
 # path: /tmp/fluent/
 # file: ${FLOWID}_${INDEX}.json
 # format: plain
 # mkdir: true

 # send the data to Opensearch
 - name: opensearch
 match: velociraptor
 host: ${OPENSEARCH_HOST}
 port: ${OPENSEARCH_PORT}
 http_user: ${OPENSEARCH_USER}
 http_passwd: ${OPENSEARCH_PASSWD}
 logstash_format: on
 logstash_prefix: ${INDEX}
 trace_error: on
 trace_output: off
 tls.verify: off
 tls: on
 suppress_type_name: on
 compress: gzip
 buffer_size: 1mb
 retry_limit: 20
 workers: 1


sources:
 - query: |

 -- We write to a temp file and reuse it as long as the monitoring task is active.
 LET FluentConfigFile &amp;lt;= tempfile(data=FluentConfig, extension=".yaml")
 LET _ &amp;lt;= log(message="Config file created at %v", args=FluentConfigFile)

 LET Completions = SELECT *
 FROM watch_monitoring(artifact='System.Flow.Completion')
 -- Try to match ANY artifact in flow against ANY artifact in ClientArtifactsToWatch.
 -- Returns flows where there is at least one match in the completed flow.
 WHERE Flow.artifacts_with_results =~ join(array=ClientArtifactsToWatch.Artifact, sep="|")

 -- Run Fluent Bit for each results file
 LET PostProcess(ClientId, FlowId, ArtifactName, ResultsPath) =
 SELECT *
 FROM execve(argv=[ "envdir", "/etc/opensearch_creds/", FluentBinary, "-q" "-c", FluentConfigFile ],

 -- Inject these vars into the execve environment.
 -- Fluent Bit will retrieve them and add them to the data.
 env=dict(CLIENTID=ClientId,
 FLOWID=FlowId,
 INDEX=lowcase(string=regex_replace(source=ArtifactName, re='''[/ ]''',replace="_")),
 ARTIFACTNAME=ArtifactName,
 RESULTSPATH=ResultsPath
 ),

 -- Under normal circumstances length and line breaks are
 -- irrelevant since we aren't reading the data back.
 --sep="\n",
 length=99999999)


 LET GetResultsFile(ClientId, FlowId, ArtifactName) =
 SELECT
 file_store(path=Data.VFSPath) AS ResultsPath
 FROM enumerate_flow(client_id=ClientId, flow_id=FlowId)
 WHERE Type = "Result"
 -- Match either named or unnamed sources
 AND ( Data.VFSPath =~ ArtifactName
 OR pathspec(parse=Data.VFSPath).Components[-3] + "/" +
 pathspec(parse=Data.VFSPath).Components[-1] =~ ArtifactName )

 SELECT *,
 PostProcess(ClientId=ClientId,
 FlowId=FlowId,
 ArtifactName=ArtifactName,
 ResultsPath=ResultsPath)[0].Stdout AS RecordsProcessed
 FROM foreach(row=Completions,
 query={ SELECT *,
 GetResultsFile(ClientId=ClientId,
 FlowId=FlowId,
 ArtifactName=ArtifactName)[0].ResultsPath AS ResultsPath
 -- We need to check each result within each artifact to see if
 -- it is associated with the flow match that previously occurred.
 FROM foreach(row=Flow.artifacts_with_results,
 query={ SELECT _value AS ArtifactName, ClientId, FlowId
 FROM scope()
 WHERE ArtifactName IN ClientArtifactsToWatch.Artifact
 }
 )
 },
 workers=10
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Slack.Clients.Enrolled</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.slack.clients.enrolled/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.slack.clients.enrolled/</guid><description>&lt;p&gt;Send a message to slack when clients become enrolled.&lt;/p&gt;
&lt;p&gt;This artifact triggers when a client is interrogated within 60
seconds of it being seen for the first time.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Slack.Clients.Enrolled
description: |
 Send a message to slack when clients become enrolled.

 This artifact triggers when a client is interrogated within 60
 seconds of it being seen for the first time.

type: SERVER_EVENT

parameters:
 - name: FirstSeenDelay
 default: "60"
 type: int
 description: |
 The time between first_seen_time and Generic.Client.Info collection.
 - name: SlackToken
 description: |
 The token URL obtained from Slack. Leave blank to use server metadata.
 e.g. https://hooks.slack.com/services/XXXX/YYYY/ZZZZ

sources:
 - query: |
 LET token_url = if(
 condition=SlackToken,
 then=SlackToken,
 else=server_metadata().SlackToken)

 -- Returns an event for each interrogation that occurs within 60 seconds
 -- of first seen timestamp.
 LET completions = SELECT *,
 client_info(client_id=ClientId) AS ClientInfo ,
 now() AS Now
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ "Generic.Client.Info/BasicInformation"
 AND Now - ClientInfo.first_seen_at &amp;lt; FirstSeenDelay

 -- Sends the message to a slack channel.
 LET SendToSlack(Message) = SELECT *
 FROM http_client(
 method="POST",
 headers=dict(`Content-Type`="application/json"),
 data=serialize(format="json", item=dict(text=Message)),
 url=token_url)

 SELECT * FROM foreach(row=completions, query={
 SELECT * FROM foreach(row={
 SELECT * FROM source(
 artifact="Generic.Client.Info/BasicInformation",
 client_id=ClientId, flow_id=FlowId)
 }, query={
 SELECT * FROM SendToSlack(
 Message=format(format="Enrollment FROM %v with ClientID %v!",
 args=[Fqdn, ClientId]))
 })
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Telegram.Clients.Enrolled</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.telegram.clients.enrolled/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.telegram.clients.enrolled/</guid><description>&lt;p&gt;Send a message to telegram when clients become enrolled.&lt;/p&gt;
&lt;p&gt;This artifact triggers when a client is interrogated within 60
seconds of it being seen for the first time. You can manually
configure information such as FirstSeenDelay, timestamp, etc.&lt;/p&gt;
&lt;p&gt;Inspired by &lt;code&gt;Server.Slack.Clients.Enrolled&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Telegram.Clients.Enrolled
author: "td - @tuedenn"
description: |
 Send a message to telegram when clients become enrolled.

 This artifact triggers when a client is interrogated within 60
 seconds of it being seen for the first time. You can manually
 configure information such as FirstSeenDelay, timestamp, etc.

 Inspired by `Server.Slack.Clients.Enrolled`.
type: SERVER_EVENT

parameters:
 - name: FirstSeenDelay
 default: "60"
 type: int
 description: |
 The time between first_seen_time and Generic.Client.Info collection.
 - name: TeleChatID
 description: |
 The chat_id of the group chat you want to send messages to.
 e.g: -872161xxx
 - name: TeleURL
 description: |
 The url of your bot API be used to send message.
 e.g: https://api.telegram.org/bot66666xxxxx:AAGukJg5LXgPkxxxtVU2Smbtrf0tnVuNxxx/sendMessage

sources:
 - query: |
 LET chatID = if(
 condition=TeleChatID,
 then=TeleChatID,
 else=server_metadata().TeleID)

 LET urlTele = if(
 condition=TeleURL,
 then=TeleURL,
 else=server_metadata().TeleURL)

 -- Returns an event for each interrogation that occurs within 60 seconds
 -- of first seen timestamp.

 LET completions = SELECT client_id AS ClientId,
 os_info.hostname AS Hostname,
 os_info.fqdn AS Fqdn,
 last_ip AS LastIP,
 os_info.system AS OS,
 os_info.release AS OSrelease,
 timestamp(epoch=first_seen_at) AS FirstSeen,
 timestamp(epoch=last_seen_at) AS LastSeen,
 timestamp(epoch=now()) AS Now
 FROM clients()
 WHERE last_interrogate_artifact_name = "Generic.Client.Info/BasicInformation"
 AND first_seen_at &amp;gt; now() - FirstSeenDelay

 -- Sends the message to a telegram group.
 LET SendToTele(Message) = SELECT *
 FROM http_client(
 method="POST",
 headers=dict(`Content-Type`="application/json"),
 data=serialize(
 format="json", item=dict(chat_id=chatID, text=Message)),
 url=urlTele)

 LET send_message = SELECT *
 FROM foreach(
 row=completions,
 query={
 SELECT Content, Response, Headers.Date
 FROM SendToTele(
 Message=format(
 format="[Info] New client has been enrolled!\nTime: %v!\nHostname: %s\nIP: %s\nOS: %v",
 args=[FirstSeen, Hostname, LastIP, OSrelease]))
 })

 -- Check every minute using clock() plugin
 SELECT * FROM foreach(
 row={
 SELECT * FROM clock(period=FirstSeenDelay
 )},
 query=send_message)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Utils.BackupAzure</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.backupazure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.backupazure/</guid><description>&lt;p&gt;This server monitoring artifact will automatically zip and backup
any collected artifacts to Azure blob storage.&lt;/p&gt;
&lt;p&gt;You will need to provide a SasURL to upload to the container. The
credentials can be given as parameters or they will be taken from
the server metadata.&lt;/p&gt;
&lt;p&gt;Based on Server.Utils.BackupS3.&lt;/p&gt;
&lt;p&gt;Thanks to @shortxstack and @Recon_InfoSec&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Utils.BackupAzure
description: |
 This server monitoring artifact will automatically zip and backup
 any collected artifacts to Azure blob storage.

 You will need to provide a SasURL to upload to the container. The
 credentials can be given as parameters or they will be taken from
 the server metadata.
 
 Based on Server.Utils.BackupS3.

 Thanks to @shortxstack and @Recon_InfoSec

type: SERVER_EVENT

parameters:
 - name: ArtifactNameRegex
 default: "."
 description: A regular expression to select which artifacts to upload
 type: regex

 - name: SasURL
 description: A SAS URL to use for upload to the container.

 - name: RemoveDownloads
 type: bool
 description: If set, remove the flow export files after upload
 
 - name: UploadSubdirectory
 default: FALSE
 type: bool
 description: If set, upload exports to subirectory per flow

sources:
 - query: |
 -- Allow these settings to be set by the artifact parameter or the server metadata.
 LET sas_url &amp;lt;= if(condition=SasURL, then=SasURL,
 else=server_metadata().DefaultSasURL)

 LET completions = SELECT *,
 client_info(client_id=ClientId).os_info.fqdn AS Fqdn,
 create_flow_download(client_id=ClientId,
 flow_id=FlowId, wait=TRUE) AS FlowDownload
 FROM watch_monitoring(artifact="System.Flow.Completion")
 WHERE Flow.artifacts_with_results =~ ArtifactNameRegex
 
 SELECT upload_azure(
 file=FlowDownload,
 accessor="fs",
 sas_url=sas_url,
 name=if(condition=UploadSubdirectory, 
 then=format(format="%v/Host %v %v %v.zip",args=[FlowId, Fqdn, FlowId, timestamp(epoch=now())]),
 else=format(format="Host %v %v %v.zip",args=[Fqdn, FlowId, timestamp(epoch=now())]))
 ) AS Upload

 FROM completions
 WHERE Upload OR
 if(condition=RemoveDownloads,
 then=rm(filename=file_store(path=FlowDownload)))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Utils.DeleteClientLabel</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/deleteclientlabel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/deleteclientlabel/</guid><description>&lt;p&gt;This artifact completely removes a client from the data store if a configured
label is set.&lt;/p&gt;
&lt;p&gt;We reccomend running as a server artifact then if happy with actions add as an
action for monitoring.&lt;/p&gt;
&lt;p&gt;Be careful with this one: there is no way to recover old
data. However, if the client still exists, it will just
automatically re-enroll when it next connects. You will still be able
to talk to it, it is just that old collected data is deleted.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Utils.DeleteClientLabel
author: Matt Green - @mgreen27
description: |
 This artifact completely removes a client from the data store if a configured
 label is set.

 We reccomend running as a server artifact then if happy with actions add as an
 action for monitoring.

 Be careful with this one: there is no way to recover old
 data. However, if the client still exists, it will just
 automatically re-enroll when it next connects. You will still be able
 to talk to it, it is just that old collected data is deleted.

type: SERVER

parameters:
 - name: LabelToDelete
 description: A label to delete the client if applied to machine.
 default: todelete
 - name: ReallyDoIt
 description: If you really want to delete the client, check this.
 type: bool

sources:
 - query: |
 LET to_remove = SELECT
 client_id AS ClientId,
 os_info.hostname as Hostname,
 timestamp(epoch=first_seen_at) AS FirstSeen,
 timestamp(epoch=last_seen_at) AS LastSeen,
 agent_information.version AS AgentVersion,
 agent_information.build_time AS AgentBuildTime,
 os_info.release as OS,
 os_info.machine as Architecture,
 os_info.fqdn as Fqdn,
 last_ip AS LastIp,
 labels,
 os_info.mac_addresses as mac_addresses
 FROM clients()
 WHERE LabelToDelete IN labels

 LET deleted_files &amp;lt;= SELECT *
 FROM client_delete(client_id=to_remove.ClientId, really_do_it=ReallyDoIt)

 SELECT *,
 {
 SELECT vfs_path
 FROM deleted_files
 WHERE client_id = ClientId
 } AS DeletedFiles,
 {
 SELECT type
 FROM deleted_files
 WHERE client_id = ClientId
 GROUP BY type
 } AS DeletedFileType,
 {
 SELECT really_do_it
 FROM deleted_files
 WHERE client_id = ClientId
 GROUP BY really_do_it
 } AS really_do_it
 FROM to_remove

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Utils.OrphanedFlows</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.orphanedflows/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.orphanedflows/</guid><description>&lt;p&gt;Sometimes flows are deleted but there is still outstanding data for
them in flight. The server will continue to save this data after the
flow is deleted.&lt;/p&gt;
&lt;p&gt;This happens when a hunt is deleted (thereby deleting all its flows)
but there are in flight collections still outstanding.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Utils.OrphanedFlows
description: |
 Sometimes flows are deleted but there is still outstanding data for
 them in flight. The server will continue to save this data after the
 flow is deleted.

 This happens when a hunt is deleted (thereby deleting all its flows)
 but there are in flight collections still outstanding.

type: SERVER

sources:
- query: |
 -- Calculate the space taken by each file (Does not count directories)
 LET _Du(OSPath, Accessor) =
 SELECT sum(item=Size) AS Sum
 FROM glob(globs="/**", root=OSPath, accessor=Accessor)
 GROUP BY 1
 LET Du(OSPath, Accessor) = _Du(OSPath=OSPath, Accessor=Accessor)[0].Sum

 -- Get all collection directories (that contain uploads, monitoring etc).
 LET FlowDirs =
 SELECT OSPath,
 OSPath[-1] AS FlowID, OSPath[-3] AS ClientId
 FROM glob(globs="/clients/*/collections/*", accessor="fs")
 WHERE NOT FlowID =~ ".db"

 -- An OrphanedFlows is a flow that does not have a metadata record
 -- but still has some data.
 LET OrphanedFlows = SELECT file_store(path=OSPath.String) AS Path,
 ClientId, FlowID, {
 SELECT * FROM flows(client_id=ClientId, flow_id=FlowID)
 } AS Details, Du(OSPath=OSPath, Accessor="fs") AS Size
 FROM FlowDirs
 WHERE NOT Details AND Size &amp;gt; 0
 ORDER BY Size DESC

 SELECT Path, ClientId, FlowID, Size, humanize(bytes=Size) AS HumanSize
 FROM OrphanedFlows

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Utils.QuerySummary</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.querysummary/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.querysummary/</guid><description>&lt;p&gt;Takes a query and outputs number of unique items per column, as well as the top 10 most frequently occuring items&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Utils.QuerySummary
author: Clay Norris, Mike Cohen
description: Takes a query and outputs number of unique items per column, as well as the top 10 most frequently occuring items


parameters:
 - name: Query
 
sources:
 - query: |
 LET summary &amp;lt;= dict()
 
 LET IncrementValue(Value, Dict) = set(item=Dict, field=Value, value=get(item=Dict, field=Value, default=0) + 1)
 LET Increment(Column, Value) = set(item=summary, field=Column,
 value=IncrementValue(Value=Value, Dict=get(item=summary, field=Column, default=dict())))
 
 LET _ &amp;lt;= SELECT *, { 
 SELECT Increment(Column=_key, Value=str(str=_value))
 FROM items(item=_value)
 }
 FROM items(item=Query)
 
 SELECT _key as Column, to_dict(item={
 SELECT _key,_value FROM items(item=_value) ORDER BY _value Desc LIMIT 10
 }) as Top10, 
 len(list=_value) as TotalCount 
 FROM items(item=summary) ORDER BY TotalCount DESC

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Server.Utils.ScheduledDeletion</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.scheduleddeletion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/server.utils.scheduleddeletion/</guid><description>&lt;p&gt;Schedules Server.Utils.DeleteMonitoringData to cleanup server monitoring data.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Server.Utils.ScheduledDeletion
author: Zane Gittins
description: |
 Schedules Server.Utils.DeleteMonitoringData to cleanup server monitoring data.

type: SERVER_EVENT

parameters:
 - name: ScheduleDayRegex
 default: .
 - name: ScheduleTimeRegex
 default: "00:00:"
 - name: ArtifactRegex
 default: "EVTX|ETW"
 - name: DaysOld
 default: 7
 type: int

sources:
 - query: |
 LET schedule = SELECT UTC.String AS Now,
 Weekday.String AS Today
 FROM clock(period=60)
 WHERE Now =~ ScheduleTimeRegex AND Today =~ ScheduleDayRegex AND
 log(message="Launching at time " + Now)
 
 SELECT * FROM foreach(row=schedule, query={
 SELECT * FROM Artifact.Server.Utils.DeleteMonitoringData(ArtifactRegex=ArtifactRegex, DateBefore=(now() - 60*60*24*DaysOld), ReallyDoIt=true)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Splunk.Events.Clients</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/splunk.events.clients/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/splunk.events.clients/</guid><description>&lt;p&gt;This server monitoring artifact will watch a selection of client
monitoring artifacts for new events and push those to a splunk
index.&lt;/p&gt;
&lt;p&gt;NOTE: You must ensure you are collecting these artifacts from the
clients by adding them to the &amp;ldquo;Client Events&amp;rdquo; GUI.&lt;/p&gt;
&lt;p&gt;To configure the event collector properly a couple steps need to be
completed prior to setting up this event:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure an index to ingest the data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Index.&lt;/li&gt;
&lt;li&gt;New Index.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the collector.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Data Inputs &amp;gt; HTTP Event Collector.&lt;/li&gt;
&lt;li&gt;Add New.&lt;/li&gt;
&lt;li&gt;Name does not matter, but ensure indexer acknowledgement is OFF.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;Selected Indexes&lt;/code&gt; to the index configured in step 1.&lt;/li&gt;
&lt;li&gt;Save API key for this event.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set Global settings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Data Inputs &amp;gt; HTTP Event Collector &amp;gt; Global Settings&lt;/li&gt;
&lt;li&gt;Ensure &lt;code&gt;All Tokens&lt;/code&gt; is set to ENABLED&lt;/li&gt;
&lt;li&gt;Copy the HTTP Port Number for this event&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure your Splunk props.conf and tranforms.conf&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add the following to props.conf
[vql]
INDEXED_EXTRACTIONS = json
DATETIME_CONFIG = CURRENT
TZ = GMT
category = Custom
pulldown_type = 1
TRANSFORMS-vql-sourcetype = vql-sourcetype,vql-timestamp
TRUNCATE = 512000
KV_MODE = none
AUTO_KV_JSON = false&lt;/li&gt;
&lt;li&gt;Add the following to transforms.conf
[vql-sourcetype]
INGEST_EVAL = sourcetype=lower(src_artifact)
[vql-timestamp]
INGEST_EVAL = _time=case( &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Linux_Search_FileFinder&amp;rdquo;,strptime(CTime,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_System_VFS_ListDirectory&amp;rdquo;,strptime(ctime,&amp;quot;%Y-%m-%dT%H:%M:%S.%NZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Timeline_MFT&amp;rdquo;,strptime(event_time,&amp;quot;%Y-%m-%dT%H:%M:%S.%NZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_NTFS_MFT&amp;rdquo;,strptime(Created0x10,&amp;quot;%Y-%m-%dT%H:%M:%S.%NZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_EventLogs_Evtx&amp;rdquo;,strptime(TimeCreated,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Custom_Windows_EventLogs_System_7045&amp;rdquo;,strptime(TimeCreated,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_EventLogs_RDPAuth&amp;rdquo;,strptime(EventTime,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Analysis_EvidenceOfExecution_UserAssist&amp;rdquo;,strptime(LastExecution,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Analysis_EvidenceOfExecution_Amcache&amp;rdquo;,strptime(KeyMTime,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_System_Amcache_InventoryApplicationFile&amp;rdquo;,strptime(LastModified,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Search_FileFinder&amp;rdquo;,strptime(CTime,&amp;quot;%Y-%m-%dT%H:%M:%S.%NZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Applications_NirsoftBrowserViewer&amp;rdquo;,strptime(Visited,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Registry_RecentDocs&amp;rdquo;,strptime(LastWriteTime,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Forensics_UserAccessLogs_Clients&amp;rdquo;,strptime(InsertDate,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Forensics_UserAccessLogs_DNS&amp;rdquo;,strptime(LastSeen,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Forensics_UserAccessLogs_SystemIdentity&amp;rdquo;,strptime(CreationTime,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Custom_Windows_Application_IIS_IISLogs&amp;rdquo;,strptime(event_time,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_MacOS_Applications_Chrome_History&amp;rdquo;,strptime(last_visit_time,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;), &lt;br&gt;
src_artifact=&amp;ldquo;artifact_Windows_Registry_UserAssist&amp;rdquo;,strptime(LastExecution,&amp;quot;%Y-%m-%dT%H:%M:%SZ&amp;quot;) &lt;br&gt;
)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;Enable SSL&lt;/code&gt; only works if SSL is properly configured on your
Splunk server &amp;ndash; meaning you have proper certificates and DNS. If you are
accessing your Splunk instance by IP, &lt;code&gt;Enable SSL&lt;/code&gt; should be set to OFF.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Splunk.Events.Clients
author: "@jurelou, Modified By @SilverKnightKMA"
description: |
 This server monitoring artifact will watch a selection of client
 monitoring artifacts for new events and push those to a splunk
 index.

 NOTE: You must ensure you are collecting these artifacts from the
 clients by adding them to the "Client Events" GUI.

 To configure the event collector properly a couple steps need to be
 completed prior to setting up this event:
 1. Configure an index to ingest the data.
 * Go to Settings &amp;gt; Index.
 * New Index.
 2. Configure the collector.
 * Go to Settings &amp;gt; Data Inputs &amp;gt; HTTP Event Collector.
 * Add New.
 * Name does not matter, but ensure indexer acknowledgement is OFF.
 * Set `Selected Indexes` to the index configured in step 1.
 * Save API key for this event.
 3. Set Global settings.
 * Go to Settings &amp;gt; Data Inputs &amp;gt; HTTP Event Collector &amp;gt; Global Settings
 * Ensure `All Tokens` is set to ENABLED
 * Copy the HTTP Port Number for this event
 4. Configure your Splunk props.conf and tranforms.conf
 * Add the following to props.conf
 [vql]
 INDEXED_EXTRACTIONS = json
 DATETIME_CONFIG = CURRENT
 TZ = GMT
 category = Custom
 pulldown_type = 1
 TRANSFORMS-vql-sourcetype = vql-sourcetype,vql-timestamp
 TRUNCATE = 512000
 KV_MODE = none
 AUTO_KV_JSON = false
 * Add the following to transforms.conf
 [vql-sourcetype]
 INGEST_EVAL = sourcetype=lower(src_artifact)
 [vql-timestamp]
 INGEST_EVAL = _time=case( \
 src_artifact="artifact_Linux_Search_FileFinder",strptime(CTime,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_System_VFS_ListDirectory",strptime(ctime,"%Y-%m-%dT%H:%M:%S.%NZ"), \
 src_artifact="artifact_Windows_Timeline_MFT",strptime(event_time,"%Y-%m-%dT%H:%M:%S.%NZ"), \
 src_artifact="artifact_Windows_NTFS_MFT",strptime(Created0x10,"%Y-%m-%dT%H:%M:%S.%NZ"), \
 src_artifact="artifact_Windows_EventLogs_Evtx",strptime(TimeCreated,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Custom_Windows_EventLogs_System_7045",strptime(TimeCreated,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_EventLogs_RDPAuth",strptime(EventTime,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Analysis_EvidenceOfExecution_UserAssist",strptime(LastExecution,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Analysis_EvidenceOfExecution_Amcache",strptime(KeyMTime,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_System_Amcache_InventoryApplicationFile",strptime(LastModified,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Search_FileFinder",strptime(CTime,"%Y-%m-%dT%H:%M:%S.%NZ"), \
 src_artifact="artifact_Windows_Applications_NirsoftBrowserViewer",strptime(Visited,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Registry_RecentDocs",strptime(LastWriteTime,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Forensics_UserAccessLogs_Clients",strptime(InsertDate,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Forensics_UserAccessLogs_DNS",strptime(LastSeen,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Forensics_UserAccessLogs_SystemIdentity",strptime(CreationTime,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Custom_Windows_Application_IIS_IISLogs",strptime(event_time,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_MacOS_Applications_Chrome_History",strptime(last_visit_time,"%Y-%m-%dT%H:%M:%SZ"), \
 src_artifact="artifact_Windows_Registry_UserAssist",strptime(LastExecution,"%Y-%m-%dT%H:%M:%SZ") \
 )


 &amp;gt; Note: `Enable SSL` only works if SSL is properly configured on your
 Splunk server -- meaning you have proper certificates and DNS. If you are
 accessing your Splunk instance by IP, `Enable SSL` should be set to OFF.

type: SERVER_EVENT

parameters:
 - name: ClientArtifactsToWatch
 type: artifactset
 artifact_type: CLIENT_EVENT
 default: |
 Artifact
 Windows.Detection.PsexecService
 Windows.Events.ProcessCreation
 Windows.Events.ServiceCreation
 - name: ServerArtifactsToWatch
 type: artifactset
 artifact_type: SERVER_EVENT
 default: |
 Artifact
 Server.Audit.Logs
 - name: url
 default: http://127.0.0.1:8088/services/collector
 description: |
 The Splunk collector url, this is typically the url of the Splunk
 server followed by :8088/services/collector.
 - name: token
 description: |
 API token given when the event collector is configured on Splunk.
 - name: index
 default: velociraptor
 description: |
 Index to ingest the data. This should be set up when configuring
 the event collector.
 - name: SkipVerify
 default: false
 type: bool
 description: |
 SSL configured with the event collector. This is false by default.
 - name: RootCerts
 description: |
 As a better alternative to skip_verify, allows root ca certs to
 be added here.
 - name: HostnameField
 description: Field to extract hostname from
 default: ClientId
 - name: TimestampField
 description: Field to extract timestamp from
 default: timestamp

sources:
 - query: |
 LET artifacts_to_watch = SELECT * FROM chain(
 a={SELECT Artifact FROM ClientArtifactsToWatch},
 b={SELECT Artifact FROM ServerArtifactsToWatch})
 WHERE NOT Artifact =~ "Splunk.Events.Clients"
 AND log(message="Uploading artifact " + Artifact + " to Splunk")
 LET events = SELECT * FROM foreach(
 row=artifacts_to_watch,
 async=TRUE, // Required for event queries in foreach()
 query={
 SELECT *, "Artifact_" + Artifact as _index,
 Artifact,
 timestamp(epoch=now()) AS timestamp
 FROM watch_monitoring(artifact=Artifact)
 })
 
 SELECT * FROM splunk_upload(
 query = events,
 url = url,
 token = token,
 index = index,
 skip_verify = SkipVerify,
 root_ca = RootCerts,
 wait_time=5,
 hostname_field=HostnameField,
 timestamp_field=TimestampField
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ActiveDirectory.PrivilegedUsers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/activedirectoryprivilegedusers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/activedirectoryprivilegedusers/</guid><description>&lt;p&gt;If on a Domain Controller (ProductType = 2), recursively enumerate
membership of privileged groups, then for each user, collect
details relevant to an investigation: Create Date, Last Logon,
Group Membership, SID&lt;/p&gt;
&lt;p&gt;If not on a Domain Controller, return nothing&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ActiveDirectory.PrivilegedUsers

author: liteman @kevinfosec

description: |
 If on a Domain Controller (ProductType = 2), recursively enumerate
 membership of privileged groups, then for each user, collect
 details relevant to an investigation: Create Date, Last Logon,
 Group Membership, SID

 If not on a Domain Controller, return nothing

type: CLIENT

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

 query: |
 LET info &amp;lt;= SELECT * from info()

 LET script &amp;lt;= '

 $prodtype = Get-WmiObject -Class Win32_OperatingSystem | Select -ExpandProperty ProductType

 if ($prodType -eq 2) {
 import-module activedirectory

 $users = @()

 $groups = @("Domain Admins", "Enterprise Admins", "Administrators", "Schema Admins", "Account Operators", "Backup Operators", "Print Operators", "Server Operators", "Cert Publishers")

 foreach ($group in $groups) {
 foreach ($user in @(Get-AdGroupMember -Identity $group -Recursive)) {
 if (-Not $users.contains($user)) {
 $users += $user
 }
 }

 }

 $userdetails = @()
 foreach ($user in ($users | Sort-Object | Get-Unique)) {
 $userdetails += Get-ADUser -Identity $user -Properties *
 }

 ConvertTo-Json -InputObject $userdetails

 }
 '

 LET out = SELECT parse_json_array(data=Stdout) AS Output
 FROM execve(argv=["powershell",
 "-ExecutionPolicy", "Unrestricted", "-encodedCommand",
 base64encode(string=utf16_encode(
 string=script))
 ], length=1000000)
 SELECT * FROM foreach(row=out.Output[0],
 query={
 SELECT
 SamAccountName,
 DistinguishedName,
 SID.Value as UserSID,
 SID.AccountDomainSid as DomainSID,
 Enabled,
 adminCount,
 timestamp(epoch=grok(data=Created, grok="%{INT:timestamp}").timestamp) as created,
 DisplayName,
 timestamp(winfiletime=lastLogon) as last_logon,
 timestamp(epoch=grok(data=Modified, grok="%{INT:timestamp}").timestamp) as modified,
 MemberOf as Groups,
 timestamp(winfiletime=pwdLastSet) as password_last_set

 FROM scope()
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Analysis.Capa</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.analysis.capa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.analysis.capa/</guid><description>&lt;p&gt;Analyze PE, ELF, or shellcode files with capa.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;capa detects capabilities in executable files. You run it against
a PE, ELF, or shellcode file and it tells you what it thinks the
program can do. For example, it might suggest that the file is a
backdoor, is capable of installing services, or relies on HTTP to
communicate.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/fireeye/capa" target="_blank" &gt;https://github.com/fireeye/capa&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Analysis.Capa
description: |
 Analyze PE, ELF, or shellcode files with capa.

 "capa detects capabilities in executable files. You run it against
 a PE, ELF, or shellcode file and it tells you what it thinks the
 program can do. For example, it might suggest that the file is a
 backdoor, is capable of installing services, or relies on HTTP to
 communicate."

 https://github.com/fireeye/capa

type: CLIENT
author: Wes Lambert - @therealwlambert
tools:
 - name: CapaWindows
 url: https://github.com/mandiant/capa/releases/download/v6.1.0/capa-v6.1.0-windows.zip
 expected_hash: 070923d5ca225ef29a670af9cc66a8d648fcaaff7e283cb1ddc73de6e3610f0f
 serve_locally: true
parameters:
 - name: File
sources:
 - query: |
 LET Capa &amp;lt;= SELECT OSPath FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="CapaWindows")
 LET CapaPath &amp;lt;= tempfile(extension=".exe")
 LET UnzipIt &amp;lt;= SELECT
 copy(filename=pathspec(DelegateAccessor='file',
 DelegatePath=Capa[0].OSPath, Path='capa.exe'),
 dest=CapaPath,
 accessor='zip')
 FROM scope()
 Let ExecCapa &amp;lt;= SELECT * FROM execve(argv=[
 CapaPath,
 '-j',
 File
 ], length=10000000)
 LET Data = SELECT * FROM foreach (row={
 SELECT parse_json(data=Stdout)
 AS Data
 FROM ExecCapa}, query={
 SELECT rules FROM Data})
 SELECT * FROM foreach(row=items(item=Data.rules[0]), query={
 SELECT _key AS Rule,
 _value.matches AS Matches,
 get(member="_value.meta.namespace") AS Namespace,
 get(member="_value.meta.scope") AS _Scope,
 get(member="_value.meta.att&amp;amp;ck.0.tactic") AS Tactic,
 get(member="_value.meta.att&amp;amp;ck.0.technique") + " - " + get(member="_value.meta.att&amp;amp;ck.0.id") AS Technique,
 get(member="_value.meta.author") AS _Author,
 get(member="_value.meta") AS _Meta
 FROM scope()})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Analysis.SuspiciousWMIConsumers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/suspiciouswmiconsumers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/suspiciouswmiconsumers/</guid><description>&lt;p&gt;This artifact reports suspicious WMI Event Consumers and their associated Filters
that may indicate a malicious abuse for persistence.&lt;/p&gt;
&lt;p&gt;NOTE: This artifact uses the same logic as Windows.Persistence.PermanentWMIEvents
however, this artifact narrows down the reported results based on a research by SANS.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Analysis.SuspiciousWMIConsumers

description: |
 This artifact reports suspicious WMI Event Consumers and their associated Filters
 that may indicate a malicious abuse for persistence.

 NOTE: This artifact uses the same logic as Windows.Persistence.PermanentWMIEvents 
 however, this artifact narrows down the reported results based on a research by SANS.

reference: 
 - https://youtu.be/aBQ1vEjK6v4

author: Amged Wageh - @amgdgocha

parameters:
 - name: AllRootNamespaces
 description: Select to scan all ROOT namespaces. This setting over rides specific namespaces configured below.
 type: bool
 - name: Namespaces
 description: Add a list of target namespaces.
 type: csv
 default: |
 namespace
 root/subscription
 root/default
 - name: InterstingConsumerTypes
 description: A list of the most abused event consumer types.
 type: csv
 default: |
 consumer_types
 ActiveScriptEventConsumer
 CommandLineEventConsumer
 - name: KnownGoodFilters
 description: A list of known good filter names.
 type: csv
 default: |
 filter_name
 BVTFilter
 TSLogonFilter
 RmAssistEventFilter
 - name: KnownGoodConsumers
 description: A list of known good consumer names.
 type: csv
 default: |
 consumer_name
 NTEventLogConsumer
 "SCM Event Log Consumer"
 - name: KnownBadKeywords
 description: A list of known bad keywords.
 type: csv
 default: |
 keyword
 .exe
 .vbs
 .ps1
 .dll
 .eval
 activexobject
 powershell
 commandLinetemplate
 scripttext
 wscript
 - name: KnownGoodKeywords
 description: A list of known good scripts and executables.
 type: csv
 default: |
 keyword
 TSLogonEvents.vbs
 RAevent.vbs
 KernCap.vbs
 WSCEAA.exe
 - name: ScriptingEngines
 description: A list of the ActiveScriptEventConsumer scripting engines.
 type: csv
 default: |
 scripting_engine
 VBScript
 JScript

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

 query: |
 LET namespaces &amp;lt;= SELECT * FROM if(condition=AllRootNamespaces, 
 then= { 
 SELECT 'root/' + Name as namespace 
 FROM wmi(namespace='ROOT',query='SELECT * FROM __namespace')
 WHERE namespace
 },
 else= Namespaces)

 LET FilterToConsumerBinding &amp;lt;= SELECT * FROM foreach(
 row=namespaces,
 query={
 SELECT parse_string_with_regex(string=Consumer,
 regex=['((?P&amp;lt;namespace&amp;gt;^[^:]+):)?(?P&amp;lt;Type&amp;gt;.+?)\\.Name="(?P&amp;lt;Name&amp;gt;.+)"']) as Consumer,
 parse_string_with_regex(string=Filter,regex=['((?P&amp;lt;namespace&amp;gt;^[^:]+):)?(?P&amp;lt;Type&amp;gt;.+?)\\.Name="(?P&amp;lt;Name&amp;gt;.+)"']) as Filter
 FROM wmi(
 query="SELECT * FROM __FilterToConsumerBinding",namespace=namespace)
 },workers=len(list=namespaces))
 WHERE Consumer.Type IN InterstingConsumerTypes.consumer_types

 LET FilterToConsumerBindingLookup &amp;lt;= SELECT * FROM foreach(
 row=namespaces,
 query={
 SELECT {
 SELECT * FROM wmi(
 query="SELECT * FROM " + Consumer.Type, namespace=Consumer.namespace || namespace) 
 WHERE Name = Consumer.Name AND NOT 
 Name IN KnownGoodConsumers.consumer_name
 } AS ConsumerDetails,
 {
 SELECT * FROM wmi(
 query="SELECT * FROM " + Filter.Type, namespace=Filter.namespace || namespace) 
 WHERE Name = Filter.Name AND NOT
 Name IN KnownGoodFilters.filter_name
 } AS FilterDetails,
 namespace as Namespace
 FROM FilterToConsumerBinding
 WHERE (FilterDetails AND ConsumerDetails)
 },workers=len(list=namespaces))

 LET SuspiciousFilterToConsumerBindingLookup &amp;lt;= SELECT * FROM foreach(
 row=KnownBadKeywords,
 query={
 SELECT ConsumerDetails, FilterDetails 
 FROM FilterToConsumerBindingLookup
 WHERE lowcase(string=ConsumerDetails.CommandLineTemplate) =~ keyword OR 
 lowcase(string=ConsumerDetails.ScriptText) =~ keyword OR 
 ConsumerDetails.ScriptingEngine IN ScriptingEngines.scripting_engine
 }
 ) GROUP BY ConsumerDetails, FilterDetails

 SELECT * FROM foreach(
 row=KnownGoodKeywords,
 query={
 SELECT ConsumerDetails, FilterDetails 
 FROM SuspiciousFilterToConsumerBindingLookup
 WHERE NOT ConsumerDetails.CommandLineTemplate =~ keyword
 }
 ) GROUP BY ConsumerDetails, FilterDetails

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.AnyDesk</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.anydesk/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.anydesk/</guid><description>&lt;p&gt;This parses AnyDesk logs to retrieve information about AnyDesk usage. It includes source IP addresses, AnyDesk ID&amp;rsquo;s, and filetransfers.&lt;/p&gt;
&lt;p&gt;Parts of below code was used from Matt Green - @mgreen27&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.AnyDesk
description: |
 This parses AnyDesk logs to retrieve information about AnyDesk usage. It includes source IP addresses, AnyDesk ID's, and filetransfers.

 Parts of below code was used from Matt Green - @mgreen27

author: Jos Clephas - @DfirJos

reference:
 - https://attack.mitre.org/techniques/T1219/


type: CLIENT
parameters:
 - name: DateAfter
 description: "search for events after this date. YYYY-MM-DDTmm:hh:ss Z"
 type: timestamp
 - name: DateBefore
 description: "search for events before this date. YYYY-MM-DDTmm:hh:ss Z"
 type: timestamp
 - name: SearchVSS
 description: "Add VSS into query."
 type: bool
 - name: MessageRegex
 description: "Keyword search using regex, for example: IP address, AnyDesk ID's"
 default: .
 - name: SearchFilesGlobTable
 type: csv
 default: |
 Glob
 C:\Users\*\AppData\Roaming\AnyDesk\ad_*\ad*.trace
 C:\Users\*\AppData\Roaming\AnyDesk\ad*.trace
 C:\ProgramData\AnyDesk\ad*.trace
 - name: OutputAll
 type: bool
 description: "By default it only shows events concerning IP addresses, AnyDeskID's and source hostnames. By selecting this it outputs all events."
 default: FALSE

sources:
 - query: |
 -- Build time bounds
 LET DateAfterTime &amp;lt;= if(condition=DateAfter,
 then=DateAfter, else="1600-01-01")
 LET DateBeforeTime &amp;lt;= if(condition=DateBefore,
 then=DateBefore, else="2200-01-01")

 LET fspaths &amp;lt;= SELECT OSPath FROM glob(globs=SearchFilesGlobTable.Glob)

 -- function returning list of VSS paths corresponding to path
 LET vsspaths(path) = SELECT OSPath
 FROM Artifact.Windows.Search.VSS(SearchFilesGlob=path)

 LET parse_log(OSPath) = SELECT parse_string_with_regex(
 string=Line,
 regex="^[\\s\\w]+?" + 
 "(?P&amp;lt;Timestamp&amp;gt;[\\d]{4}-[\\d]{2}-[\\d]{2}\\s[\\d]{2}:[\\d]{2}:[\\d]{2}.[\\d]{3})" +
 "\\s+\\w+\\s+" +
 "(?P&amp;lt;PPID&amp;gt;\\d+)\\s+" +
 "(?P&amp;lt;PID&amp;gt;\\d+)[\\s\\w]+" +
 "(?P&amp;lt;Type&amp;gt;.+)[ ][-][ ]" +
 "(?P&amp;lt;Message&amp;gt;" +
 "(Incoming session request: (?P&amp;lt;ComputerName&amp;gt;.+)[ ][(](?P&amp;lt;AnyDeskID&amp;gt;\\d+).)?" +
 "(Logged in from (?P&amp;lt;LoggedInFromIP&amp;gt;[\\d.]+):(?P&amp;lt;Port&amp;gt;\\d+))?" +
 "(?P&amp;lt;SessionStopped&amp;gt;Session stopped)?" +
 "(Preparing files in ['](?P&amp;lt;PotentialFileTransfer&amp;gt;.+)['].+)?" +
 "(External address: (?P&amp;lt;ExternalAddress&amp;gt;[\\d.]+):)?" + 
 ".+$)"
 ) as Record,OSPath
 FROM parse_lines(filename=OSPath) 

 -- function returning IOC hits
 LET logsearch(PathList) = SELECT * FROM foreach(
 row=PathList,
 query={
 SELECT *,timestamp(epoch=Record.Timestamp,format="2006-01-02 15:04:05") AS Timestamp
 FROM parse_log(OSPath=OSPath)
 WHERE Timestamp &amp;lt; DateBeforeTime AND
 Timestamp &amp;gt; DateAfterTime AND 
 Record.Message =~ MessageRegex AND 
 if(condition=OutputAll, then=TRUE, else= Record.ComputerName OR
 Record.LoggedInFromIP OR
 Record.PotentialFileTransfer OR
 Record.SessionStopped OR
 Record.AnyDeskID OR
 Record.ExternalAddress) 
 }) 

 -- include VSS in calculation and deduplicate with GROUP BY by file
 LET include_vss = SELECT * FROM foreach(row=fspaths,
 query={
 SELECT *
 FROM logsearch(PathList={
 SELECT OSPath FROM vsspaths(path=OSPath)
 })
 GROUP BY Record
 })

 -- exclude VSS in logsearch`
 LET exclude_vss = SELECT * FROM logsearch(PathList={SELECT OSPath FROM fspaths})

 -- return rows
 SELECT Timestamp,
 Record.Message as Message,
 Record.ComputerName as ComputerName,
 Record.LoggedInFromIP as LoggedInFromIP,
 Record.PotentialFileTransfer as PotentialFileTransfer,
 Record.AnyDeskID as AnyDeskID,
 Record.ExternalAddress as ExternalAddress,
 OSPath
 FROM if(condition=SearchVSS,
 then=include_vss,
 else=exclude_vss)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.AnyDesk.LogParser</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.anydesk.logparser/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.anydesk.logparser/</guid><description>&lt;p&gt;Parses the AnyDesk ad.trace log file.&lt;/p&gt;
&lt;p&gt;Info such as connection times, clipboard activity, and remote host information are captured.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.AnyDesk.LogParser
description: |
 Parses the AnyDesk ad.trace log file.

 Info such as connection times, clipboard activity, and remote host information are captured.

author: Rob Homewood, angry-bender and Yogesh Khatri (@swiftforensics)

type: CLIENT
parameters:
 - name: FileGlob
 default: C:\Users\*\AppData\Roaming\Anydesk\ad.trace

sources:
 - query: |

 -- Grabs file path of provided file glob
 LET InputLogPath &amp;lt;= SELECT FullPath 
 FROM glob(globs=FileGlob)

 -- Parses file against regex
 LET parse_log &amp;lt;= SELECT
 parse_string_with_regex(
 string=Line,
 regex= ['''\s+(?P&amp;lt;Info&amp;gt;(info)\s+)''', 
 '''(?P&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})''',
 '''(\d{4,}.*?)(?P&amp;lt;PPID&amp;gt;\b\d{4,5}\b)''',
 '''\b\b\d{4,5}.*(?P&amp;lt;PID&amp;gt;\b\b\d{4,5}\b)''',
 '''(?P&amp;lt;Message&amp;gt;(anynet.relay_conn|anynet.any_socket|app.local_file_transfer|app.prepare_task|app.local_file_transfer|app.ctrl_clip_comp|app.backend_session|app.ft_src_session|app.ctrl_clip_comp)\s-\s\w.*)'''])
 as Record
 FROM parse_lines(filename=InputLogPath.FullPath)
 
 -- Prints matching data where there is an entry in Record.Message 
 SELECT Record.Date as Date, Record.PPID as PPID, Record.PID as PID, Record.Message as Message,
 -- Extracts IP address from Message field and adds to its own column
 if(condition=Record.Message=~"External", then=parse_string_with_regex(string=Record.Message, regex="((?:[0-9]{1,3}[\\.]){3}[0-9]{1,3})")).g1 AS ExternalIPAddress,
 -- Extracts remote IP address from Message field and adds to its own column
 if(condition=Record.Message=~"Logged in from ", then=parse_string_with_regex(string=Record.Message, regex="((?:[0-9]{1,3}[\\.]){3}[0-9]{1,3})")).g1 AS RemoteIP
 FROM parse_log 
 WHERE Record.Message

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.Cylance</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/cylance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/cylance/</guid><description>&lt;p&gt;Parse Cylance logs.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.Cylance
author: "Matt Green - @mgreen27"
description: |
 Parse Cylance logs.

parameters:
 - name: FileGlob
 default: C:\ProgramData\Cylance\Status\Status.json

sources:
 - query: |
 LET files = SELECT * FROM glob(globs=FileGlob)
 
 LET parse_json_files = SELECT 
 FullPath,
 parse_json(data=Data) as json
 FROM read_file(filenames=FullPath)
 
 LET results &amp;lt;= SELECT * FROM foreach(
 row=files,
 query=parse_json_files
 )
 
 SELECT 
 FullPath,
 json.SnapshotTime as SnapshotTime,
 json.ProductInfo as ProductInfo,
 json.Policy as Policy,
 json.ScanState as ScanState
 FROM results
 
 - name: Threats
 queries:
 - |
 SELECT * FROM foreach(row={
 SELECT json.Threats.Threat as Threats
 FROM results
 },
 query={
 SELECT * FROM foreach(row=Threats,
 query={
 SELECT 
 time_stamp,
 file_hash_id,
 file_md5,
 file_path,
 full_file_path,
 is_running,
 auto_run,
 file_status,
 file_type,
 score,
 file_size
 FROM scope()
 })
 })
 
 - name: Scripts
 queries:
 - |
 SELECT * FROM foreach(row={
 SELECT json.Scripts.Script as Scripts
 FROM results
 },
 query={
 SELECT * FROM foreach(row=Scripts,
 query={
 SELECT 
 EventDetail,
 script_path,
 script_name,
 file_hash_id,
 file_md5,
 file_sha1,
 drive_type,
 last_modified,
 interpreter,
 username,
 groups,
 sid,
 action
 FROM scope()
 })
 })


 - name: Exploits
 queries:
 - |
 SELECT * FROM foreach(row={
 SELECT json.Exploits.Exploit as Exploits
 FROM results
 },
 query={
 SELECT * FROM foreach(row=Exploits,
 query={
 SELECT 
 EventDetail,
 ProcessId,
 ProcessTag,
 ImagePath,
 ImageHash,
 FileVersion,
 Username,
 Groups,
 Sid,
 ItemType,
 State,
 MemDefVersion,
 Count
 FROM scope()
 })
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.DefenderDHParser</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/defenderdhparser/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/defenderdhparser/</guid><description>&lt;p&gt;This artifact leverages Windows Defender DetectionHistory tool to parse and return
the parameters of Windows Defender detections contained in Detection History files.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.DefenderDHParser

description: |
 This artifact leverages Windows Defender DetectionHistory tool to parse and return
 the parameters of Windows Defender detections contained in Detection History files.

author: Eduardo Mattos - @eduardfir

reference: 
 - https://github.com/jklepsercyber/defender-detectionhistory-parser
 - https://www.sans.org/blog/uncovering-windows-defender-real-time-protection-history-with-dhparser/

tools:
 - name: DHParser
 url: https://github.com/jklepsercyber/defender-detectionhistory-parser/archive/refs/tags/v1.0.zip

parameters:
 - name: DetectionHistoryPath
 description: "Path to Defender Detection History Files"
 default: C:\ProgramData\Microsoft\Windows Defender\Scans\History\Service\

sources:
 - query: |
 -- preparation
 LET Hostname &amp;lt;= SELECT Hostname as Host FROM info()
 LET Toolzip &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="DHParser", IsExecutable=FALSE)
 LET TmpDir &amp;lt;= tempdir(remove_last=TRUE)
 LET UnzipIt &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)
 LET DHParseExePath &amp;lt;= SELECT NewPath as ExePath FROM UnzipIt
 WHERE OriginalPath =~ "dhparser.exe"

 -- execute DHParser
 LET ExecDHParser &amp;lt;= SELECT * FROM execve(argv=[
 DHParseExePath.ExePath[0], 
 "-rgf", DetectionHistoryPath,
 "-o", TmpDir + "\\Output"])
 
 -- store json files' results paths 
 LET jsonFiles &amp;lt;= SELECT Name, FullPath FROM glob(globs="/Output/*", root=TmpDir)
 
 -- parse json files
 SELECT * FROM foreach(row=jsonFiles,
 query={
 SELECT parse_json(data=Data) as Detection,
 { SELECT Host FROM Hostname } as Hostname
 FROM read_file(filenames=FullPath)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.DefenderHistory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.defenderhistory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.defenderhistory/</guid><description>&lt;p&gt;This artifact parses the Windows Defender files generated on threat detection and returns
the contained parameters created by Windows Defender about the detected threat.&lt;/p&gt;
&lt;p&gt;By default with no parameters DefenderHistory parses
&amp;ldquo;C:/ProgramData/Microsoft/Windows Defender/Scans/History/Service/DetectionHistory/**&amp;rdquo;
A different TargetGlob can be entered.&lt;/p&gt;
&lt;p&gt;Based on the research work done by Jordan Klepser @JordanKlepser
&lt;a href="https://github.com/jklepsercyber/defender-detectionhistory-parser" target="_blank" &gt;https://github.com/jklepsercyber/defender-detectionhistory-parser&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.DefenderHistory
author: "Roman Makuch - @rmakuch Kanstantsin Ilioukevitch - @kostyailiouk"
description: |
 This artifact parses the Windows Defender files generated on threat detection and returns
 the contained parameters created by Windows Defender about the detected threat. 

 By default with no parameters DefenderHistory parses 
 "C:/ProgramData/Microsoft/Windows Defender/Scans/History/Service/DetectionHistory/**"
 A different TargetGlob can be entered.

 Based on the research work done by Jordan Klepser @JordanKlepser
 https://github.com/jklepsercyber/defender-detectionhistory-parser 

reference:
 - https://github.com/jklepsercyber/defender-detectionhistory-parser

parameters: 
 - name: TargetGlob
 description: Glob to target.
 default: C:/ProgramData/Microsoft/Windows Defender/Scans/History/Service/DetectionHistory/**

sources:
 - query: |
 Let profile = '''
 [
 ["Info", 0, [
 ["__FileHeaderSearch", 0, "String", {"length": 6, "term":""}],
 ["__FileHeader", 0, "Value", {"value":"x=&amp;gt;format(format='%#x', args=x.__FileHeaderSearch)"}],
 ["__GUID", 24, "GUIDStruct"],
 ["__MagicVersion", 48, "String", {"length": 38, "encoding":"utf16"}],
 ["__ThreatTypeLength", 88, "uint8"],
 ["ThreatType", 96, "String", {"length":"x=&amp;gt; x.__ThreatTypeLength - 2", "encoding":"utf16"}],
 ["ThreatStatusID", 240, "Enumeration", {
 type: "uint8",
 map: {
 "Unknown": 0,
 "Detected": 1,
 "Cleaned": 2,
 "Quarantined": 3,
 "Removed": 4,
 "Allowed": 5,
 "Blocked": 6,
 "Clean Failed": 7,
 "Quarantine Failed": 102,
 "Remove Failed": 103,
 "Allow Failed": 104,
 "Abandoned": 105,
 "Blocked Failed": 107,
 }}],
 ["__Search", 241, "String", {"length": 1024, "term_hex":"0A00000015"}],
 ["SourceType", "x =&amp;gt; len(list=x.__Search) + 249", "String", {"encoding": "utf16"}],
 ["__FullPathLength", "x =&amp;gt; len(list=x.__Search) + 265", "uint8"],
 ["FullPath", "x =&amp;gt; len(list=x.__Search) + 273", "String", {"length":"x=&amp;gt; x.__FullPathLength - 2", "encoding":"utf16"}],
 ["__Sha256Search", 300, "String", {"length": 1024, "term_hex":"53006800610032"}],
 ["Sha256", "x =&amp;gt; len(list=x.__Sha256Search) + 322", "String", {"length": 128, "encoding":"utf16"}],
 ["__TimeSearch", 300, "String", {"length": 1024, "term_hex":"540069006D0065"}],
 ["Time", "x =&amp;gt; len(list=x.__TimeSearch) + 314", "WinFileTime"],
 ["__FileSizeSearch", 300, "String", {"length": 4000, "max_length": 4000, "term_hex":"530069007A0065"}],
 ["ThreatFileSize", "x =&amp;gt; len(list=x.__FileSizeSearch) + 314", "uint32"],
 ["__UserSearch", "x=&amp;gt; if(condition=Size &amp;gt; 1024, then=(Size - 1024), else=0)", "String", {"length": 1024, "term_hex":"0000080000000A0000"}],
 ["__Section3Offset", 0, "Value", {"value": "x =&amp;gt; if(condition=Size &amp;gt; 1024, then=len(list=x.__UserSearch) + (Size - 1024), else=len(list=x.__UserSearch)) + 114" }],
 ["User", "x =&amp;gt; x.__Section3Offset", "String", {"encoding": "utf16"}],
 ["__SearchStartingProcess", "x=&amp;gt; x.__Section3Offset + len(list=x.User)", "String", {"length": 1024, "term_hex": "0000150000"}],
 ["StartingProcess", "x=&amp;gt; x.__Section3Offset + len(list=x.User) + len(list=x.__SearchStartingProcess) + 6", "String", {"encoding": "utf16"}]
 ]],
 ["GUIDStruct", 16, [
 ["__D1", 0, "uint32"],
 ["__D2", 4, "uint16"],
 ["__D3", 6, "uint16"],
 ["__D4", 8, "String", {"term": "", "length": 2}],
 ["__D5", 10, "String", {"term": "", "length": 6}],
 ["DetectionID", 0, "Value", {"value": "x=&amp;gt;format(format='{%x-%x-%x-%x-%x}', args=[x.__D1, x.__D2, x.__D3, x.__D4, x.__D5])"}]
 ]],
 ]
 '''
 
 Let temp = SELECT FullPath, 
 Size, 
 parse_binary(filename=FullPath, profile = profile, struct = 'Info') as parsedfile 
 FROM glob(globs = TargetGlob)
 Where IsDir = False
 
 SELECT parsedfile.Time as EventTime,
 parsedfile.ThreatType as ThreatType,
 parsedfile.ThreatStatusID as ThreatStatus,
 parsedfile.FullPath as FullPath,
 parsedfile.Sha256 as Sha256,
 parsedfile.SourceType as SourceType,
 parsedfile.ThreatFileSize as FileSizeBytes,
 parsedfile.User as User,
 parsedfile.StartingProcess as StartingProcess,
 FullPath as ParsedFileFullPath
 FROM temp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.DefenderQuarantineExtract</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/defenderquarantineextract/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/defenderquarantineextract/</guid><description>&lt;p&gt;Extracts Quarantine Files from Windows Defender.&lt;/p&gt;
&lt;p&gt;This artifact decrypts the RC4 encrypted Windows Defender Quarantined files
and returns information about it. If it is a PE, it also parses the PE.&lt;/p&gt;
&lt;p&gt;You may also choose to upload the extracted binaries for deeper malware analysis.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.DefenderQuarantineExtract
author: "Eduardo Mattos - @eduardfir, @niicolaa"
description: |
 Extracts Quarantine Files from Windows Defender.

 This artifact decrypts the RC4 encrypted Windows Defender Quarantined files
 and returns information about it. If it is a PE, it also parses the PE.

 You may also choose to upload the extracted binaries for deeper malware analysis.

reference:
 - https://reversingfun.com/posts/how-to-extract-quarantine-files-from-windows-defender
 - https://blog.fox-it.com/2023/12/14/reverse-reveal-recover-windows-defender-quarantine-forensics/
 - https://artefacts.help/windows_defender_quarantine.html

type: CLIENT

parameters:
 - name: TargetGlob
 description: Target Files
 default: C:/ProgramData/Microsoft/Windows Defender/Quarantine/ResourceData/*/*
 - name: UploadDecodedFiles
 description: Select to upload decoded quarantined files.
 type: bool
 - name: DefenderRC4KeyHex
 default: "1e87781b8dbaa844ce69702c0c78b786a3f623b738f5edf9af83530fb3fc54faa21eb9cf1331fd0f0da954f687cb9e18279697900e53fb317c9cbce48e23d05371ecc15951b8f3649d7ca33ed68dc9047e82c9baad9799d0d458cb847ca9ffbe3c8a775233557dde13a8b14087cc1bc8f10f6ecdd083a959cff84a9d1d50755e3e191818af23e2293558766d2c07e25712b2ca0b535ed8f6c56ce73d24bdd0291771861a54b4c285a9a3db7aca6d224aeacd621db9f2a22ed1e9e11d75bed7dc0ecb0a8e68a2ff1263408dc808dffd164b116774cd0b9b8d05411ed6262e429ba495676b8398db2f35d3c1b9ced52636f2765e1a95cb7ca4c3ddabddbff38253"

sources:
 - query: |
 LET Targets = SELECT Mtime,
 Name,
 OSPath
 FROM glob(globs=TargetGlob)
 LET DefenderRC4Key = unhex(string=DefenderRC4KeyHex)
 LET Decrypted = SELECT Name,
 OSPath,
 Mtime,
 read_file(
 filename=crypto_rc4(
 key=DefenderRC4Key,
 string=read_file(filename=OSPath, accessor="file")),
 accessor="data") AS Plain
 FROM Targets
 LET Profile &amp;lt;= '''
 [
 ["Root", 0, [
 ["SDLen", 8, "uint32"],
 ["HeaderLen", 0, "Value", {"value": "x=&amp;gt;0x28 + x.SDLen"}],
 ["MalLen", "x=&amp;gt;x.SDLen + 0x1C", "uint64"],
 ["DecodedFile", 0, "Value", {
 "value": "x=&amp;gt;read_file(filename=Plain, accessor='data', offset=x.HeaderLen, length=x.MalLen)"
 }],
 ["UnparsedFooter", 0, "Value", {
 "value": "x=&amp;gt;read_file(filename=Plain, accessor='data', offset=x.HeaderLen + x.MalLen)"
 }]
 ]]
 ]'''
 LET Trimmed &amp;lt;= SELECT 
 Name,
 OSPath,
 Mtime,
 Plain,
 parse_binary(
 filename=Plain,
 accessor="data",
 profile=Profile,
 struct="Root") AS Parsed
 FROM Decrypted
 
 SELECT 
 magic(
 path=Parsed.DecodedFile,
 accessor="data") AS Magic,
 hash(
 path=Parsed.DecodedFile,
 accessor="data") AS Hash,
 Name,
 OSPath,
 Mtime,
 Parsed.MalLen AS MalfileLen,
 Parsed.UnparsedFooter AS UnparsedFooter,
 parse_pe(
 file=Parsed.DecodedFile,
 accessor="data") AS ParsedPE,
 if(
 condition=UploadDecodedFiles,
 then={
 SELECT 
 upload(
 file=Parsed.DecodedFile,
 accessor="data",
 name=Name + "_Defender_Quarantine_Extract.bin") AS FileDetails
 FROM Trimmed
 }) AS Upload
 FROM Trimmed

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.DIEC</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/diec/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/diec/</guid><description>&lt;p&gt;Execute DetectItEasy (console version) on specified paths and
return rows of results to hunt/filter on binaries based types of
files (E.g.: Packed binaries and its packers)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.DIEC
description: |
 Execute DetectItEasy (console version) on specified paths and
 return rows of results to hunt/filter on binaries based types of
 files (E.g.: Packed binaries and its packers)

author: Eduardo Mattos - @eduardfir

reference:
 - https://github.com/horsicq/Detect-It-Easy

type: CLIENT

tools:
 - name: DIEC
 url: https://github.com/horsicq/DIE-engine/releases/download/3.03b/die_win64_portable_3.03.zip

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

parameters:
 - name: TargetGlob
 default: C:\Users\**\*.{exe,dll}

 - name: EntropyScan
 type: bool

sources:
 - query: |
 -- preparation
 LET Toolzip &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="DIEC", IsExecutable=FALSE)
 LET TmpDir &amp;lt;= tempdir(remove_last=TRUE)
 LET UnzipIt &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)

 LET Targets &amp;lt;= SELECT FullPath FROM glob(globs=TargetGlob)

 -- execute DIEC
 LET ExecDIEC &amp;lt;= SELECT * FROM if(condition=EntropyScan,
 then={ -- execute EntropyScan
 SELECT * FROM foreach(row=Targets,
 query={
 SELECT parse_json(data=Stdout) as DiecOutput, FullPath
 FROM execve(argv=[
 TmpDir + "/die_win64_portable/diec.exe",
 "-e",
 "-j",
 FullPath])
 })
 },
 else={ -- execute DeepScan
 SELECT * FROM foreach(row=Targets,
 query={
 SELECT parse_json(data=Stdout) as DiecOutput, FullPath
 FROM execve(argv=[
 TmpDir + "/die_win64_portable/diec.exe",
 "-d",
 "-j",
 FullPath])
 })
 })

 -- format the output according to selected scan type
 SELECT * FROM if(condition=EntropyScan,
 then={
 SELECT
 DiecOutput.records as Records,
 DiecOutput.status as Status,
 DiecOutput.total as Entropy,
 FullPath
 FROM ExecDIEC
 },
 else={
 SELECT
 dict(Arch=DiecOutput.arch,
 Endianess=DiecOutput.endianess,
 FileType=DiecOutput.filetype,
 Mode=DiecOutput.mode,
 Type=DiecOutput.type) as PEInfo,
 DiecOutput.detects as Detects,
 FullPath
 FROM ExecDIEC
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.FreeFileSync</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.freefilesync/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.freefilesync/</guid><description>&lt;p&gt;This artefact can be used to retrieve and parse some FreeFileSync file in order to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify the latest account used to transfer data and the remote ip adresse destination in the case of SFTP protocol with the qeury GlobalInfo&lt;/li&gt;
&lt;li&gt;Identify the latest transfered files with Latest Data Transfer&lt;/li&gt;
&lt;li&gt;Identify the presence of others interesting logs about previous or attempt of files transfer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the case of logs files, only the html version has been parsed&lt;/p&gt;
&lt;p&gt;These query were made in the context of the use of legitimate data transfer tools by an attacker.
You can read more about it on &lt;a href="https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat" target="_blank" &gt;https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.FreeFileSync
author: Nathanaël Ndong, Synacktiv
description: |
 This artefact can be used to retrieve and parse some FreeFileSync file in order to:
 - Identify the latest account used to transfer data and the remote ip adresse destination in the case of SFTP protocol with the qeury GlobalInfo
 - Identify the latest transfered files with Latest Data Transfer
 - Identify the presence of others interesting logs about previous or attempt of files transfer

 In the case of logs files, only the html version has been parsed
 
 These query were made in the context of the use of legitimate data transfer tools by an attacker.
 You can read more about it on https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat

type: CLIENT

parameters:
 - name: FreeFileInfoGlob
 default: \AppData\Roaming\FreeFileSync\
 description: Use to retreive lastest global information including userID and remote destination for SFTP from GlobalSettings.xml file

 - name: userRegex
 default: .
 type: regex 
 
 - name: SearchFreeFileSyncLogs
 default: C:\Users\*\AppData\Roaming\FreeFileSync\Logs\*
 description: Use a glob to define the files that will be searched

 - name: FreeFileSyncGlob
 default: C:\Users\*\AppData\Roaming\FreeFileSync\Logs\*Last*.html
 description: Use to retreive and parse lastest html log file
 
sources:
 - name: GlobalInfo
 query: |
 
 LET GlobalSettings_xml = SELECT * FROM foreach(
 row={
 SELECT Uid, Name As User,
 expand (path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name=~userRegex
 },
 query={
 SELECT User, OSPath,
 parse_xml(file=OSPath).FreeFileSync.MainDialog.FilePanel.FolderHistoryRight AS Protocol,
 parse_xml(file=OSPath).FreeFileSync.LastOnlineCheck AS Online,
 Mtime
 FROM glob(globs=FreeFileInfoGlob + 'GlobalSettings.xml', root=HomeDirectory)
 })
 
 LET Value = SELECT * FROM foreach(
 row=GlobalSettings_xml,
 query={
 SELECT *, OSPath AS SourceFilePath
 FROM foreach(row=Protocol, query={
 SELECT * FROM _value
 })
 })
 
 SELECT Item AS Last_Session_GlobalInfo FROM Value

 - name: Latest Data Transfer
 query: |
 LET InputLogPath = SELECT OSPath FROM glob(globs=FreeFileSyncGlob)
 
 LET extract_file(message)= parse_string_with_regex(string=message,
 regex=
 '''&amp;lt;.+?&amp;gt;(?P&amp;lt;Copy&amp;gt;.+?\s.+?)\s''' +
 '''&amp;amp;quot;'''+
 '''&amp;lt;*(?P&amp;lt;Provider&amp;gt;.+?)'''+
 ''':'''+
 '''[/\\]{1,2}'''+'''(?P&amp;lt;Connexion&amp;gt;.+?)[/\\]'''+
 '''(?P&amp;lt;Message&amp;gt;.+?)'''+
 '''&amp;amp;.*?&amp;lt;/.+?&amp;gt;'''
 )
 
 LET last_date(message) = parse_string_with_regex(string=message,
 regex=
 '''(?P&amp;lt;Directory&amp;gt;.+?)''' +
 '''(?P&amp;lt;Date&amp;gt;\[.+?).html'''
 )
 
 LET parsed_line = SELECT * FROM foreach(row=InputLogPath,
 query={
 SELECT Line, FullPath FROM parse_lines(filename=InputLogPath.FullPath)
 WHERE Line =~ "Creating"
 })
 
 SELECT extract_file(message=Line).Copy AS Operation,
 extract_file(message=Line).Provider AS Protocol,
 extract_file(message=Line).Connexion AS Identifer, 
 extract_file(message=Line).Message AS File_Destination,
 last_date(message=FullPath).Date AS Last_Session_Date
 FROM parsed_line
 
 
 - name: FileUpload
 query: |
 LET logs_search = SELECT 
 OSPath,
 get(item=Data, field="mft") as Inode,
 Mode.String AS Mode,
 Size,
 Btime AS BTime,
 Mtime AS MTime,
 Ctime AS CTime,
 Atime AS ATime,
 IsDir, Data
 FROM glob(globs=SearchFreeFileSyncLogs)
 
 SELECT OSPath, Size,
 BTime, MTime, ATime,
 upload(file=OSPath) AS Upload
 FROM logs_search

column_types:
 - name: Modified
 type: timestamp
 - name: ATime
 type: timestamp
 - name: MTime
 type: timestamp
 - name: CTime
 type: timestamp
 - name: Upload
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.FTKImager</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ftkimager/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ftkimager/</guid><description>&lt;p&gt;Create an E01 Image of the C drive using FTK Imager (Command Line
Version)&lt;/p&gt;
&lt;p&gt;SourceDriveToImage usually will be 0 (as in \.\PHYSICALDRIVE0)
for the C: drive, on a Windows system.&lt;/p&gt;
&lt;p&gt;If you intend to image the secondary drive, use, for example,
SourceDriveToImage = 1, for \.\PHYSICALDRIVE1&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.FTKImager
description: |
 Create an E01 Image of the C drive using FTK Imager (Command Line
 Version)

 SourceDriveToImage usually will be 0 (as in \\.\PHYSICALDRIVE0)
 for the C: drive, on a Windows system.

 If you intend to image the secondary drive, use, for example,
 SourceDriveToImage = 1, for \\.\PHYSICALDRIVE1

author: Eduardo Mattos - @eduardfir

reference:
 - https://accessdata.com/products-services/forensic-toolkit-ftk/ftkimager

type: CLIENT

tools:
 - name: FTKImager
 url: https://ad-zip.s3.amazonaws.com/FTKImager.3.1.1_win32.zip

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

parameters:
 - name: SourceDriveToImage
 default: "0"

 - name: OutputPath
 default: "D:\\E01"

sources:
 - query: |
 -- get context on target binary
 LET bin &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="FTKImager")

 LET tmpdir &amp;lt;= tempdir()

 LET zip_file &amp;lt;= SELECT *
 FROM unzip(filename=bin[0].FullPath,
 output_directory=tmpdir)
 WHERE OriginalPath =~ "ftkimager.exe"

 -- execute payload
 SELECT Stdout, Stderr
 FROM execve(argv=[
 zip_file.NewPath[0],
 "\\\\.\\PHYSICALDRIVE" + SourceDriveToImage,
 OutputPath])

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.GoodSync</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.goodsync/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.goodsync/</guid><description>&lt;p&gt;This artefact can be used to retrieve and parse some GoodSync file in order to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;identify configured Good Sync account;&lt;/li&gt;
&lt;li&gt;identify data and time of transfered files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact have been created to identify potential exfiltrated files using GoodSync tool.
You can read more about it on &lt;a href="https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat" target="_blank" &gt;https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.GoodSync
author: Nathanaël Ndong, Synacktiv
description: |
 This artefact can be used to retrieve and parse some GoodSync file in order to
 - identify configured Good Sync account;
 - identify data and time of transfered files.
 
 This artifact have been created to identify potential exfiltrated files using GoodSync tool.
 You can read more about it on https://www.synacktiv.com/publications/legitimate-exfiltration-tools-summary-and-detection-for-incident-response-and-threat

type: CLIENT
parameters:
 - name: FileGlob
 default: C:\Users\*\AppData\Local\GoodSync\GoodSync-*

sources:
 - name: sync files
 query: |

 -- Grabs file path of provided file glob
 LET InputLogPath &amp;lt;= SELECT FullPath 
 FROM glob(globs=FileGlob)

 -- Parses file against regex
 LET parse_log &amp;lt;= SELECT
 parse_string_with_regex(
 string=Line,
 regex= '''^(?P&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s''' + 
 '''#\d+\s'''+
 '''(?P&amp;lt;Message&amp;gt;.+?)$''')
 as Record
 FROM parse_lines(filename=InputLogPath.FullPath)
 
 --SELECT * FROM parse_log WHERE Record.Message =~ "Copy New"
 -- Prints matching data where there is an entry in Record.Message 
 LET extract_files(message) =
 parse_string_with_regex(string=message,
 regex=
 '''^(?P&amp;lt;Protocol&amp;gt;\[.+?\])\s''' +
 '''.?''' +
 '''\s?(?P&amp;lt;Operation&amp;gt;Copy\sNew)\s''' +
 '''\'(?P&amp;lt;Source&amp;gt;.+?)\'\s''' +
 '''.+?\s''' +
 '''\'(?P&amp;lt;Destination&amp;gt;.+?)\'\s''' +
 '''\((?P&amp;lt;Byte&amp;gt;.+?)\)'''
 )
 SELECT Record.Date as Date, 
 extract_files(message=Record.Message).Protocol AS Protocol,
 extract_files(message=Record.Message).Operation AS Operation,
 extract_files(message=Record.Message).Source AS Source,
 extract_files(message=Record.Message).Destination AS Destination,
 extract_files(message=Record.Message).Size AS Size
 FROM parse_log
 WHERE Record.Message =~ "Copy New"
 
 - name: good_sync_account
 query: |
 
 LET InputLogPath &amp;lt;= SELECT FullPath 
 FROM glob(globs=FileGlob)

 LET parse_log &amp;lt;= SELECT
 parse_string_with_regex(
 string=Line,
 regex= '''^(?P&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s''' + 
 '''#\d+\s'''+
 '''(?P&amp;lt;Message&amp;gt;.+?)$''')
 as Record
 FROM parse_lines(filename=InputLogPath.FullPath)
 
 LET extract_user(message)= parse_string_with_regex(string=message,
 regex='''.+?\s.+?\s.+?\s''' +
 '''UserId=''' +
 '''(?P&amp;lt;UserId&amp;gt;.+?)\s''' +
 '''m_bLicActive=''' +
 '''(?P&amp;lt;Nb_licence&amp;gt;.+?)\s''' +
 '''.+?''' +
 '''(?P&amp;lt;Date_expiration&amp;gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s'''+
 '''.+?\s.+?\s.+?''' +
 '''(?P&amp;lt;Date_creation&amp;gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s'''
 ) 

 --SELECT * FROM parse_log WHERE Record.Message =~ "CheckLicenseViaGsAccount:" 
 SELECT Record.Date as Date,
 extract_user(message=Record.Message).UserId AS GoodSync_Account,
 extract_user(message=Record.Message).Nb_licence AS Active_Licence,
 extract_user(message=Record.Message).Date_expiration AS Licence_Expiration,
 extract_user(message=Record.Message).Date_creation AS Account_Creation
 FROM parse_log
 WHERE Record.Message =~ "CheckLicenseViaGsAccount:" 
 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.KACE_SW_Process</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/kace_sw_process/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/kace_sw_process/</guid><description>&lt;p&gt;This artifact parses the KACE software monitoring sqlite database - ksw_process.db
which provides excellent third party evidence of execution that may
be useful during investigation or detection work.&lt;/p&gt;
&lt;p&gt;The artifact can also be modified to target other KACE sqlite databases or set
timebounds using stime or etime fields.&lt;br&gt;
e.g: &lt;br&gt;
&lt;code&gt;SELECT * FROM process WHERE stime &amp;gt; '2023-01'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;SELECT * FROM process WHERE etime &amp;lt; '2022-12-25'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;SELECT * FROM process WHERE stime &amp;gt; '2023-01' AND etime &amp;lt; '2023-01-06'&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.KACE_SW_Process
author: Matt Green - @mgreen27
description: |
 This artifact parses the KACE software monitoring sqlite database - ksw_process.db
 which provides excellent third party evidence of execution that may 
 be useful during investigation or detection work. 
 
 The artifact can also be modified to target other KACE sqlite databases or set 
 timebounds using stime or etime fields. 
 e.g: 
 `SELECT * FROM process WHERE stime &amp;gt; '2023-01'` 
 `SELECT * FROM process WHERE etime &amp;lt; '2022-12-25'` 
 `SELECT * FROM process WHERE stime &amp;gt; '2023-01' AND etime &amp;lt; '2023-01-06'` 


parameters:
 - name: TargetGlob
 default: C:/ProgramData/Quest/KACE/ksw_process.db
 description: glob of sqlite db to target
 - name: SqlQuery
 description: SQL query to run
 default: |
 SELECT * FROM process
 - name: UserRegex
 description: regex of strings to match in user field
 default: .
 type: regex
 - name: ProcessNameRegex
 description: regex of strings to match in name field
 default: .
 type: regex
 - name: ProcessExclusionRegex
 description: regex of strings to exclude in name field.
 default: 
 type: regex

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

sources:
 - query: |
 -- find files in scope
 LET files = SELECT OSPath FROM glob(globs=TargetGlob)
 
 -- query db and output results
 SELECT * FROM foreach(row=files,
 query={
 SELECT *
 FROM sqlite(
 file=TargetGlob,
 query=SqlQuery)
 WHERE user =~ UserRegex
 AND name =~ ProcessNameRegex
 AND NOT if(condition= ProcessExclusionRegex,
 then= name=~ProcessExclusionRegex,
 else= False)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.LECmd</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.lecmd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.lecmd/</guid><description>&lt;p&gt;Execute Eric Zimmerman&amp;rsquo;s LECmd and return output for analysis.
Created using @eduardfir SBECmd VQL as a quide.&lt;br&gt;
LECmd is a CLI tool for analyzing lnk data. Learn more - &lt;a href="https://github.com/EricZimmerman/LECmd" target="_blank" &gt;https://github.com/EricZimmerman/LECmd&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.LECmd
description: |
 Execute Eric Zimmerman's LECmd and return output for analysis.
 Created using @eduardfir SBECmd VQL as a quide. 
 LECmd is a CLI tool for analyzing lnk data. Learn more - https://github.com/EricZimmerman/LECmd

author: Carlos Cajigas @carlos_cajigas. Modified by Zach K. https://www.linkedin.com/in/zach-kal on 2026-02-10 to address 404-url and csv parsing issues.

type: CLIENT

tools:
 - name: LECmd
 url: https://download.ericzimmermanstools.com/LECmd.zip
 version: 1.5.1
 
parameters:
 - name: sourceFile
 default: .
 type: regex
 description: "RegEx pattern for the name or path of the lnk file. Example 'recent' folder"
 - name: localPath
 default: .
 type: regex
 description: "RegEx pattern for the name or path of the target of the lnk file. Example 'cmd.exe'"
 - name: arguments
 default: .
 type: regex
 description: "Arguments of the lnk file. Example '/c powershell Invoke-Command'"
 - name: dateAfter
 description: "search for lnk files with a SourceCreated after this date. YYYY-MM-DD"
 - name: dateBefore
 description: "search for lnk files with a SourceCreated before this date. YYYY-MM-DD"

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

sources:
 - query: |
 -- get context on target binary
 LET lecmdpackage &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="LECmd", IsExecutable=FALSE)

 -- build tempfolder for output
 LET tmpdir &amp;lt;= tempdir()
 
 -- decompress utility
 LET payload = SELECT * 
 FROM unzip(filename=lecmdpackage[0].FullPath,
 output_directory=tmpdir)
 
 -- execute payload
 LET deploy &amp;lt;= SELECT * 
 FROM execve(argv=[payload.NewPath[0], 
 "-d", 
 "c:/", 
 "--csv", 
 tmpdir, 
 "--csvf", 
 "results.csv"])
 
 -- find the actual CSV file created
 LET csvfile &amp;lt;= SELECT OSPath FROM glob(globs="results*.csv", root=tmpdir) LIMIT 1
 
 -- parse csv
 SELECT SourceFile, LocalPath, Arguments, SourceCreated, 
 SourceModified, WorkingDirectory, RelativePath, 
 TargetCreated, TargetModified, DriveType, VolumeLabel
 FROM parse_csv(filename=csvfile.OSPath[0])
 WHERE 
 (if(condition=dateAfter, then=SourceCreated &amp;gt; dateAfter,
 else=TRUE) AND 
 if(condition=dateBefore, then=SourceCreated &amp;lt; dateBefore, 
 else=TRUE))
 AND SourceFile =~ sourceFile
 AND LocalPath =~ localPath
 AND Arguments =~ arguments

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.MouseWithoutBorders</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.mousewithoutborders/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.applications.mousewithoutborders/</guid><description>&lt;p&gt;This artifact parses Microsoft Mouse Without Borders (MWB) runtime logs, module interface logs and the settings file.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s recommended to use the Sort and Stack features to handle repeated events effectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.MouseWithoutBorders
description: |
 This artifact parses Microsoft Mouse Without Borders (MWB) runtime logs, module interface logs and the settings file.


 * It's recommended to use the Sort and Stack features to handle repeated events effectively.

author: Mohamed Sultan
 
reference:
 - https://0xsultan.github.io/dfir/Exfiltrate-Without-Borders/

type: CLIENT
parameters:
 - name: UserFilter
 default: .
 type: regex
 description: Regex to filter specific users (default all users)
 
 - name: DateAfter
 type: timestamp
 description: Only show logs after this date
 
 - name: DateBefore
 type: timestamp
 description: Only show logs before this date
 
 - name: RuntimeLogs
 default: 'C:\Users\*\AppData\Local\Microsoft\PowerToys\MouseWithoutBorders\Logs\*\*.*'
 description: Glob to runtime logs.

 - name: ModuleLogFiles
 default: 'C:\Users\*\AppData\Local\Microsoft\PowerToys\MouseWithoutBorders\LogsModuleInterface\*.*'
 description: Glob pattern for module interface log files

 - name: SettingsFile
 default: 'C:\Users\*\AppData\Local\Microsoft\PowerToys\MouseWithoutBorders\settings.json'
 description: Glob to settings.

precondition: SELECT OS FROM info() WHERE OS = 'windows'

sources:

 - name: RuntimeLogs
 description: Parses MWB runtime logs
 query: |
 -- message line e.g. 05/17 07:29:43.152(1)PowerToys Started!
 LET MessageRegex = '''(?P&amp;lt;MonthDay&amp;gt;\d{2}/\d{2}) (?P&amp;lt;Time&amp;gt;\d{2}:\d{2}:\d{2}\.\d+)\((?P&amp;lt;ThreadID&amp;gt;\d+)\)(?P&amp;lt;Message&amp;gt;.+)'''

 -- message patterns
 LET ImportantPatterns = '''PowerToys Started|TCP listening on port|Keyboard/Mouse hooks installed|Helper process|New connection from client|tcpClient\.Connect.*Unable to connect|Cannot resolve.*machine|==&amp;gt; '''
 
 -- parse runtime log files
 LET parsed_messages = SELECT * FROM foreach(
 row={
 SELECT OSPath 
 FROM glob(globs=RuntimeLogs)
 WHERE OSPath =~ UserFilter
 },
 query={
 SELECT 
 OSPath,
 parse_string_with_regex(string=Line, regex=MessageRegex) AS Parsed
 FROM parse_lines(filename=OSPath)
 WHERE Line =~ MessageRegex
 AND parse_string_with_regex(string=Line, regex=MessageRegex).Message =~ ImportantPatterns
 }
 )

 SELECT 
 OSPath,
 timestamp(string=format(format="%s/%s %s", args=[ regex_replace(source=OSPath, re=".*Log_(\\d{4})-\\d{2}-\\d{2}\\.log.*", replace="$1"), Parsed.MonthDay, Parsed.Time ])) AS Timestamp,
 regex_replace(source=Parsed.Message, re="^==&amp;gt; ", replace="File Transfer: ") AS EventDescription

 FROM parsed_messages
 WHERE Parsed.Message != ""
 AND (NOT DateAfter OR timestamp(string=format(format="%s/%s %s", args=[ regex_replace(source=OSPath, re=".*Log_(\\d{4})-\\d{2}-\\d{2}\\.log.*", replace="$1"), Parsed.MonthDay, Parsed.Time ])) &amp;gt; DateAfter)
 AND (NOT DateBefore OR timestamp(string=format(format="%s/%s %s", args=[ regex_replace(source=OSPath, re=".*Log_(\\d{4})-\\d{2}-\\d{2}\\.log.*", replace="$1"), Parsed.MonthDay, Parsed.Time ])) &amp;lt; DateBefore)
 ORDER BY Timestamp


 - name: ModuleInterfaceLogs
 description: Parses MWB module interface logs
 query: |
 -- Define regex for module interface logs
 LET ModuleLogRegex = '''^\[(?P&amp;lt;Timestamp&amp;gt;\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+)\]\s+\[p-(?P&amp;lt;PID&amp;gt;\d+)\]\s+\[t-(?P&amp;lt;TID&amp;gt;\d+)\]\s+\[(?P&amp;lt;Level&amp;gt;\w+)\]\s+(?P&amp;lt;Message&amp;gt;.*)$'''
 
 -- Find module interface log files
 LET module_files = SELECT * FROM foreach(
 row={
 SELECT OSPath 
 FROM glob(globs=ModuleLogFiles)
 WHERE OSPath =~ UserFilter
 },
 query={
 SELECT OSPath 
 FROM glob(globs=ModuleLogFiles)
 WHERE OSPath =~ UserFilter
 }
 )

 -- Parse module logs
 LET parsed_module = SELECT * FROM foreach(
 row=module_files,
 query={
 SELECT 
 OSPath,
 parse_string_with_regex(
 string=Line,
 regex=ModuleLogRegex
 ) AS Parsed
 FROM parse_lines(filename=OSPath)
 WHERE Line =~ "^\\["
 }
 )
 
 -- Extract structured data
 SELECT 
 OSPath,
 timestamp(string=Parsed.Timestamp) AS Timestamp,
 -- Parsed.PID AS PID,
 -- Parsed.TID AS TID,
 Parsed.Message AS RawMessage
 
 FROM parsed_module
 WHERE Parsed.Timestamp
 AND (NOT DateAfter OR timestamp(string=Parsed.Timestamp) &amp;gt; DateAfter)
 AND (NOT DateBefore OR timestamp(string=Parsed.Timestamp) &amp;lt; DateBefore)

 - name: Configuration
 description: Extracts MWB configuration from settings.json
 query: |
 LET config_files = SELECT OSPath
 FROM glob(globs="C:\\Users\\*\\AppData\\Local\\Microsoft\\PowerToys\\MouseWithoutBorders\\settings.json")
 WHERE OSPath =~ UserFilter
 
 LET parsed_config = SELECT 
 OSPath,
 stat(filename=OSPath).Mtime AS ModificationTime,
 parse_json(data=read_file(filename=OSPath)) AS Config
 FROM config_files
 
 SELECT 
 OSPath,
 ModificationTime,
 Config.properties.SecurityKey.value AS SecurityKey,
 Config.properties.MachineMatrixString AS ConnectedMachines,
 Config.properties.MachinePool.value AS MachinePool_ID,
 -- Extract CurrentMachineName (first machine name from MachinePool)
 if(condition=Config.properties.MachinePool.value AND Config.properties.MachinePool.value =~ "^([^:,]+):",
 then=regex_replace(source=Config.properties.MachinePool.value, re="^([^:,]+):.*", replace="$1"),
 else="Unknown") AS CurrentMachineName,
 Config.properties.TCPPort.value AS TCPPort,
 Config.properties.ShareClipboard.value AS ShareClipboard,
 Config.properties.TransferFile.value AS TransferFile,
 Config.properties.UseService.value AS UseService,
 Config.properties.ValidateRemoteMachineIP.value AS ValidateRemoteIP,
 Config.properties.SameSubnetOnly.value AS SameSubnetOnly,
 Config.properties.FirstRun.value AS FirstRun,
 -- Name2IP field (most time is empty)
 if(condition=Config.properties.Name2IP.value AND Config.properties.Name2IP.value != "",
 then=Config.properties.Name2IP.value,
 else="") AS IPAddressMapping

 FROM parsed_config

column_types:
 - name: Timestamp
 type: timestamp
 - name: ModificationTime
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.OfficeMacros.MacroRaptor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/macroraptor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/macroraptor/</guid><description>&lt;p&gt;This artifact implements OleTools MacroRaptor capability in VQL.&lt;/p&gt;
&lt;p&gt;Use as a Hunt or triage capability.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.OfficeMacros.MacroRaptor
author: Matt Green - @mgreen27
description: |
 This artifact implements OleTools MacroRaptor capability in VQL.
 
 Use as a Hunt or triage capability.

reference:
 - http://www.decalage.info/mraptor
 - https://github.com/decalage2/oletools/wiki/mraptor
 
parameters:
 - name: TargetGlob
 default: "C:\\Users\\**\\*.{doc,dot,docx,docm,dotx,dotm,docb,xls,xlt,xlm,xlsx,xlsm,xltx,xltm,xlsb,ppt,pptx,pptm,potx,potm}"
 description: The directory to search for office documents.
 - name: ShowAllDetections
 type: bool
 description: If selected return both Suspicious and non-suspicious.
 - name: UploadDocument
 type: bool
 description: "Upload documents. WARNING: Advised to not use with ShowAllDetections True as this may upload multiple versions of the same document."
 - name: AutoExecRegex
 default: "\\b(?:Auto(?:Exec|_?Open|_?Close|Exit|New)|Document(?:_?Open|_Close|_?BeforeClose|Change|_New)|NewDocument|Workbook(?:_Open|_Activate|_Close|_BeforeClose)|\\w+_(?:Painted|Painting|GotFocus|LostFocus|MouseHover|Layout|Click|Change|Resize|BeforeNavigate2|BeforeScriptExecute|DocumentComplete|DownloadBegin|DownloadComplete|FileDownload|NavigateComplete2|NavigateError|ProgressChange|PropertyChange|SetSecureLockIcon|StatusTextChange|TitleChange|MouseMove|MouseEnter|MouseLeave|OnConnecting))|Auto_Ope\\b"
 - name: WriteRegex
 default: "\\b(?:FileCopy|CopyFile|Kill|CreateTextFile|VirtualAlloc|RtlMoveMemory|URLDownloadToFileA?|AltStartupPath|WriteProcessMemory|ADODB\\.Stream|WriteText|SaveToFile|SaveAs|SaveAsRTF|FileSaveAs|MkDir|RmDir|SaveSetting|SetAttr)\\b|(?:\\bOpen\\b[^\\n]+\\b(?:Write|Append|Binary|Output|Random)\\b)"
 - name: ExecRegex
 default: "\\b(?:Shell|CreateObject|GetObject|SendKeys|RUN|CALL|MacScript|FollowHyperlink|CreateThread|ShellExecuteA?|ExecuteExcel4Macro|EXEC|REGISTER|SetTimer)\\b|(?:\\bDeclare\\b[^\\n]+\\bLib\\b)"

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

 query: |
 -- firstly match regex for macro code of interest
 LET macros = SELECT * FROM foreach(
 row={
 SELECT OSPath,Name,Size,Mtime,Atime,Ctime,Btime FROM glob(globs=TargetGlob)
 },
 query={
 SELECT 
 OSPath,Name,Size,
 dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as Timestamps,
 dict(
 AutoExec = if(condition= Code=~AutoExecRegex,
 then= True,
 else= False),
 Write = if(condition= Code=~WriteRegex,
 then= True,
 else= False),
 Execute = if(condition= Code=~ExecRegex,
 then= True,
 else= False)
 ) as MacroDetection,
 dict(Type=Type,StreamName=StreamName,ModuleName=ModuleName,Code=Code) as MacroCode
 FROM olevba(file=OSPath)
 WHERE Code =~ AutoExecRegex OR Code =~ WriteRegex OR Code=~ ExecRegex
 })
 
 -- determine if suspicious
 LET results = SELECT 
 OSPath,Name,Size,Timestamps,
 if(condition= MacroDetection.AutoExec AND ( MacroDetection.Write OR MacroDetection.Execute ),
 then = True,
 else= False ) as Suspicious,
 MacroDetection,
 MacroCode
 FROM macros
 WHERE if(condition= ShowAllDetections,
 then= True,
 else= Suspicious)
 
 -- upload hits to server
 LET upload_results = SELECT *, upload(file=OSPath) as Upload
 FROM results

 -- output rows
 SELECT *,
 hash(path=OSPath) as Hash
 FROM if(condition= UploadDocument,
 then= { SELECT * FROM upload_results},
 else= { SELECT * FROM results})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Applications.OfficeServerCache</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/officeservercache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/officeservercache/</guid><description>&lt;p&gt;Return Office Internet Server Cache Registry keys and values in
order to identify possible C2 URLs from malicious opened Office
documents.&lt;/p&gt;
&lt;p&gt;Such keys should be written by exploits such as CVE-2021-40444
(Microsoft MSHTML Remote Code Execution Vulnerability)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Applications.OfficeServerCache

description: |
 Return Office Internet Server Cache Registry keys and values in
 order to identify possible C2 URLs from malicious opened Office
 documents.

 Such keys should be written by exploits such as CVE-2021-40444
 (Microsoft MSHTML Remote Code Execution Vulnerability)

author: Eduardo Mattos - @eduardfir

reference:
 - https://twitter.com/RonnyTNL/status/1435918945349931008/photo/1

type: CLIENT

parameters:
 - name: OfficeServerCacheKey
 default: SOFTWARE\Microsoft\Office\*\Common\Internet\Server Cache\**
 - name: UserNameRegex
 default: .
 description: Filter by this UserName regex.
 - name: TargetRegex
 default: "http|https|ftp|smb|webdav|\\\\|//|:"
 description: Target server regex filter. Default should return all protocols.
 - name: TargetWhitelist
 description: Target whitelist regex.

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 query: |
 LET UserList &amp;lt;= SELECT Name as UserName, User_sid as SID FROM users()
 WHERE Name =~ UserNameRegex

 SELECT * FROM foreach(
 row={
 SELECT * FROM UserList
 },
 query={
 SELECT
 ModTime as Modified,
 UserName,
 Name,
 FullPath
 FROM glob(globs="HKEY_USERS\\" + SID + "\\" + OfficeServerCacheKey, accessor="registry")
 WHERE Name =~ TargetRegex
 AND NOT if(condition=TargetWhitelist,
 then= Name=~TargetWhitelist,
 else= False)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.AttackSimulation.AtomicRedTeam</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.attacksimulation.atomicredteam/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.attacksimulation.atomicredteam/</guid><description>&lt;p&gt;This artifact allows you to run Atomic Red Team tests on Windows
endpoints using Invoke-AtomicRedTeam. Linux and MacOS endpoints
will soon be supported.&lt;/p&gt;
&lt;p&gt;NOTE: All tests may not work out OOB. You may notice interference
or inoperability of some tests with Windows Defender/antivirus/EDR
enabled. Best-effort checks are made using the built-in
&lt;strong&gt;-GetPreReqs&lt;/strong&gt; flag. This is an initial PoC, and as such, much
testing is needed, and feedback is welcome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/redcanaryco/invoke-atomicredteam" target="_blank" &gt;https://github.com/redcanaryco/invoke-atomicredteam&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Invoke-AtomicRedTeam is a PowerShell module to execute tests as
defined in the atomics folder of Red Canary&amp;rsquo;s Atomic Red Team
project. The &amp;ldquo;atomics folder&amp;rdquo; contains a folder for each Technique
defined by the MITRE ATT&amp;amp;CK™ Framework. Inside of each of these
&amp;ldquo;T#&amp;rdquo; folders you&amp;rsquo;ll find a yaml file that defines the attack
procedures for each atomic test as well as an easier to read
markdown (md) version of the same data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Executing atomic tests may leave your system in an undesirable
state. You are responsible for understanding what a test does
before executing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure you have permission to test before you begin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It is recommended to set up a test machine for atomic test
execution that is similar to the build in your environment. Be
sure you have your collection/EDR solution in place, and that
the endpoint is checking in and active.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.AttackSimulation.AtomicRedTeam
author: Wes Lambert -- @therealwlambert
description: |
 This artifact allows you to run Atomic Red Team tests on Windows
 endpoints using Invoke-AtomicRedTeam. Linux and MacOS endpoints
 will soon be supported.

 NOTE: All tests may not work out OOB. You may notice interference
 or inoperability of some tests with Windows Defender/antivirus/EDR
 enabled. Best-effort checks are made using the built-in
 **-GetPreReqs** flag. This is an initial PoC, and as such, much
 testing is needed, and feedback is welcome.

 **Reference:**

 https://github.com/redcanaryco/invoke-atomicredteam

 **Description:**

 Invoke-AtomicRedTeam is a PowerShell module to execute tests as
 defined in the atomics folder of Red Canary's Atomic Red Team
 project. The "atomics folder" contains a folder for each Technique
 defined by the MITRE ATT&amp;amp;CK™ Framework. Inside of each of these
 "T#" folders you'll find a yaml file that defines the attack
 procedures for each atomic test as well as an easier to read
 markdown (md) version of the same data.

 - Executing atomic tests may leave your system in an undesirable
 state. You are responsible for understanding what a test does
 before executing.

 - Ensure you have permission to test before you begin.

 - It is recommended to set up a test machine for atomic test
 execution that is similar to the build in your environment. Be
 sure you have your collection/EDR solution in place, and that
 the endpoint is checking in and active.

type: CLIENT

column_types:
 - name: Technique
 type: safe_url

parameters:
 - name: InstallART
 description: Install AtomicRedTeam Execution Framework (Choose this for the first run, then de-select thereafter)
 default: Y
 type: bool

 - name: ExecutionLogFile
 description: Path to log file (CSV) for executions by ART tests
 default: C:\Windows\Temp\ARTExec.csv

 - name: RemoveExecLog
 description: Remove execution log before running artifact (in the event we don't want to intertwine results from previous tests)
 default: Y
 type: bool

 - name: Cleanup
 description: Clean up execution artifacts
 default: Y
 type: bool

 - name: RunAll
 description: NOT RECOMMENDED...USE WITH CAUTION - Run all ART tests
 default: N
 type: bool

 - name: T1558.004 - 1
 description: AS-REP Roasting - Rubeus asreproast
 type: bool

 - name: T1056.004 - 1
 description: Credential API Hooking - Hook PowerShell TLS Encrypt/Decrypt Messages
 type: bool

 - name: T1552.001 - 3
 description: Credentials In Files - Extracting passwords with findstr
 type: bool

 - name: T1552.001 - 4
 description: Credentials In Files - Access unattend.xml
 type: bool

 - name: T1555 - 1
 description: Credentials from Password Stores - Extract Windows Credential Manager via VBA
 type: bool

 - name: T1555 - 2
 description: Credentials from Password Stores - Dump credentials from Windows Credential Manager With PowerShell [windows Credentials]
 type: bool

 - name: T1555 - 3
 description: Credentials from Password Stores - Dump credentials from Windows Credential Manager With PowerShell [web Credentials]
 type: bool

 - name: T1555 - 4
 description: Credentials from Password Stores - Enumerate credentials from Windows Credential Manager using vaultcmd.exe [Windows Credentials]
 type: bool

 - name: T1555 - 5
 description: Credentials from Password Stores - Enumerate credentials from Windows Credential Manager using vaultcmd.exe [Web Credentials]
 type: bool

 - name: T1555.003 - 1
 description: Credentials from Web Browsers - Run Chrome-password Collector
 type: bool

 - name: T1555.003 - 3
 description: Credentials from Web Browsers - LaZagne - Credentials from Browser
 type: bool

 - name: T1555.003 - 4
 description: Credentials from Web Browsers - Simulating access to Chrome Login Data
 type: bool

 - name: T1552.002 - 1
 description: Credentials in Registry - Enumeration for Credentials in Registry
 type: bool

 - name: T1552.002 - 2
 description: Credentials in Registry - Enumeration for PuTTY Credentials in Registry
 type: bool

 - name: T1003.006 - 1
 description: DCSync - DCSync (Active Directory)
 type: bool

 - name: T1187 - 1
 description: Forced Authentication - PetitPotam
 type: bool

 - name: T1056.002 - 2
 description: GUI Input Capture - PowerShell - Prompt User for Password
 type: bool

 - name: T1558.001 - 1
 description: Golden Ticket - Crafting Active Directory golden tickets with mimikatz
 type: bool

 - name: T1552.006 - 1
 description: Group Policy Preferences - GPP Passwords (findstr)
 type: bool

 - name: T1552.006 - 2
 description: Group Policy Preferences - GPP Passwords (Get-GPPPassword)
 type: bool

 - name: T1558.003 - 1
 description: Kerberoasting - Request for service tickets
 type: bool

 - name: T1558.003 - 2
 description: Kerberoasting - Rubeus kerberoast
 type: bool

 - name: T1558.003 - 3
 description: Kerberoasting - Extract all accounts in use as SPN using setspn
 type: bool

 - name: T1558.003 - 4
 description: Kerberoasting - Request A Single Ticket via PowerShell
 type: bool

 - name: T1558.003 - 5
 description: Kerberoasting - Request All Tickets via PowerShell
 type: bool

 - name: T1056.001 - 1
 description: Keylogging - Input Capture
 type: bool

 - name: T1003.004 - 1
 description: LSA Secrets - Dumping LSA Secrets
 type: bool

 - name: T1003.001 - 1
 description: LSASS Memory - Windows Credential Editor
 type: bool

 - name: T1003.001 - 2
 description: LSASS Memory - Dump LSASS.exe Memory using ProcDump
 type: bool

 - name: T1003.001 - 3
 description: LSASS Memory - Dump LSASS.exe Memory using comsvcs.dll
 type: bool

 - name: T1003.001 - 4
 description: LSASS Memory - Dump LSASS.exe Memory using direct system calls and API unhooking
 type: bool

 - name: T1003.001 - 5
 description: LSASS Memory - Dump LSASS.exe Memory using Windows Task Manager
 type: bool

 - name: T1003.001 - 6
 description: LSASS Memory - Offline Credential Theft With Mimikatz
 type: bool

 - name: T1003.001 - 7
 description: LSASS Memory - LSASS read with pypykatz
 type: bool

 - name: T1003.001 - 8
 description: LSASS Memory - Dump LSASS.exe Memory using Out-Minidump.ps1
 type: bool

 - name: T1003.001 - 9
 description: LSASS Memory - Create Mini Dump of LSASS.exe using ProcDump
 type: bool

 - name: T1003.001 - 10
 description: LSASS Memory - Powershell Mimikatz
 type: bool

 - name: T1003.001 - 11
 description: LSASS Memory - Dump LSASS with .Net 5 createdump.exe
 type: bool

 - name: T1003.001 - 12
 description: LSASS Memory - Dump LSASS.exe using imported Microsoft DLLs
 type: bool

 - name: T1003.003 - 1
 description: NTDS - Create Volume Shadow Copy with vssadmin
 type: bool

 - name: T1003.003 - 2
 description: NTDS - Copy NTDS.dit from Volume Shadow Copy
 type: bool

 - name: T1003.003 - 3
 description: NTDS - Dump Active Directory Database with NTDSUtil
 type: bool

 - name: T1003.003 - 4
 description: NTDS - Create Volume Shadow Copy with WMI
 type: bool

 - name: T1003.003 - 5
 description: NTDS - Create Volume Shadow Copy remotely with WMI
 type: bool

 - name: T1003.003 - 6
 description: NTDS - Create Volume Shadow Copy with Powershell
 type: bool

 - name: T1003.003 - 7
 description: NTDS - Create Symlink to Volume Shadow Copy
 type: bool

 - name: T1040 - 3
 description: Network Sniffing - Packet Capture Windows Command Prompt
 type: bool

 - name: T1040 - 4
 description: Network Sniffing - Windows Internal Packet Capture
 type: bool

 - name: T1003 - 1
 description: OS Credential Dumping - Gsecdump
 type: bool

 - name: T1003 - 2
 description: OS Credential Dumping - Credential Dumping with NPPSpy
 type: bool

 - name: T1003 - 3
 description: OS Credential Dumping - Dump svchost.exe to gather RDP credentials
 type: bool

 - name: T1110.002 - 1
 description: Password Cracking - Password Cracking with Hashcat
 type: bool

 - name: T1556.002 - 1
 description: Password Filter DLL - Install and Register Password Filter DLL
 type: bool

 - name: T1110.001 - 1
 description: Password Guessing - Brute Force Credentials of all Active Directory domain users via SMB
 type: bool

 - name: T1110.001 - 2
 description: Password Guessing - Brute Force Credentials of single Active Directory domain user via LDAP against domain controller (NTLM or Kerberos)
 type: bool

 - name: T1110.003 - 1
 description: Password Spraying - Password Spray all Domain Users
 type: bool

 - name: T1110.003 - 2
 description: Password Spraying - Password Spray (DomainPasswordSpray)
 type: bool

 - name: T1110.003 - 3
 description: Password Spraying - Password spray all Active Directory domain users with a single password via LDAP against domain controller (NTLM or Kerberos)
 type: bool

 - name: T1552.004 - 1
 description: Private Keys - Private Keys
 type: bool

 - name: T1552.004 - 6
 description: Private Keys - ADFS token signing and encryption certificates theft - Local
 type: bool

 - name: T1552.004 - 7
 description: Private Keys - ADFS token signing and encryption certificates theft - Remote
 type: bool

 - name: T1003.002 - 1
 description: Security Account Manager - Registry dump of SAM, creds, and secrets
 type: bool

 - name: T1003.002 - 2
 description: Security Account Manager - Registry parse with pypykatz
 type: bool

 - name: T1003.002 - 3
 description: Security Account Manager - esentutl.exe SAM copy
 type: bool

 - name: T1003.002 - 4
 description: Security Account Manager - PowerDump Registry dump of SAM for hashes and usernames
 type: bool

 - name: T1003.002 - 5
 description: Security Account Manager - dump volume shadow copy hives with certutil
 type: bool

 - name: T1003.002 - 6
 description: Security Account Manager - dump volume shadow copy hives with System.IO.File
 type: bool

 - name: T1560 - 1
 description: Archive Collected Data - Compress Data for Exfiltration With PowerShell
 type: bool

 - name: T1560.001 - 1
 description: Archive via Utility - Compress Data for Exfiltration With Rar
 type: bool

 - name: T1560.001 - 2
 description: Archive via Utility - Compress Data and lock with password for Exfiltration with winrar
 type: bool

 - name: T1560.001 - 3
 description: Archive via Utility - Compress Data and lock with password for Exfiltration with winzip
 type: bool

 - name: T1560.001 - 4
 description: Archive via Utility - Compress Data and lock with password for Exfiltration with 7zip
 type: bool

 - name: T1123 - 1
 description: Audio Capture - using device audio capture commandlet
 type: bool

 - name: T1119 - 1
 description: Automated Collection - Automated Collection Command Prompt
 type: bool

 - name: T1119 - 2
 description: Automated Collection - Automated Collection PowerShell
 type: bool

 - name: T1119 - 3
 description: Automated Collection - Recon information for export with PowerShell
 type: bool

 - name: T1119 - 4
 description: Automated Collection - Recon information for export with Command Prompt
 type: bool

 - name: T1115 - 1
 description: Clipboard Data - Utilize Clipboard to store or execute commands from
 type: bool

 - name: T1115 - 2
 description: Clipboard Data - Execute Commands from Clipboard using PowerShell
 type: bool

 - name: T1115 - 4
 description: Clipboard Data - Collect Clipboard Data via VBA
 type: bool

 - name: T1056.004 - 1
 description: Credential API Hooking - Hook PowerShell TLS Encrypt/Decrypt Messages
 type: bool

 - name: T1056.002 - 2
 description: GUI Input Capture - PowerShell - Prompt User for Password
 type: bool

 - name: T1056.001 - 1
 description: Keylogging - Input Capture
 type: bool

 - name: T1074.001 - 1
 description: Local Data Staging - Stage data from Discovery.bat
 type: bool

 - name: T1074.001 - 3
 description: Local Data Staging - Zip a Folder with PowerShell for Staging in Temp
 type: bool

 - name: T1114.001 - 1
 description: Local Email Collection - Email Collection with PowerShell Get-Inbox
 type: bool

 - name: T1113 - 5
 description: Screen Capture - Windows Screencapture
 type: bool

 - name: T1113 - 6
 description: Screen Capture - Windows Screen Capture (CopyFromScreen)
 type: bool

 - name: T1546.008 - 1
 description: Accessibility Features - Attaches Command Prompt as a Debugger to a List of Target Processes
 type: bool

 - name: T1546.008 - 2
 description: Accessibility Features - Replace binary of sticky keys
 type: bool

 - name: T1546.010 - 1
 description: AppInit DLLs - Install AppInit Shim
 type: bool

 - name: T1546.011 - 1
 description: Application Shimming - Application Shim Installation
 type: bool

 - name: T1546.011 - 2
 description: Application Shimming - New shim database files created in the default shim database directory
 type: bool

 - name: T1546.011 - 3
 description: Application Shimming - Registry key creation and/or modification events for SDB
 type: bool

 - name: T1055.004 - 1
 description: Asynchronous Procedure Call - Process Injection via C#
 type: bool

 - name: T1053.002 - 1
 description: At (Windows) - At.exe Scheduled task
 type: bool

 - name: T1548.002 - 1
 description: Bypass User Account Control - Bypass UAC using Event Viewer (cmd)
 type: bool

 - name: T1548.002 - 2
 description: Bypass User Account Control - Bypass UAC using Event Viewer (PowerShell)
 type: bool

 - name: T1548.002 - 3
 description: Bypass User Account Control - Bypass UAC using Fodhelper
 type: bool

 - name: T1548.002 - 4
 description: Bypass User Account Control - Bypass UAC using Fodhelper - PowerShell
 type: bool

 - name: T1548.002 - 5
 description: Bypass User Account Control - Bypass UAC using ComputerDefaults (PowerShell)
 type: bool

 - name: T1548.002 - 6
 description: Bypass User Account Control - Bypass UAC by Mocking Trusted Directories
 type: bool

 - name: T1548.002 - 7
 description: Bypass User Account Control - Bypass UAC using sdclt DelegateExecute
 type: bool

 - name: T1548.002 - 8
 description: Bypass User Account Control - Disable UAC using reg.exe
 type: bool

 - name: T1548.002 - 9
 description: Bypass User Account Control - Bypass UAC using SilentCleanup task
 type: bool

 - name: T1548.002 - 10
 description: Bypass User Account Control - UACME Bypass Method 23
 type: bool

 - name: T1548.002 - 11
 description: Bypass User Account Control - UACME Bypass Method 31
 type: bool

 - name: T1548.002 - 12
 description: Bypass User Account Control - UACME Bypass Method 33
 type: bool

 - name: T1548.002 - 13
 description: Bypass User Account Control - UACME Bypass Method 34
 type: bool

 - name: T1548.002 - 14
 description: Bypass User Account Control - UACME Bypass Method 39
 type: bool

 - name: T1548.002 - 15
 description: Bypass User Account Control - UACME Bypass Method 56
 type: bool

 - name: T1548.002 - 16
 description: Bypass User Account Control - UACME Bypass Method 59
 type: bool

 - name: T1548.002 - 17
 description: Bypass User Account Control - UACME Bypass Method 61
 type: bool

 - name: T1574.012 - 1
 description: COR_PROFILER - User scope COR_PROFILER
 type: bool

 - name: T1574.012 - 2
 description: COR_PROFILER - System Scope COR_PROFILER
 type: bool

 - name: T1574.012 - 3
 description: COR_PROFILER - Registry-free process scope COR_PROFILER
 type: bool

 - name: T1546.001 - 1
 description: Change Default File Association - Change Default File Association
 type: bool

 - name: T1134.002 - 1
 description: Create Process with Token - Access Token Manipulation
 type: bool

 - name: T1574.001 - 1
 description: DLL Search Order Hijacking - DLL Search Order Hijacking - amsi.dll
 type: bool

 - name: T1574.002 - 1
 description: DLL Side-Loading - DLL Side-Loading using the Notepad++ GUP.exe binary
 type: bool

 - name: T1078.001 - 1
 description: Default Accounts - Enable Guest account with RDP capability and admin privileges
 type: bool

 - name: T1078.001 - 2
 description: Default Accounts - Activate Guest Account
 type: bool

 - name: T1055.001 - 1
 description: Dynamic-link Library Injection - Process Injection via mavinject.exe
 type: bool

 - name: T1546.012 - 1
 description: Image File Execution Options Injection - IFEO Add Debugger
 type: bool

 - name: T1546.012 - 2
 description: Image File Execution Options Injection - IFEO Global Flags
 type: bool

 - name: T1078.003 - 1
 description: Local Accounts - Create local account with admin privileges
 type: bool

 - name: T1037.001 - 1
 description: Logon Script (Windows) - Logon Scripts
 type: bool

 - name: T1546.007 - 1
 description: Netsh Helper DLL - Netsh Helper DLL Registration
 type: bool

 - name: T1134.004 - 1
 description: Parent PID Spoofing - Parent PID Spoofing using PowerShell
 type: bool

 - name: T1134.004 - 2
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from Current Process
 type: bool

 - name: T1134.004 - 3
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from Specified Process
 type: bool

 - name: T1134.004 - 4
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from svchost.exe
 type: bool

 - name: T1134.004 - 5
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from New Process
 type: bool

 - name: T1574.009 - 1
 description: Path Interception by Unquoted Path - Execution of program.exe as service with unquoted service path
 type: bool

 - name: T1547.010 - 1
 description: Port Monitors - Add Port Monitor persistence in Registry
 type: bool

 - name: T1546.013 - 1
 description: PowerShell Profile - Append malicious start-process cmdlet
 type: bool

 - name: T1055.012 - 1
 description: Process Hollowing - Process Hollowing using PowerShell
 type: bool

 - name: T1055.012 - 2
 description: Process Hollowing - RunPE via VBA
 type: bool

 - name: T1055 - 1
 description: Process Injection - Shellcode execution via VBA
 type: bool

 - name: T1055 - 2
 description: Process Injection - Remote Process Injection in LSASS via mimikatz
 type: bool

 - name: T1547.001 - 1
 description: Registry Run Keys / Startup Folder - Reg Key Run
 type: bool

 - name: T1547.001 - 2
 description: Registry Run Keys / Startup Folder - Reg Key RunOnce
 type: bool

 - name: T1547.001 - 3
 description: Registry Run Keys / Startup Folder - PowerShell Registry RunOnce
 type: bool

 - name: T1547.001 - 4
 description: Registry Run Keys / Startup Folder - Suspicious vbs file run from startup Folder
 type: bool

 - name: T1547.001 - 5
 description: Registry Run Keys / Startup Folder - Suspicious jse file run from startup Folder
 type: bool

 - name: T1547.001 - 6
 description: Registry Run Keys / Startup Folder - Suspicious bat file run from startup Folder
 type: bool

 - name: T1547.001 - 7
 description: Registry Run Keys / Startup Folder - Add Executable Shortcut Link to User Startup Folder
 type: bool

 - name: T1053.005 - 1
 description: Scheduled Task - Scheduled Task Startup Script
 type: bool

 - name: T1053.005 - 2
 description: Scheduled Task - Scheduled task Local
 type: bool

 - name: T1053.005 - 3
 description: Scheduled Task - Scheduled task Remote
 type: bool

 - name: T1053.005 - 4
 description: Scheduled Task - Powershell Cmdlet Scheduled Task
 type: bool

 - name: T1053.005 - 5
 description: Scheduled Task - Task Scheduler via VBA
 type: bool

 - name: T1053.005 - 6
 description: Scheduled Task - WMI Invoke-CimMethod Scheduled Task
 type: bool

 - name: T1546.002 - 1
 description: Screensaver - Set Arbitrary Binary as Screensaver
 type: bool

 - name: T1547.005 - 1
 description: Security Support Provider - Modify SSP configuration in registry
 type: bool

 - name: T1574.011 - 1
 description: Services Registry Permissions Weakness - Service Registry Permissions Weakness
 type: bool

 - name: T1574.011 - 2
 description: Services Registry Permissions Weakness - Service ImagePath Change with reg.exe
 type: bool

 - name: T1547.009 - 1
 description: Shortcut Modification - Shortcut Modification
 type: bool

 - name: T1547.009 - 2
 description: Shortcut Modification - Create shortcut to cmd in startup folders
 type: bool

 - name: T1134.001 - 1
 description: Token Impersonation/Theft - Named pipe client impersonation
 type: bool

 - name: T1134.001 - 2
 description: Token Impersonation/Theft - `SeDebugPrivilege` token duplication
 type: bool

 - name: T1546.003 - 1
 description: Windows Management Instrumentation Event Subscription - Persistence via WMI Event Subscription
 type: bool

 - name: T1543.003 - 1
 description: Windows Service - Modify Fax service to run PowerShell
 type: bool

 - name: T1543.003 - 2
 description: Windows Service - Service Installation CMD
 type: bool

 - name: T1543.003 - 3
 description: Windows Service - Service Installation PowerShell
 type: bool

 - name: T1547.004 - 1
 description: Winlogon Helper DLL - Winlogon Shell Key Persistence - PowerShell
 type: bool

 - name: T1547.004 - 2
 description: Winlogon Helper DLL - Winlogon Userinit Key Persistence - PowerShell
 type: bool

 - name: T1547.004 - 3
 description: Winlogon Helper DLL - Winlogon Notify Key Logon Persistence - PowerShell
 type: bool

 - name: T1055.004 - 1
 description: Asynchronous Procedure Call - Process Injection via C#
 type: bool

 - name: T1197 - 1
 description: BITS Jobs - Bitsadmin Download (cmd)
 type: bool

 - name: T1197 - 2
 description: BITS Jobs - Bitsadmin Download (PowerShell)
 type: bool

 - name: T1197 - 3
 description: BITS Jobs - Persist, Download, &amp;amp; Execute
 type: bool

 - name: T1197 - 4
 description: BITS Jobs - Bits download using desktopimgdownldr.exe (cmd)
 type: bool

 - name: T1548.002 - 1
 description: Bypass User Account Control - Bypass UAC using Event Viewer (cmd)
 type: bool

 - name: T1548.002 - 2
 description: Bypass User Account Control - Bypass UAC using Event Viewer (PowerShell)
 type: bool

 - name: T1548.002 - 3
 description: Bypass User Account Control - Bypass UAC using Fodhelper
 type: bool

 - name: T1548.002 - 4
 description: Bypass User Account Control - Bypass UAC using Fodhelper - PowerShell
 type: bool

 - name: T1548.002 - 5
 description: Bypass User Account Control - Bypass UAC using ComputerDefaults (PowerShell)
 type: bool

 - name: T1548.002 - 6
 description: Bypass User Account Control - Bypass UAC by Mocking Trusted Directories
 type: bool

 - name: T1548.002 - 7
 description: Bypass User Account Control - Bypass UAC using sdclt DelegateExecute
 type: bool

 - name: T1548.002 - 8
 description: Bypass User Account Control - Disable UAC using reg.exe
 type: bool

 - name: T1548.002 - 9
 description: Bypass User Account Control - Bypass UAC using SilentCleanup task
 type: bool

 - name: T1548.002 - 10
 description: Bypass User Account Control - UACME Bypass Method 23
 type: bool

 - name: T1548.002 - 11
 description: Bypass User Account Control - UACME Bypass Method 31
 type: bool

 - name: T1548.002 - 12
 description: Bypass User Account Control - UACME Bypass Method 33
 type: bool

 - name: T1548.002 - 13
 description: Bypass User Account Control - UACME Bypass Method 34
 type: bool

 - name: T1548.002 - 14
 description: Bypass User Account Control - UACME Bypass Method 39
 type: bool

 - name: T1548.002 - 15
 description: Bypass User Account Control - UACME Bypass Method 56
 type: bool

 - name: T1548.002 - 16
 description: Bypass User Account Control - UACME Bypass Method 59
 type: bool

 - name: T1548.002 - 17
 description: Bypass User Account Control - UACME Bypass Method 61
 type: bool

 - name: T1218.003 - 1
 description: CMSTP - CMSTP Executing Remote Scriptlet
 type: bool

 - name: T1218.003 - 2
 description: CMSTP - CMSTP Executing UAC Bypass
 type: bool

 - name: T1574.012 - 1
 description: COR_PROFILER - User scope COR_PROFILER
 type: bool

 - name: T1574.012 - 2
 description: COR_PROFILER - System Scope COR_PROFILER
 type: bool

 - name: T1574.012 - 3
 description: COR_PROFILER - Registry-free process scope COR_PROFILER
 type: bool

 - name: T1070.003 - 10
 description: Clear Command History - Prevent Powershell History Logging
 type: bool

 - name: T1070.003 - 11
 description: Clear Command History - Clear Powershell History by Deleting History File
 type: bool

 - name: T1070.001 - 1
 description: Clear Windows Event Logs - Clear Logs
 type: bool

 - name: T1070.001 - 2
 description: Clear Windows Event Logs - Delete System Logs Using Clear-EventLog
 type: bool

 - name: T1070.001 - 3
 description: Clear Windows Event Logs - Clear Event Logs via VBA
 type: bool

 - name: T1027.004 - 1
 description: Compile After Delivery - Compile After Delivery using csc.exe
 type: bool

 - name: T1027.004 - 2
 description: Compile After Delivery - Dynamic C# Compile
 type: bool

 - name: T1218.001 - 1
 description: Compiled HTML File - Compiled HTML Help Local Payload
 type: bool

 - name: T1218.001 - 2
 description: Compiled HTML File - Compiled HTML Help Remote Payload
 type: bool

 - name: T1218.001 - 3
 description: Compiled HTML File - Invoke CHM with default Shortcut Command Execution
 type: bool

 - name: T1218.001 - 4
 description: Compiled HTML File - Invoke CHM with InfoTech Storage Protocol Handler
 type: bool

 - name: T1218.001 - 5
 description: Compiled HTML File - Invoke CHM Simulate Double click
 type: bool

 - name: T1218.001 - 6
 description: Compiled HTML File - Invoke CHM with Script Engine and Help Topic
 type: bool

 - name: T1218.001 - 7
 description: Compiled HTML File - Invoke CHM Shortcut Command with ITS and Help Topic
 type: bool

 - name: T1218.002 - 1
 description: Control Panel - Control Panel Items
 type: bool

 - name: T1134.002 - 1
 description: Create Process with Token - Access Token Manipulation
 type: bool

 - name: T1574.001 - 1
 description: DLL Search Order Hijacking - DLL Search Order Hijacking - amsi.dll
 type: bool

 - name: T1574.002 - 1
 description: DLL Side-Loading - DLL Side-Loading using the Notepad++ GUP.exe binary
 type: bool

 - name: T1078.001 - 1
 description: Default Accounts - Enable Guest account with RDP capability and admin privileges
 type: bool

 - name: T1078.001 - 2
 description: Default Accounts - Activate Guest Account
 type: bool

 - name: T1140 - 1
 description: Deobfuscate/Decode Files or Information - Deobfuscate/Decode Files Or Information
 type: bool

 - name: T1140 - 2
 description: Deobfuscate/Decode Files or Information - Certutil Rename and Decode
 type: bool

 - name: T1006 - 1
 description: Direct Volume Access - Read volume boot sector via DOS device path (PowerShell)
 type: bool

 - name: T1562.002 - 1
 description: Disable Windows Event Logging - Disable Windows IIS HTTP Logging
 type: bool

 - name: T1562.002 - 2
 description: Disable Windows Event Logging - Kill Event Log Service Threads
 type: bool

 - name: T1562.002 - 3
 description: Disable Windows Event Logging - Impair Windows Audit Log Policy
 type: bool

 - name: T1562.002 - 4
 description: Disable Windows Event Logging - Clear Windows Audit Policy Config
 type: bool

 - name: T1562.002 - 5
 description: Disable Windows Event Logging - Disable Event Logging with wevtutil
 type: bool

 - name: T1562.004 - 1
 description: Disable or Modify System Firewall - Disable Microsoft Defender Firewall
 type: bool

 - name: T1562.004 - 2
 description: Disable or Modify System Firewall - Disable Microsoft Defender Firewall via Registry
 type: bool

 - name: T1562.004 - 3
 description: Disable or Modify System Firewall - Allow SMB and RDP on Microsoft Defender Firewall
 type: bool

 - name: T1562.004 - 4
 description: Disable or Modify System Firewall - Opening ports for proxy - HARDRAIN
 type: bool

 - name: T1562.004 - 5
 description: Disable or Modify System Firewall - Open a local port through Windows Firewall to any profile
 type: bool

 - name: T1562.004 - 6
 description: Disable or Modify System Firewall - Allow Executable Through Firewall Located in Non-Standard Location
 type: bool

 - name: T1562.001 - 10
 description: Disable or Modify Tools - Unload Sysmon Filter Driver
 type: bool

 - name: T1562.001 - 11
 description: Disable or Modify Tools - Uninstall Sysmon
 type: bool

 - name: T1562.001 - 12
 description: Disable or Modify Tools - AMSI Bypass - AMSI InitFailed
 type: bool

 - name: T1562.001 - 13
 description: Disable or Modify Tools - AMSI Bypass - Remove AMSI Provider Reg Key
 type: bool

 - name: T1562.001 - 14
 description: Disable or Modify Tools - Disable Arbitrary Security Windows Service
 type: bool

 - name: T1562.001 - 15
 description: Disable or Modify Tools - Tamper with Windows Defender ATP PowerShell
 type: bool

 - name: T1562.001 - 16
 description: Disable or Modify Tools - Tamper with Windows Defender Command Prompt
 type: bool

 - name: T1562.001 - 17
 description: Disable or Modify Tools - Tamper with Windows Defender Registry
 type: bool

 - name: T1562.001 - 18
 description: Disable or Modify Tools - Disable Microsoft Office Security Features
 type: bool

 - name: T1562.001 - 19
 description: Disable or Modify Tools - Remove Windows Defender Definition Files
 type: bool

 - name: T1562.001 - 20
 description: Disable or Modify Tools - Stop and Remove Arbitrary Security Windows Service
 type: bool

 - name: T1562.001 - 21
 description: Disable or Modify Tools - Uninstall Crowdstrike Falcon on Windows
 type: bool

 - name: T1562.001 - 22
 description: Disable or Modify Tools - Tamper with Windows Defender Evade Scanning -Folder
 type: bool

 - name: T1562.001 - 23
 description: Disable or Modify Tools - Tamper with Windows Defender Evade Scanning -Extension
 type: bool

 - name: T1562.001 - 24
 description: Disable or Modify Tools - Tamper with Windows Defender Evade Scanning -Process
 type: bool

 - name: T1055.001 - 1
 description: Dynamic-link Library Injection - Process Injection via mavinject.exe
 type: bool

 - name: T1070.004 - 4
 description: File Deletion - Delete a single file - Windows cmd
 type: bool

 - name: T1070.004 - 5
 description: File Deletion - Delete an entire folder - Windows cmd
 type: bool

 - name: T1070.004 - 6
 description: File Deletion - Delete a single file - Windows PowerShell
 type: bool

 - name: T1070.004 - 7
 description: File Deletion - Delete an entire folder - Windows PowerShell
 type: bool

 - name: T1070.004 - 9
 description: File Deletion - Delete Prefetch File
 type: bool

 - name: T1070.004 - 10
 description: File Deletion - Delete TeamViewer Log Files
 type: bool

 - name: T1564.001 - 3
 description: Hidden Files and Directories - Create Windows System File with Attrib
 type: bool

 - name: T1564.001 - 4
 description: Hidden Files and Directories - Create Windows Hidden File with Attrib
 type: bool

 - name: T1564.003 - 1
 description: Hidden Window - Hidden Window
 type: bool

 - name: T1564 - 1
 description: Hide Artifacts - Extract binary files via VBA
 type: bool

 - name: T1564 - 2
 description: Hide Artifacts - Create a Hidden User Called "$"
 type: bool

 - name: T1564 - 3
 description: Hide Artifacts - Create an "Administrator " user (with a space on the end)
 type: bool

 - name: T1070 - 1
 description: Indicator Removal on Host - Indicator Removal using FSUtil
 type: bool

 - name: T1202 - 1
 description: Indirect Command Execution - Indirect Command Execution - pcalua.exe
 type: bool

 - name: T1202 - 2
 description: Indirect Command Execution - Indirect Command Execution - forfiles.exe
 type: bool

 - name: T1202 - 3
 description: Indirect Command Execution - Indirect Command Execution - conhost.exe
 type: bool

 - name: T1553.004 - 4
 description: Install Root Certificate - Install root CA on Windows
 type: bool

 - name: T1553.004 - 5
 description: Install Root Certificate - Install root CA on Windows with certutil
 type: bool

 - name: T1218.004 - 1
 description: InstallUtil - CheckIfInstallable method call
 type: bool

 - name: T1218.004 - 2
 description: InstallUtil - InstallHelper method call
 type: bool

 - name: T1218.004 - 3
 description: InstallUtil - InstallUtil class constructor method call
 type: bool

 - name: T1218.004 - 4
 description: InstallUtil - InstallUtil Install method call
 type: bool

 - name: T1218.004 - 5
 description: InstallUtil - InstallUtil Uninstall method call - /U variant
 type: bool

 - name: T1218.004 - 6
 description: InstallUtil - InstallUtil Uninstall method call - '/installtype=notransaction /action=uninstall' variant
 type: bool

 - name: T1218.004 - 7
 description: InstallUtil - InstallUtil HelpText method call
 type: bool

 - name: T1218.004 - 8
 description: InstallUtil - InstallUtil evasive invocation
 type: bool

 - name: T1078.003 - 1
 description: Local Accounts - Create local account with admin privileges
 type: bool

 - name: T1127.001 - 1
 description: MSBuild - MSBuild Bypass Using Inline Tasks (C#)
 type: bool

 - name: T1127.001 - 2
 description: MSBuild - MSBuild Bypass Using Inline Tasks (VB)
 type: bool

 - name: T1553.005 - 1
 description: Mark-of-the-Web Bypass - Mount ISO image
 type: bool

 - name: T1553.005 - 2
 description: Mark-of-the-Web Bypass - Mount an ISO image and run executable from the ISO
 type: bool

 - name: T1553.005 - 3
 description: Mark-of-the-Web Bypass - Remove the Zone.Identifier alternate data stream
 type: bool

 - name: T1036.004 - 1
 description: Masquerade Task or Service - Creating W32Time similar named service using schtasks
 type: bool

 - name: T1036.004 - 2
 description: Masquerade Task or Service - Creating W32Time similar named service using sc
 type: bool

 - name: T1036 - 1
 description: Masquerading - System File Copied to Unusual Location
 type: bool

 - name: T1112 - 1
 description: Modify Registry - Modify Registry of Current User Profile - cmd
 type: bool

 - name: T1112 - 2
 description: Modify Registry - Modify Registry of Local Machine - cmd
 type: bool

 - name: T1112 - 3
 description: Modify Registry - Modify registry to store logon credentials
 type: bool

 - name: T1112 - 4
 description: Modify Registry - Add domain to Trusted sites Zone
 type: bool

 - name: T1112 - 5
 description: Modify Registry - Javascript in registry
 type: bool

 - name: T1112 - 6
 description: Modify Registry - Change Powershell Execution Policy to Bypass
 type: bool

 - name: T1218.005 - 1
 description: Mshta - Mshta executes JavaScript Scheme Fetch Remote Payload With GetObject
 type: bool

 - name: T1218.005 - 2
 description: Mshta - Mshta executes VBScript to execute malicious command
 type: bool

 - name: T1218.005 - 3
 description: Mshta - Mshta Executes Remote HTML Application (HTA)
 type: bool

 - name: T1218.005 - 4
 description: Mshta - Invoke HTML Application - Jscript Engine over Local UNC Simulating Lateral Movement
 type: bool

 - name: T1218.005 - 5
 description: Mshta - Invoke HTML Application - Jscript Engine Simulating Double Click
 type: bool

 - name: T1218.005 - 6
 description: Mshta - Invoke HTML Application - Direct download from URI
 type: bool

 - name: T1218.005 - 7
 description: Mshta - Invoke HTML Application - JScript Engine with Rundll32 and Inline Protocol Handler
 type: bool

 - name: T1218.005 - 8
 description: Mshta - Invoke HTML Application - JScript Engine with Inline Protocol Handler
 type: bool

 - name: T1218.005 - 9
 description: Mshta - Invoke HTML Application - Simulate Lateral Movement over UNC Path
 type: bool

 - name: T1218.005 - 10
 description: Mshta - Mshta used to Execute PowerShell
 type: bool

 - name: T1218.007 - 1
 description: Msiexec - Msiexec.exe - Execute Local MSI file
 type: bool

 - name: T1218.007 - 2
 description: Msiexec - Msiexec.exe - Execute Remote MSI file
 type: bool

 - name: T1218.007 - 3
 description: Msiexec - Msiexec.exe - Execute Arbitrary DLL
 type: bool

 - name: T1564.004 - 1
 description: NTFS File Attributes - Alternate Data Streams (ADS)
 type: bool

 - name: T1564.004 - 2
 description: NTFS File Attributes - Store file in Alternate Data Stream (ADS)
 type: bool

 - name: T1564.004 - 3
 description: NTFS File Attributes - Create ADS command prompt
 type: bool

 - name: T1564.004 - 4
 description: NTFS File Attributes - Create ADS PowerShell
 type: bool

 - name: T1070.005 - 1
 description: Network Share Connection Removal - Add Network Share
 type: bool

 - name: T1070.005 - 2
 description: Network Share Connection Removal - Remove Network Share
 type: bool

 - name: T1070.005 - 3
 description: Network Share Connection Removal - Remove Network Share PowerShell
 type: bool

 - name: T1027 - 2
 description: Obfuscated Files or Information - Execute base64-encoded PowerShell
 type: bool

 - name: T1027 - 3
 description: Obfuscated Files or Information - Execute base64-encoded PowerShell from Windows Registry
 type: bool

 - name: T1027 - 4
 description: Obfuscated Files or Information - Execution from Compressed File
 type: bool

 - name: T1027 - 5
 description: Obfuscated Files or Information - DLP Evasion via Sensitive Data in VBA Macro over email
 type: bool

 - name: T1027 - 6
 description: Obfuscated Files or Information - DLP Evasion via Sensitive Data in VBA Macro over HTTP
 type: bool

 - name: T1027 - 7
 description: Obfuscated Files or Information - Obfuscated Command in PowerShell
 type: bool

 - name: T1027 - 8
 description: Obfuscated Files or Information - Obfuscated Command Line using special Unicode characters
 type: bool

 - name: T1218.008 - 1
 description: Odbcconf - Odbcconf.exe - Execute Arbitrary DLL
 type: bool

 - name: T1134.004 - 1
 description: Parent PID Spoofing - Parent PID Spoofing using PowerShell
 type: bool

 - name: T1134.004 - 2
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from Current Process
 type: bool

 - name: T1134.004 - 3
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from Specified Process
 type: bool

 - name: T1134.004 - 4
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from svchost.exe
 type: bool

 - name: T1134.004 - 5
 description: Parent PID Spoofing - Parent PID Spoofing - Spawn from New Process
 type: bool

 - name: T1550.002 - 1
 description: Pass the Hash - Mimikatz Pass the Hash
 type: bool

 - name: T1550.002 - 2
 description: Pass the Hash - crackmapexec Pass the Hash
 type: bool

 - name: T1550.003 - 1
 description: Pass the Ticket - Mimikatz Kerberos Ticket Attack
 type: bool

 - name: T1556.002 - 1
 description: Password Filter DLL - Install and Register Password Filter DLL
 type: bool

 - name: T1574.009 - 1
 description: Path Interception by Unquoted Path - Execution of program.exe as service with unquoted service path
 type: bool

 - name: T1055.012 - 1
 description: Process Hollowing - Process Hollowing using PowerShell
 type: bool

 - name: T1055.012 - 2
 description: Process Hollowing - RunPE via VBA
 type: bool

 - name: T1055 - 1
 description: Process Injection - Shellcode execution via VBA
 type: bool

 - name: T1055 - 2
 description: Process Injection - Remote Process Injection in LSASS via mimikatz
 type: bool

 - name: T1216.001 - 1
 description: PubPrn - PubPrn.vbs Signed Script Bypass
 type: bool

 - name: T1218.009 - 1
 description: Regsvcs/Regasm - Regasm Uninstall Method Call Test
 type: bool

 - name: T1218.009 - 2
 description: Regsvcs/Regasm - Regsvcs Uninstall Method Call Test
 type: bool

 - name: T1218.010 - 1
 description: Regsvr32 - Regsvr32 local COM scriptlet execution
 type: bool

 - name: T1218.010 - 2
 description: Regsvr32 - Regsvr32 remote COM scriptlet execution
 type: bool

 - name: T1218.010 - 3
 description: Regsvr32 - Regsvr32 local DLL execution
 type: bool

 - name: T1218.010 - 4
 description: Regsvr32 - Regsvr32 Registering Non DLL
 type: bool

 - name: T1218.010 - 5
 description: Regsvr32 - Regsvr32 Silent DLL Install Call DllRegisterServer
 type: bool

 - name: T1036.003 - 1
 description: Rename System Utilities - Masquerading as Windows LSASS process
 type: bool

 - name: T1036.003 - 3
 description: Rename System Utilities - Masquerading - cscript.exe running as notepad.exe
 type: bool

 - name: T1036.003 - 4
 description: Rename System Utilities - Masquerading - wscript.exe running as svchost.exe
 type: bool

 - name: T1036.003 - 5
 description: Rename System Utilities - Masquerading - powershell.exe running as taskhostw.exe
 type: bool

 - name: T1036.003 - 6
 description: Rename System Utilities - Masquerading - non-windows exe running as windows exe
 type: bool

 - name: T1036.003 - 7
 description: Rename System Utilities - Masquerading - windows exe running as different windows exe
 type: bool

 - name: T1036.003 - 8
 description: Rename System Utilities - Malicious process Masquerading as LSM.exe
 type: bool

 - name: T1036.003 - 9
 description: Rename System Utilities - File Extension Masquerading
 type: bool

 - name: T1207 - 1
 description: Rogue Domain Controller - DCShadow (Active Directory)
 type: bool

 - name: T1014 - 3
 description: Rootkit - Windows Signed Driver Rootkit Test
 type: bool

 - name: T1218.011 - 1
 description: Rundll32 - Rundll32 execute JavaScript Remote Payload With GetObject
 type: bool

 - name: T1218.011 - 2
 description: Rundll32 - Rundll32 execute VBscript command
 type: bool

 - name: T1218.011 - 3
 description: Rundll32 - Rundll32 advpack.dll Execution
 type: bool

 - name: T1218.011 - 4
 description: Rundll32 - Rundll32 ieadvpack.dll Execution
 type: bool

 - name: T1218.011 - 5
 description: Rundll32 - Rundll32 syssetup.dll Execution
 type: bool

 - name: T1218.011 - 6
 description: Rundll32 - Rundll32 setupapi.dll Execution
 type: bool

 - name: T1218.011 - 7
 description: Rundll32 - Execution of HTA and VBS Files using Rundll32 and URL.dll
 type: bool

 - name: T1218.011 - 8
 description: Rundll32 - Launches an executable using Rundll32 and pcwutl.dll
 type: bool

 - name: T1574.011 - 1
 description: Services Registry Permissions Weakness - Service Registry Permissions Weakness
 type: bool

 - name: T1574.011 - 2
 description: Services Registry Permissions Weakness - Service ImagePath Change with reg.exe
 type: bool

 - name: T1218 - 1
 description: Signed Binary Proxy Execution - mavinject - Inject DLL into running process
 type: bool

 - name: T1218 - 2
 description: Signed Binary Proxy Execution - SyncAppvPublishingServer - Execute arbitrary PowerShell code
 type: bool

 - name: T1218 - 3
 description: Signed Binary Proxy Execution - Register-CimProvider - Execute evil dll
 type: bool

 - name: T1218 - 4
 description: Signed Binary Proxy Execution - InfDefaultInstall.exe .inf Execution
 type: bool

 - name: T1218 - 5
 description: Signed Binary Proxy Execution - ProtocolHandler.exe Downloaded a Suspicious File
 type: bool

 - name: T1218 - 6
 description: Signed Binary Proxy Execution - Microsoft.Workflow.Compiler.exe Payload Execution
 type: bool

 - name: T1218 - 7
 description: Signed Binary Proxy Execution - Renamed Microsoft.Workflow.Compiler.exe Payload Executions
 type: bool

 - name: T1218 - 8
 description: Signed Binary Proxy Execution - Invoke-ATHRemoteFXvGPUDisablementCommand base test
 type: bool

 - name: T1216 - 1
 description: Signed Script Proxy Execution - SyncAppvPublishingServer Signed Script PowerShell Command Execution
 type: bool

 - name: T1216 - 2
 description: Signed Script Proxy Execution - manage-bde.wsf Signed Script Command Execution
 type: bool

 - name: T1497.001 - 2
 description: System Checks - Detect Virtualization Environment (Windows)
 type: bool

 - name: T1221 - 1
 description: Template Injection - WINWORD Remote Template Injection
 type: bool

 - name: T1070.006 - 5
 description: Timestomp - Windows - Modify file creation timestamp with PowerShell
 type: bool

 - name: T1070.006 - 6
 description: Timestomp - Windows - Modify file last modified timestamp with PowerShell
 type: bool

 - name: T1070.006 - 7
 description: Timestomp - Windows - Modify file last access timestamp with PowerShell
 type: bool

 - name: T1070.006 - 8
 description: Timestomp - Windows - Timestomp a File
 type: bool

 - name: T1134.001 - 1
 description: Token Impersonation/Theft - Named pipe client impersonation
 type: bool

 - name: T1134.001 - 2
 description: Token Impersonation/Theft - `SeDebugPrivilege` token duplication
 type: bool

 - name: T1222.001 - 1
 description: Windows File and Directory Permissions Modification - Take ownership using takeown utility
 type: bool

 - name: T1222.001 - 2
 description: Windows File and Directory Permissions Modification - cacls - Grant permission to specified user or group recursively
 type: bool

 - name: T1222.001 - 3
 description: Windows File and Directory Permissions Modification - attrib - Remove read-only attribute
 type: bool

 - name: T1222.001 - 4
 description: Windows File and Directory Permissions Modification - attrib - hide file
 type: bool

 - name: T1222.001 - 5
 description: Windows File and Directory Permissions Modification - Grant Full Access to folder for Everyone - Ryuk Ransomware Style
 type: bool

 - name: T1220 - 1
 description: XSL Script Processing - MSXSL Bypass using local files
 type: bool

 - name: T1220 - 2
 description: XSL Script Processing - MSXSL Bypass using remote files
 type: bool

 - name: T1220 - 3
 description: XSL Script Processing - WMIC bypass using local XSL file
 type: bool

 - name: T1220 - 4
 description: XSL Script Processing - WMIC bypass using remote XSL file
 type: bool

 - name: T1546.008 - 1
 description: Accessibility Features - Attaches Command Prompt as a Debugger to a List of Target Processes
 type: bool

 - name: T1546.008 - 2
 description: Accessibility Features - Replace binary of sticky keys
 type: bool

 - name: T1098 - 1
 description: Account Manipulation - Admin Account Manipulate
 type: bool

 - name: T1098 - 2
 description: Account Manipulation - Domain Account and Group Manipulate
 type: bool

 - name: T1137.006 - 1
 description: Add-ins - Code Executed Via Excel Add-in File (Xll)
 type: bool

 - name: T1546.010 - 1
 description: AppInit DLLs - Install AppInit Shim
 type: bool

 - name: T1546.011 - 1
 description: Application Shimming - Application Shim Installation
 type: bool

 - name: T1546.011 - 2
 description: Application Shimming - New shim database files created in the default shim database directory
 type: bool

 - name: T1546.011 - 3
 description: Application Shimming - Registry key creation and/or modification events for SDB
 type: bool

 - name: T1053.002 - 1
 description: At (Windows) - At.exe Scheduled task
 type: bool

 - name: T1197 - 1
 description: BITS Jobs - Bitsadmin Download (cmd)
 type: bool

 - name: T1197 - 2
 description: BITS Jobs - Bitsadmin Download (PowerShell)
 type: bool

 - name: T1197 - 3
 description: BITS Jobs - Persist, Download, &amp;amp; Execute
 type: bool

 - name: T1197 - 4
 description: BITS Jobs - Bits download using desktopimgdownldr.exe (cmd)
 type: bool

 - name: T1176 - 1
 description: Browser Extensions - Chrome (Developer Mode)
 type: bool

 - name: T1176 - 2
 description: Browser Extensions - Chrome (Chrome Web Store)
 type: bool

 - name: T1176 - 3
 description: Browser Extensions - Firefox
 type: bool

 - name: T1176 - 4
 description: Browser Extensions - Edge Chromium Addon - VPN
 type: bool

 - name: T1574.012 - 1
 description: COR_PROFILER - User scope COR_PROFILER
 type: bool

 - name: T1574.012 - 2
 description: COR_PROFILER - System Scope COR_PROFILER
 type: bool

 - name: T1574.012 - 3
 description: COR_PROFILER - Registry-free process scope COR_PROFILER
 type: bool

 - name: T1546.001 - 1
 description: Change Default File Association - Change Default File Association
 type: bool

 - name: T1574.001 - 1
 description: DLL Search Order Hijacking - DLL Search Order Hijacking - amsi.dll
 type: bool

 - name: T1574.002 - 1
 description: DLL Side-Loading - DLL Side-Loading using the Notepad++ GUP.exe binary
 type: bool

 - name: T1078.001 - 1
 description: Default Accounts - Enable Guest account with RDP capability and admin privileges
 type: bool

 - name: T1078.001 - 2
 description: Default Accounts - Activate Guest Account
 type: bool

 - name: T1136.002 - 1
 description: Domain Account - Create a new Windows domain admin user
 type: bool

 - name: T1136.002 - 2
 description: Domain Account - Create a new account similar to ANONYMOUS LOGON
 type: bool

 - name: T1136.002 - 3
 description: Domain Account - Create a new Domain Account using PowerShell
 type: bool

 - name: T1133 - 1
 description: External Remote Services - Running Chrome VPN Extensions via the Registry 2 vpn extension
 type: bool

 - name: T1546.012 - 1
 description: Image File Execution Options Injection - IFEO Add Debugger
 type: bool

 - name: T1546.012 - 2
 description: Image File Execution Options Injection - IFEO Global Flags
 type: bool

 - name: T1136.001 - 3
 description: Local Account - Create a new user in a command prompt
 type: bool

 - name: T1136.001 - 4
 description: Local Account - Create a new user in PowerShell
 type: bool

 - name: T1136.001 - 6
 description: Local Account - Create a new Windows admin user
 type: bool

 - name: T1078.003 - 1
 description: Local Accounts - Create local account with admin privileges
 type: bool

 - name: T1037.001 - 1
 description: Logon Script (Windows) - Logon Scripts
 type: bool

 - name: T1546.007 - 1
 description: Netsh Helper DLL - Netsh Helper DLL Registration
 type: bool

 - name: T1137 - 1
 description: Office Application Startup - Office Application Startup - Outlook as a C2
 type: bool

 - name: T1137.002 - 1
 description: Office Test - Office Application Startup Test Persistence
 type: bool

 - name: T1137.004 - 1
 description: Outlook Home Page - Install Outlook Home Page Persistence
 type: bool

 - name: T1556.002 - 1
 description: Password Filter DLL - Install and Register Password Filter DLL
 type: bool

 - name: T1574.009 - 1
 description: Path Interception by Unquoted Path - Execution of program.exe as service with unquoted service path
 type: bool

 - name: T1547.010 - 1
 description: Port Monitors - Add Port Monitor persistence in Registry
 type: bool

 - name: T1546.013 - 1
 description: PowerShell Profile - Append malicious start-process cmdlet
 type: bool

 - name: T1547.001 - 1
 description: Registry Run Keys / Startup Folder - Reg Key Run
 type: bool

 - name: T1547.001 - 2
 description: Registry Run Keys / Startup Folder - Reg Key RunOnce
 type: bool

 - name: T1547.001 - 3
 description: Registry Run Keys / Startup Folder - PowerShell Registry RunOnce
 type: bool

 - name: T1547.001 - 4
 description: Registry Run Keys / Startup Folder - Suspicious vbs file run from startup Folder
 type: bool

 - name: T1547.001 - 5
 description: Registry Run Keys / Startup Folder - Suspicious jse file run from startup Folder
 type: bool

 - name: T1547.001 - 6
 description: Registry Run Keys / Startup Folder - Suspicious bat file run from startup Folder
 type: bool

 - name: T1547.001 - 7
 description: Registry Run Keys / Startup Folder - Add Executable Shortcut Link to User Startup Folder
 type: bool

 - name: T1053.005 - 1
 description: Scheduled Task - Scheduled Task Startup Script
 type: bool

 - name: T1053.005 - 2
 description: Scheduled Task - Scheduled task Local
 type: bool

 - name: T1053.005 - 3
 description: Scheduled Task - Scheduled task Remote
 type: bool

 - name: T1053.005 - 4
 description: Scheduled Task - Powershell Cmdlet Scheduled Task
 type: bool

 - name: T1053.005 - 5
 description: Scheduled Task - Task Scheduler via VBA
 type: bool

 - name: T1053.005 - 6
 description: Scheduled Task - WMI Invoke-CimMethod Scheduled Task
 type: bool

 - name: T1546.002 - 1
 description: Screensaver - Set Arbitrary Binary as Screensaver
 type: bool

 - name: T1547.005 - 1
 description: Security Support Provider - Modify SSP configuration in registry
 type: bool

 - name: T1574.011 - 1
 description: Services Registry Permissions Weakness - Service Registry Permissions Weakness
 type: bool

 - name: T1574.011 - 2
 description: Services Registry Permissions Weakness - Service ImagePath Change with reg.exe
 type: bool

 - name: T1547.009 - 1
 description: Shortcut Modification - Shortcut Modification
 type: bool

 - name: T1547.009 - 2
 description: Shortcut Modification - Create shortcut to cmd in startup folders
 type: bool

 - name: T1505.002 - 1
 description: Transport Agent - Install MS Exchange Transport Agent Persistence
 type: bool

 - name: T1505.003 - 1
 description: Web Shell - Web Shell Written to Disk
 type: bool

 - name: T1546.003 - 1
 description: Windows Management Instrumentation Event Subscription - Persistence via WMI Event Subscription
 type: bool

 - name: T1543.003 - 1
 description: Windows Service - Modify Fax service to run PowerShell
 type: bool

 - name: T1543.003 - 2
 description: Windows Service - Service Installation CMD
 type: bool

 - name: T1543.003 - 3
 description: Windows Service - Service Installation PowerShell
 type: bool

 - name: T1547.004 - 1
 description: Winlogon Helper DLL - Winlogon Shell Key Persistence - PowerShell
 type: bool

 - name: T1547.004 - 2
 description: Winlogon Helper DLL - Winlogon Userinit Key Persistence - PowerShell
 type: bool

 - name: T1547.004 - 3
 description: Winlogon Helper DLL - Winlogon Notify Key Logon Persistence - PowerShell
 type: bool

 - name: T1531 - 1
 description: Account Access Removal - Change User Password - Windows
 type: bool

 - name: T1531 - 2
 description: Account Access Removal - Delete User - Windows
 type: bool

 - name: T1531 - 3
 description: Account Access Removal - Remove Account From Domain Admin Group
 type: bool

 - name: T1485 - 1
 description: Data Destruction - Windows - Overwrite file with Sysinternals SDelete
 type: bool

 - name: T1486 - 5
 description: Data Encrypted for Impact - PureLocker Ransom Note
 type: bool

 - name: T1490 - 1
 description: Inhibit System Recovery - Windows - Delete Volume Shadow Copies
 type: bool

 - name: T1490 - 2
 description: Inhibit System Recovery - Windows - Delete Volume Shadow Copies via WMI
 type: bool

 - name: T1490 - 3
 description: Inhibit System Recovery - Windows - wbadmin Delete Windows Backup Catalog
 type: bool

 - name: T1490 - 4
 description: Inhibit System Recovery - Windows - Disable Windows Recovery Console Repair
 type: bool

 - name: T1490 - 5
 description: Inhibit System Recovery - Windows - Delete Volume Shadow Copies via WMI with PowerShell
 type: bool

 - name: T1490 - 6
 description: Inhibit System Recovery - Windows - Delete Backup Files
 type: bool

 - name: T1490 - 7
 description: Inhibit System Recovery - Windows - wbadmin Delete systemstatebackup
 type: bool

 - name: T1490 - 8
 description: Inhibit System Recovery - Windows - Disable the SR scheduled task
 type: bool

 - name: T1491.001 - 1
 description: Internal Defacement - Replace Desktop Wallpaper
 type: bool

 - name: T1489 - 1
 description: Service Stop - Windows - Stop service using Service Controller
 type: bool

 - name: T1489 - 2
 description: Service Stop - Windows - Stop service using net.exe
 type: bool

 - name: T1489 - 3
 description: Service Stop - Windows - Stop service by killing process
 type: bool

 - name: T1529 - 1
 description: System Shutdown/Reboot - Shutdown System - Windows
 type: bool

 - name: T1529 - 2
 description: System Shutdown/Reboot - Restart System - Windows
 type: bool

 - name: T1010 - 1
 description: Application Window Discovery - List Process Main Windows - C# .NET
 type: bool

 - name: T1217 - 4
 description: Browser Bookmark Discovery - List Google Chrome Bookmarks on Windows with powershell
 type: bool

 - name: T1217 - 5
 description: Browser Bookmark Discovery - List Google Chrome / Edge Chromium Bookmarks on Windows with command prompt
 type: bool

 - name: T1217 - 6
 description: Browser Bookmark Discovery - List Mozilla Firefox bookmarks on Windows with command prompt
 type: bool

 - name: T1217 - 7
 description: Browser Bookmark Discovery - List Internet Explorer Bookmarks using the command prompt
 type: bool

 - name: T1087.002 - 1
 description: Domain Account - Enumerate all accounts (Domain)
 type: bool

 - name: T1087.002 - 2
 description: Domain Account - Enumerate all accounts via PowerShell (Domain)
 type: bool

 - name: T1087.002 - 3
 description: Domain Account - Enumerate logged on users via CMD (Domain)
 type: bool

 - name: T1087.002 - 4
 description: Domain Account - Automated AD Recon (ADRecon)
 type: bool

 - name: T1087.002 - 5
 description: Domain Account - Adfind -Listing password policy
 type: bool

 - name: T1087.002 - 6
 description: Domain Account - Adfind - Enumerate Active Directory Admins
 type: bool

 - name: T1087.002 - 7
 description: Domain Account - Adfind - Enumerate Active Directory User Objects
 type: bool

 - name: T1087.002 - 8
 description: Domain Account - Adfind - Enumerate Active Directory Exchange AD Objects
 type: bool

 - name: T1087.002 - 9
 description: Domain Account - Enumerate Default Domain Admin Details (Domain)
 type: bool

 - name: T1087.002 - 10
 description: Domain Account - Enumerate Active Directory for Unconstrained Delegation
 type: bool

 - name: T1069.002 - 1
 description: Domain Groups - Basic Permission Groups Discovery Windows (Domain)
 type: bool

 - name: T1069.002 - 2
 description: Domain Groups - Permission Groups Discovery PowerShell (Domain)
 type: bool

 - name: T1069.002 - 3
 description: Domain Groups - Elevated group enumeration using net group (Domain)
 type: bool

 - name: T1069.002 - 4
 description: Domain Groups - Find machines where user has local admin access (PowerView)
 type: bool

 - name: T1069.002 - 5
 description: Domain Groups - Find local admins on all machines in domain (PowerView)
 type: bool

 - name: T1069.002 - 6
 description: Domain Groups - Find Local Admins via Group Policy (PowerView)
 type: bool

 - name: T1069.002 - 7
 description: Domain Groups - Enumerate Users Not Requiring Pre Auth (ASRepRoast)
 type: bool

 - name: T1069.002 - 8
 description: Domain Groups - Adfind - Query Active Directory Groups
 type: bool

 - name: T1482 - 1
 description: Domain Trust Discovery - Windows - Discover domain trusts with dsquery
 type: bool

 - name: T1482 - 2
 description: Domain Trust Discovery - Windows - Discover domain trusts with nltest
 type: bool

 - name: T1482 - 3
 description: Domain Trust Discovery - Powershell enumerate domains and forests
 type: bool

 - name: T1482 - 4
 description: Domain Trust Discovery - Adfind - Enumerate Active Directory OUs
 type: bool

 - name: T1482 - 5
 description: Domain Trust Discovery - Adfind - Enumerate Active Directory Trusts
 type: bool

 - name: T1482 - 6
 description: Domain Trust Discovery - Get-DomainTrust with PowerView
 type: bool

 - name: T1482 - 7
 description: Domain Trust Discovery - Get-ForestTrust with PowerView
 type: bool

 - name: T1083 - 1
 description: File and Directory Discovery - File and Directory Discovery (cmd.exe)
 type: bool

 - name: T1083 - 2
 description: File and Directory Discovery - File and Directory Discovery (PowerShell)
 type: bool

 - name: T1087.001 - 8
 description: Local Account - Enumerate all accounts on Windows (Local)
 type: bool

 - name: T1087.001 - 9
 description: Local Account - Enumerate all accounts via PowerShell (Local)
 type: bool

 - name: T1087.001 - 10
 description: Local Account - Enumerate logged on users via CMD (Local)
 type: bool

 - name: T1069.001 - 2
 description: Local Groups - Basic Permission Groups Discovery Windows (Local)
 type: bool

 - name: T1069.001 - 3
 description: Local Groups - Permission Groups Discovery PowerShell (Local)
 type: bool

 - name: T1069.001 - 4
 description: Local Groups - SharpHound3 - LocalAdmin
 type: bool

 - name: T1069.001 - 5
 description: Local Groups - Wmic Group Discovery
 type: bool

 - name: T1069.001 - 6
 description: Local Groups - WMIObject Group Discovery
 type: bool

 - name: T1046 - 3
 description: Network Service Scanning - Port Scan NMap for Windows
 type: bool

 - name: T1046 - 4
 description: Network Service Scanning - Port Scan using python
 type: bool

 - name: T1135 - 3
 description: Network Share Discovery - Network Share Discovery command prompt
 type: bool

 - name: T1135 - 4
 description: Network Share Discovery - Network Share Discovery PowerShell
 type: bool

 - name: T1135 - 5
 description: Network Share Discovery - View available share drives
 type: bool

 - name: T1135 - 6
 description: Network Share Discovery - Share Discovery with PowerView
 type: bool

 - name: T1040 - 3
 description: Network Sniffing - Packet Capture Windows Command Prompt
 type: bool

 - name: T1040 - 4
 description: Network Sniffing - Windows Internal Packet Capture
 type: bool

 - name: T1201 - 5
 description: Password Policy Discovery - Examine local password policy - Windows
 type: bool

 - name: T1201 - 6
 description: Password Policy Discovery - Examine domain password policy - Windows
 type: bool

 - name: T1120 - 1
 description: Peripheral Device Discovery - Win32_PnPEntity Hardware Inventory
 type: bool

 - name: T1057 - 2
 description: Process Discovery - Process Discovery - tasklist
 type: bool

 - name: T1012 - 1
 description: Query Registry - Query Registry
 type: bool

 - name: T1018 - 1
 description: Remote System Discovery - Remote System Discovery - net
 type: bool

 - name: T1018 - 2
 description: Remote System Discovery - Remote System Discovery - net group Domain Computers
 type: bool

 - name: T1018 - 3
 description: Remote System Discovery - Remote System Discovery - nltest
 type: bool

 - name: T1018 - 4
 description: Remote System Discovery - Remote System Discovery - ping sweep
 type: bool

 - name: T1018 - 5
 description: Remote System Discovery - Remote System Discovery - arp
 type: bool

 - name: T1018 - 8
 description: Remote System Discovery - Remote System Discovery - nslookup
 type: bool

 - name: T1018 - 9
 description: Remote System Discovery - Remote System Discovery - adidnsdump
 type: bool

 - name: T1018 - 10
 description: Remote System Discovery - Adfind - Enumerate Active Directory Computer Objects
 type: bool

 - name: T1018 - 11
 description: Remote System Discovery - Adfind - Enumerate Active Directory Domain Controller Objects
 type: bool

 - name: T1518.001 - 1
 description: Security Software Discovery - Security Software Discovery
 type: bool

 - name: T1518.001 - 2
 description: Security Software Discovery - Security Software Discovery - powershell
 type: bool

 - name: T1518.001 - 5
 description: Security Software Discovery - Security Software Discovery - Sysmon Service
 type: bool

 - name: T1518.001 - 6
 description: Security Software Discovery - Security Software Discovery - AV Discovery via WMI
 type: bool

 - name: T1518 - 1
 description: Software Discovery - Find and Display Internet Explorer Browser Version
 type: bool

 - name: T1518 - 2
 description: Software Discovery - Applications Installed
 type: bool

 - name: T1497.001 - 2
 description: System Checks - Detect Virtualization Environment (Windows)
 type: bool

 - name: T1082 - 1
 description: System Information Discovery - System Information Discovery
 type: bool

 - name: T1082 - 6
 description: System Information Discovery - Hostname Discovery (Windows)
 type: bool

 - name: T1082 - 8
 description: System Information Discovery - Windows MachineGUID Discovery
 type: bool

 - name: T1082 - 9
 description: System Information Discovery - Griffon Recon
 type: bool

 - name: T1082 - 10
 description: System Information Discovery - Environment variables discovery on windows
 type: bool

 - name: T1016 - 1
 description: System Network Configuration Discovery - System Network Configuration Discovery on Windows
 type: bool

 - name: T1016 - 2
 description: System Network Configuration Discovery - List Windows Firewall Rules
 type: bool

 - name: T1016 - 4
 description: System Network Configuration Discovery - System Network Configuration Discovery (TrickBot Style)
 type: bool

 - name: T1016 - 5
 description: System Network Configuration Discovery - List Open Egress Ports
 type: bool

 - name: T1016 - 6
 description: System Network Configuration Discovery - Adfind - Enumerate Active Directory Subnet Objects
 type: bool

 - name: T1016 - 7
 description: System Network Configuration Discovery - Qakbot Recon
 type: bool

 - name: T1049 - 1
 description: System Network Connections Discovery - System Network Connections Discovery
 type: bool

 - name: T1049 - 2
 description: System Network Connections Discovery - System Network Connections Discovery with PowerShell
 type: bool

 - name: T1049 - 4
 description: System Network Connections Discovery - System Discovery using SharpView
 type: bool

 - name: T1033 - 1
 description: System Owner/User Discovery - System Owner/User Discovery
 type: bool

 - name: T1033 - 3
 description: System Owner/User Discovery - Find computers where user has session - Stealth mode (PowerView)
 type: bool

 - name: T1007 - 1
 description: System Service Discovery - System Service Discovery
 type: bool

 - name: T1007 - 2
 description: System Service Discovery - System Service Discovery - net.exe
 type: bool

 - name: T1124 - 1
 description: System Time Discovery - System Time Discovery
 type: bool

 - name: T1124 - 2
 description: System Time Discovery - System Time Discovery - PowerShell
 type: bool

 - name: T1071.004 - 1
 description: DNS - DNS Large Query Volume
 type: bool

 - name: T1071.004 - 2
 description: DNS - DNS Regular Beaconing
 type: bool

 - name: T1071.004 - 3
 description: DNS - DNS Long Domain Query
 type: bool

 - name: T1071.004 - 4
 description: DNS - DNS C2
 type: bool

 - name: T1573 - 1
 description: Encrypted Channel - OpenSSL C2
 type: bool

 - name: T1105 - 7
 description: Ingress Tool Transfer - certutil download (urlcache)
 type: bool

 - name: T1105 - 8
 description: Ingress Tool Transfer - certutil download (verifyctl)
 type: bool

 - name: T1105 - 9
 description: Ingress Tool Transfer - Windows - BITSAdmin BITS Download
 type: bool

 - name: T1105 - 10
 description: Ingress Tool Transfer - Windows - PowerShell Download
 type: bool

 - name: T1105 - 11
 description: Ingress Tool Transfer - OSTAP Worming Activity
 type: bool

 - name: T1105 - 12
 description: Ingress Tool Transfer - svchost writing a file to a UNC path
 type: bool

 - name: T1105 - 13
 description: Ingress Tool Transfer - Download a File with Windows Defender MpCmdRun.exe
 type: bool

 - name: T1105 - 15
 description: Ingress Tool Transfer - File Download via PowerShell
 type: bool

 - name: T1105 - 16
 description: Ingress Tool Transfer - File download with finger.exe on Windows
 type: bool

 - name: T1105 - 17
 description: Ingress Tool Transfer - Download a file with IMEWDBLD.exe
 type: bool

 - name: T1105 - 18
 description: Ingress Tool Transfer - Curl Download File
 type: bool

 - name: T1090.001 - 3
 description: Internal Proxy - portproxy reg key
 type: bool

 - name: T1095 - 1
 description: Non-Application Layer Protocol - ICMP C2
 type: bool

 - name: T1095 - 2
 description: Non-Application Layer Protocol - Netcat C2
 type: bool

 - name: T1095 - 3
 description: Non-Application Layer Protocol - Powercat C2
 type: bool

 - name: T1571 - 1
 description: Non-Standard Port - Testing usage of uncommonly used port with PowerShell
 type: bool

 - name: T1572 - 1
 description: Protocol Tunneling - DNS over HTTPS Large Query Volume
 type: bool

 - name: T1572 - 2
 description: Protocol Tunneling - DNS over HTTPS Regular Beaconing
 type: bool

 - name: T1572 - 3
 description: Protocol Tunneling - DNS over HTTPS Long Domain Query
 type: bool

 - name: T1219 - 1
 description: Remote Access Software - TeamViewer Files Detected Test on Windows
 type: bool

 - name: T1219 - 2
 description: Remote Access Software - AnyDesk Files Detected Test on Windows
 type: bool

 - name: T1219 - 3
 description: Remote Access Software - LogMeIn Files Detected Test on Windows
 type: bool

 - name: T1219 - 4
 description: Remote Access Software - GoToAssist Files Detected Test on Windows
 type: bool

 - name: T1219 - 5
 description: Remote Access Software - ScreenConnect Application Download and Install on Windows
 type: bool

 - name: T1132.001 - 2
 description: Standard Encoding - XOR Encoded data.
 type: bool

 - name: T1071.001 - 1
 description: Web Protocols - Malicious User Agents - Powershell
 type: bool

 - name: T1071.001 - 2
 description: Web Protocols - Malicious User Agents - CMD
 type: bool

 - name: T1053.002 - 1
 description: At (Windows) - At.exe Scheduled task
 type: bool

 - name: T1559.002 - 1
 description: Dynamic Data Exchange - Execute Commands
 type: bool

 - name: T1559.002 - 2
 description: Dynamic Data Exchange - Execute PowerShell script via Word DDE
 type: bool

 - name: T1559.002 - 3
 description: Dynamic Data Exchange - DDEAUTO
 type: bool

 - name: T1204.002 - 1
 description: Malicious File - OSTap Style Macro Execution
 type: bool

 - name: T1204.002 - 2
 description: Malicious File - OSTap Payload Download
 type: bool

 - name: T1204.002 - 3
 description: Malicious File - Maldoc choice flags command execution
 type: bool

 - name: T1204.002 - 4
 description: Malicious File - OSTAP JS version
 type: bool

 - name: T1204.002 - 5
 description: Malicious File - Office launching .bat file from AppData
 type: bool

 - name: T1204.002 - 6
 description: Malicious File - Excel 4 Macro
 type: bool

 - name: T1204.002 - 7
 description: Malicious File - Headless Chrome code execution via VBA
 type: bool

 - name: T1204.002 - 8
 description: Malicious File - Potentially Unwanted Applications (PUA)
 type: bool

 - name: T1204.002 - 9
 description: Malicious File - Office Generic Payload Download
 type: bool

 - name: T1106 - 1
 description: Native API - Execution through API - CreateProcess
 type: bool

 - name: T1059.001 - 1
 description: PowerShell - Mimikatz
 type: bool

 - name: T1059.001 - 2
 description: PowerShell - Run BloodHound from local disk
 type: bool

 - name: T1059.001 - 3
 description: PowerShell - Run Bloodhound from Memory using Download Cradle
 type: bool

 - name: T1059.001 - 4
 description: PowerShell - Obfuscation Tests
 type: bool

 - name: T1059.001 - 5
 description: PowerShell - Mimikatz - Cradlecraft PsSendKeys
 type: bool

 - name: T1059.001 - 6
 description: PowerShell - Invoke-AppPathBypass
 type: bool

 - name: T1059.001 - 7
 description: PowerShell - Powershell MsXml COM object - with prompt
 type: bool

 - name: T1059.001 - 8
 description: PowerShell - Powershell XML requests
 type: bool

 - name: T1059.001 - 9
 description: PowerShell - Powershell invoke mshta.exe download
 type: bool

 - name: T1059.001 - 10
 description: PowerShell - Powershell Invoke-DownloadCradle
 type: bool

 - name: T1059.001 - 11
 description: PowerShell - PowerShell Fileless Script Execution
 type: bool

 - name: T1059.001 - 12
 description: PowerShell - PowerShell Downgrade Attack
 type: bool

 - name: T1059.001 - 13
 description: PowerShell - NTFS Alternate Data Stream Access
 type: bool

 - name: T1059.001 - 14
 description: PowerShell - PowerShell Session Creation and Use
 type: bool

 - name: T1059.001 - 15
 description: PowerShell - ATHPowerShellCommandLineParameter -Command parameter variations
 type: bool

 - name: T1059.001 - 16
 description: PowerShell - ATHPowerShellCommandLineParameter -Command parameter variations with encoded arguments
 type: bool

 - name: T1059.001 - 17
 description: PowerShell - ATHPowerShellCommandLineParameter -EncodedCommand parameter variations
 type: bool

 - name: T1059.001 - 18
 description: PowerShell - ATHPowerShellCommandLineParameter -EncodedCommand parameter variations with encoded arguments
 type: bool

 - name: T1059.001 - 19
 description: PowerShell - PowerShell Command Execution
 type: bool

 - name: T1059.001 - 20
 description: PowerShell - PowerShell Invoke Known Malicious Cmdlets
 type: bool

 - name: T1059.001 - 21
 description: PowerShell - PowerUp Invoke-AllChecks
 type: bool

 - name: T1053.005 - 1
 description: Scheduled Task - Scheduled Task Startup Script
 type: bool

 - name: T1053.005 - 2
 description: Scheduled Task - Scheduled task Local
 type: bool

 - name: T1053.005 - 3
 description: Scheduled Task - Scheduled task Remote
 type: bool

 - name: T1053.005 - 4
 description: Scheduled Task - Powershell Cmdlet Scheduled Task
 type: bool

 - name: T1053.005 - 5
 description: Scheduled Task - Task Scheduler via VBA
 type: bool

 - name: T1053.005 - 6
 description: Scheduled Task - WMI Invoke-CimMethod Scheduled Task
 type: bool

 - name: T1569.002 - 1
 description: Service Execution - Execute a Command as a Service
 type: bool

 - name: T1569.002 - 2
 description: Service Execution - Use PsExec to execute a command on a remote host
 type: bool

 - name: T1072 - 1
 description: Software Deployment Tools - Radmin Viewer Utility
 type: bool

 - name: T1059.005 - 1
 description: Visual Basic - Visual Basic script execution to gather local computer information
 type: bool

 - name: T1059.005 - 2
 description: Visual Basic - Encoded VBS code execution
 type: bool

 - name: T1059.005 - 3
 description: Visual Basic - Extract Memory via VBA
 type: bool

 - name: T1059.003 - 1
 description: Windows Command Shell - Create and Execute Batch Script
 type: bool

 - name: T1059.003 - 2
 description: Windows Command Shell - Writes text to a file and displays it.
 type: bool

 - name: T1059.003 - 3
 description: Windows Command Shell - Suspicious Execution via Windows Command Shell
 type: bool

 - name: T1047 - 1
 description: Windows Management Instrumentation - WMI Reconnaissance Users
 type: bool

 - name: T1047 - 2
 description: Windows Management Instrumentation - WMI Reconnaissance Processes
 type: bool

 - name: T1047 - 3
 description: Windows Management Instrumentation - WMI Reconnaissance Software
 type: bool

 - name: T1047 - 4
 description: Windows Management Instrumentation - WMI Reconnaissance List Remote Services
 type: bool

 - name: T1047 - 5
 description: Windows Management Instrumentation - WMI Execute Local Process
 type: bool

 - name: T1047 - 6
 description: Windows Management Instrumentation - WMI Execute Remote Process
 type: bool

 - name: T1047 - 7
 description: Windows Management Instrumentation - Create a Process using WMI Query and an Encoded Command
 type: bool

 - name: T1047 - 8
 description: Windows Management Instrumentation - Create a Process using obfuscated Win32_Process
 type: bool

 - name: T1047 - 9
 description: Windows Management Instrumentation - WMI Execute rundll32
 type: bool

 - name: T1020 - 1
 description: Automated Exfiltration - IcedID Botnet HTTP PUT
 type: bool

 - name: T1048 - 3
 description: Exfiltration Over Alternative Protocol - DNSExfiltration (doh)
 type: bool

 - name: T1041 - 1
 description: Exfiltration Over C2 Channel - C2 Data Exfiltration
 type: bool

 - name: T1048.003 - 2
 description: Exfiltration Over Unencrypted/Obfuscated Non-C2 Protocol - Exfiltration Over Alternative Protocol - ICMP
 type: bool

 - name: T1048.003 - 4
 description: Exfiltration Over Unencrypted/Obfuscated Non-C2 Protocol - Exfiltration Over Alternative Protocol - HTTP
 type: bool

 - name: T1048.003 - 5
 description: Exfiltration Over Unencrypted/Obfuscated Non-C2 Protocol - Exfiltration Over Alternative Protocol - SMTP
 type: bool

 - name: T1567 - 1
 description: Exfiltration Over Web Service - Data Exfiltration with ConfigSecurityPolicy
 type: bool

 - name: T1021.003 - 1
 description: Distributed Component Object Model - PowerShell Lateral Movement using MMC20
 type: bool

 - name: T1550.002 - 1
 description: Pass the Hash - Mimikatz Pass the Hash
 type: bool

 - name: T1550.002 - 2
 description: Pass the Hash - crackmapexec Pass the Hash
 type: bool

 - name: T1550.003 - 1
 description: Pass the Ticket - Mimikatz Kerberos Ticket Attack
 type: bool

 - name: T1563.002 - 1
 description: RDP Hijacking - RDP hijacking
 type: bool

 - name: T1021.001 - 1
 description: Remote Desktop Protocol - RDP to DomainController
 type: bool

 - name: T1021.001 - 2
 description: Remote Desktop Protocol - RDP to Server
 type: bool

 - name: T1021.001 - 3
 description: Remote Desktop Protocol - Changing RDP Port to Non Standard Port via Powershell
 type: bool

 - name: T1021.001 - 4
 description: Remote Desktop Protocol - Changing RDP Port to Non Standard Port via Command_Prompt
 type: bool

 - name: T1021.002 - 1
 description: SMB/Windows Admin Shares - Map admin share
 type: bool

 - name: T1021.002 - 2
 description: SMB/Windows Admin Shares - Map Admin Share PowerShell
 type: bool

 - name: T1021.002 - 3
 description: SMB/Windows Admin Shares - Copy and Execute File with PsExec
 type: bool

 - name: T1021.002 - 4
 description: SMB/Windows Admin Shares - Execute command writing output to local Admin Share
 type: bool

 - name: T1072 - 1
 description: Software Deployment Tools - Radmin Viewer Utility
 type: bool

 - name: T1021.006 - 1
 description: Windows Remote Management - Enable Windows Remote Management
 type: bool

 - name: T1021.006 - 2
 description: Windows Remote Management - Invoke-Command
 type: bool

 - name: T1021.006 - 3
 description: Windows Remote Management - WinRM Access with Evil-WinRM
 type: bool

 - name: T1078.001 - 1
 description: Default Accounts - Enable Guest account with RDP capability and admin privileges
 type: bool

 - name: T1078.001 - 2
 description: Default Accounts - Activate Guest Account
 type: bool

 - name: T1133 - 1
 description: External Remote Services - Running Chrome VPN Extensions via the Registry 2 vpn extension
 type: bool

 - name: T1078.003 - 1
 description: Local Accounts - Create local account with admin privileges
 type: bool

 - name: T1566.001 - 1
 description: Spearphishing Attachment - Download Phishing Attachment - VBScript
 type: bool

 - name: T1566.001 - 2
 description: Spearphishing Attachment - Word spawned a command shell and used an IP address in the command line
 type: bool


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

sources:
 - query: |
 LET CommandTable = SELECT * FROM parse_csv(accessor="data", filename='''
 Flag,Command
 T1558.004 - 1,Invoke-AtomicTest T1558.004 -TestNumbers 1
 T1056.004 - 1,Invoke-AtomicTest T1056.004 -TestNumbers 1
 T1552.001 - 3,Invoke-AtomicTest T1552.001 -TestNumbers 3
 T1552.001 - 4,Invoke-AtomicTest T1552.001 -TestNumbers 4
 T1555 - 1,Invoke-AtomicTest T1555 -TestNumbers 1
 T1555 - 2,Invoke-AtomicTest T1555 -TestNumbers 2
 T1555 - 3,Invoke-AtomicTest T1555 -TestNumbers 3
 T1555 - 4,Invoke-AtomicTest T1555 -TestNumbers 4
 T1555 - 5,Invoke-AtomicTest T1555 -TestNumbers 5
 T1555.003 - 1,Invoke-AtomicTest T1555.003 -TestNumbers 1
 T1555.003 - 3,Invoke-AtomicTest T1555.003 -TestNumbers 3
 T1555.003 - 4,Invoke-AtomicTest T1555.003 -TestNumbers 4
 T1552.002 - 1,Invoke-AtomicTest T1552.002 -TestNumbers 1
 T1552.002 - 2,Invoke-AtomicTest T1552.002 -TestNumbers 2
 T1003.006 - 1,Invoke-AtomicTest T1003.006 -TestNumbers 1
 T1187 - 1,Invoke-AtomicTest T1187 -TestNumbers 1
 T1056.002 - 2,Invoke-AtomicTest T1056.002 -TestNumbers 2
 T1558.001 - 1,Invoke-AtomicTest T1558.001 -TestNumbers 1
 T1552.006 - 1,Invoke-AtomicTest T1552.006 -TestNumbers 1
 T1552.006 - 2,Invoke-AtomicTest T1552.006 -TestNumbers 2
 T1558.003 - 1,Invoke-AtomicTest T1558.003 -TestNumbers 1
 T1558.003 - 2,Invoke-AtomicTest T1558.003 -TestNumbers 2
 T1558.003 - 3,Invoke-AtomicTest T1558.003 -TestNumbers 3
 T1558.003 - 4,Invoke-AtomicTest T1558.003 -TestNumbers 4
 T1558.003 - 5,Invoke-AtomicTest T1558.003 -TestNumbers 5
 T1056.001 - 1,Invoke-AtomicTest T1056.001 -TestNumbers 1
 T1003.004 - 1,Invoke-AtomicTest T1003.004 -TestNumbers 1
 T1003.001 - 1,Invoke-AtomicTest T1003.001 -TestNumbers 1
 T1003.001 - 2,Invoke-AtomicTest T1003.001 -TestNumbers 2
 T1003.001 - 3,Invoke-AtomicTest T1003.001 -TestNumbers 3
 T1003.001 - 4,Invoke-AtomicTest T1003.001 -TestNumbers 4
 T1003.001 - 5,Invoke-AtomicTest T1003.001 -TestNumbers 5
 T1003.001 - 6,Invoke-AtomicTest T1003.001 -TestNumbers 6
 T1003.001 - 7,Invoke-AtomicTest T1003.001 -TestNumbers 7
 T1003.001 - 8,Invoke-AtomicTest T1003.001 -TestNumbers 8
 T1003.001 - 9,Invoke-AtomicTest T1003.001 -TestNumbers 9
 T1003.001 - 10,Invoke-AtomicTest T1003.001 -TestNumbers 10
 T1003.001 - 11,Invoke-AtomicTest T1003.001 -TestNumbers 11
 T1003.001 - 12,Invoke-AtomicTest T1003.001 -TestNumbers 12
 T1003.003 - 1,Invoke-AtomicTest T1003.003 -TestNumbers 1
 T1003.003 - 2,Invoke-AtomicTest T1003.003 -TestNumbers 2
 T1003.003 - 3,Invoke-AtomicTest T1003.003 -TestNumbers 3
 T1003.003 - 4,Invoke-AtomicTest T1003.003 -TestNumbers 4
 T1003.003 - 5,Invoke-AtomicTest T1003.003 -TestNumbers 5
 T1003.003 - 6,Invoke-AtomicTest T1003.003 -TestNumbers 6
 T1003.003 - 7,Invoke-AtomicTest T1003.003 -TestNumbers 7
 T1040 - 3,Invoke-AtomicTest T1040 -TestNumbers 3
 T1040 - 4,Invoke-AtomicTest T1040 -TestNumbers 4
 T1003 - 1,Invoke-AtomicTest T1003 -TestNumbers 1
 T1003 - 2,Invoke-AtomicTest T1003 -TestNumbers 2
 T1003 - 3,Invoke-AtomicTest T1003 -TestNumbers 3
 T1110.002 - 1,Invoke-AtomicTest T1110.002 -TestNumbers 1
 T1556.002 - 1,Invoke-AtomicTest T1556.002 -TestNumbers 1
 T1110.001 - 1,Invoke-AtomicTest T1110.001 -TestNumbers 1
 T1110.001 - 2,Invoke-AtomicTest T1110.001 -TestNumbers 2
 T1110.003 - 1,Invoke-AtomicTest T1110.003 -TestNumbers 1
 T1110.003 - 2,Invoke-AtomicTest T1110.003 -TestNumbers 2
 T1110.003 - 3,Invoke-AtomicTest T1110.003 -TestNumbers 3
 T1552.004 - 1,Invoke-AtomicTest T1552.004 -TestNumbers 1
 T1552.004 - 6,Invoke-AtomicTest T1552.004 -TestNumbers 6
 T1552.004 - 7,Invoke-AtomicTest T1552.004 -TestNumbers 7
 T1003.002 - 1,Invoke-AtomicTest T1003.002 -TestNumbers 1
 T1003.002 - 2,Invoke-AtomicTest T1003.002 -TestNumbers 2
 T1003.002 - 3,Invoke-AtomicTest T1003.002 -TestNumbers 3
 T1003.002 - 4,Invoke-AtomicTest T1003.002 -TestNumbers 4
 T1003.002 - 5,Invoke-AtomicTest T1003.002 -TestNumbers 5
 T1003.002 - 6,Invoke-AtomicTest T1003.002 -TestNumbers 6
 T1560 - 1,Invoke-AtomicTest T1560 -TestNumbers 1
 T1560.001 - 1,Invoke-AtomicTest T1560.001 -TestNumbers 1
 T1560.001 - 2,Invoke-AtomicTest T1560.001 -TestNumbers 2
 T1560.001 - 3,Invoke-AtomicTest T1560.001 -TestNumbers 3
 T1560.001 - 4,Invoke-AtomicTest T1560.001 -TestNumbers 4
 T1123 - 1,Invoke-AtomicTest T1123 -TestNumbers 1
 T1119 - 1,Invoke-AtomicTest T1119 -TestNumbers 1
 T1119 - 2,Invoke-AtomicTest T1119 -TestNumbers 2
 T1119 - 3,Invoke-AtomicTest T1119 -TestNumbers 3
 T1119 - 4,Invoke-AtomicTest T1119 -TestNumbers 4
 T1115 - 1,Invoke-AtomicTest T1115 -TestNumbers 1
 T1115 - 2,Invoke-AtomicTest T1115 -TestNumbers 2
 T1115 - 4,Invoke-AtomicTest T1115 -TestNumbers 4
 T1056.004 - 1,Invoke-AtomicTest T1056.004 -TestNumbers 1
 T1056.002 - 2,Invoke-AtomicTest T1056.002 -TestNumbers 2
 T1056.001 - 1,Invoke-AtomicTest T1056.001 -TestNumbers 1
 T1074.001 - 1,Invoke-AtomicTest T1074.001 -TestNumbers 1
 T1074.001 - 3,Invoke-AtomicTest T1074.001 -TestNumbers 3
 T1114.001 - 1,Invoke-AtomicTest T1114.001 -TestNumbers 1
 T1113 - 5,Invoke-AtomicTest T1113 -TestNumbers 5
 T1113 - 6,Invoke-AtomicTest T1113 -TestNumbers 6
 T1546.008 - 1,Invoke-AtomicTest T1546.008 -TestNumbers 1
 T1546.008 - 2,Invoke-AtomicTest T1546.008 -TestNumbers 2
 T1546.010 - 1,Invoke-AtomicTest T1546.010 -TestNumbers 1
 T1546.011 - 1,Invoke-AtomicTest T1546.011 -TestNumbers 1
 T1546.011 - 2,Invoke-AtomicTest T1546.011 -TestNumbers 2
 T1546.011 - 3,Invoke-AtomicTest T1546.011 -TestNumbers 3
 T1055.004 - 1,Invoke-AtomicTest T1055.004 -TestNumbers 1
 T1053.002 - 1,Invoke-AtomicTest T1053.002 -TestNumbers 1
 T1548.002 - 1,Invoke-AtomicTest T1548.002 -TestNumbers 1
 T1548.002 - 2,Invoke-AtomicTest T1548.002 -TestNumbers 2
 T1548.002 - 3,Invoke-AtomicTest T1548.002 -TestNumbers 3
 T1548.002 - 4,Invoke-AtomicTest T1548.002 -TestNumbers 4
 T1548.002 - 5,Invoke-AtomicTest T1548.002 -TestNumbers 5
 T1548.002 - 6,Invoke-AtomicTest T1548.002 -TestNumbers 6
 T1548.002 - 7,Invoke-AtomicTest T1548.002 -TestNumbers 7
 T1548.002 - 8,Invoke-AtomicTest T1548.002 -TestNumbers 8
 T1548.002 - 9,Invoke-AtomicTest T1548.002 -TestNumbers 9
 T1548.002 - 10,Invoke-AtomicTest T1548.002 -TestNumbers 10
 T1548.002 - 11,Invoke-AtomicTest T1548.002 -TestNumbers 11
 T1548.002 - 12,Invoke-AtomicTest T1548.002 -TestNumbers 12
 T1548.002 - 13,Invoke-AtomicTest T1548.002 -TestNumbers 13
 T1548.002 - 14,Invoke-AtomicTest T1548.002 -TestNumbers 14
 T1548.002 - 15,Invoke-AtomicTest T1548.002 -TestNumbers 15
 T1548.002 - 16,Invoke-AtomicTest T1548.002 -TestNumbers 16
 T1548.002 - 17,Invoke-AtomicTest T1548.002 -TestNumbers 17
 T1574.012 - 1,Invoke-AtomicTest T1574.012 -TestNumbers 1
 T1574.012 - 2,Invoke-AtomicTest T1574.012 -TestNumbers 2
 T1574.012 - 3,Invoke-AtomicTest T1574.012 -TestNumbers 3
 T1546.001 - 1,Invoke-AtomicTest T1546.001 -TestNumbers 1
 T1134.002 - 1,Invoke-AtomicTest T1134.002 -TestNumbers 1
 T1574.001 - 1,Invoke-AtomicTest T1574.001 -TestNumbers 1
 T1574.002 - 1,Invoke-AtomicTest T1574.002 -TestNumbers 1
 T1078.001 - 1,Invoke-AtomicTest T1078.001 -TestNumbers 1
 T1078.001 - 2,Invoke-AtomicTest T1078.001 -TestNumbers 2
 T1055.001 - 1,Invoke-AtomicTest T1055.001 -TestNumbers 1
 T1546.012 - 1,Invoke-AtomicTest T1546.012 -TestNumbers 1
 T1546.012 - 2,Invoke-AtomicTest T1546.012 -TestNumbers 2
 T1078.003 - 1,Invoke-AtomicTest T1078.003 -TestNumbers 1
 T1037.001 - 1,Invoke-AtomicTest T1037.001 -TestNumbers 1
 T1546.007 - 1,Invoke-AtomicTest T1546.007 -TestNumbers 1
 T1134.004 - 1,Invoke-AtomicTest T1134.004 -TestNumbers 1
 T1134.004 - 2,Invoke-AtomicTest T1134.004 -TestNumbers 2
 T1134.004 - 3,Invoke-AtomicTest T1134.004 -TestNumbers 3
 T1134.004 - 4,Invoke-AtomicTest T1134.004 -TestNumbers 4
 T1134.004 - 5,Invoke-AtomicTest T1134.004 -TestNumbers 5
 T1574.009 - 1,Invoke-AtomicTest T1574.009 -TestNumbers 1
 T1547.010 - 1,Invoke-AtomicTest T1547.010 -TestNumbers 1
 T1546.013 - 1,Invoke-AtomicTest T1546.013 -TestNumbers 1
 T1055.012 - 1,Invoke-AtomicTest T1055.012 -TestNumbers 1
 T1055.012 - 2,Invoke-AtomicTest T1055.012 -TestNumbers 2
 T1055 - 1,Invoke-AtomicTest T1055 -TestNumbers 1
 T1055 - 2,Invoke-AtomicTest T1055 -TestNumbers 2
 T1547.001 - 1,Invoke-AtomicTest T1547.001 -TestNumbers 1
 T1547.001 - 2,Invoke-AtomicTest T1547.001 -TestNumbers 2
 T1547.001 - 3,Invoke-AtomicTest T1547.001 -TestNumbers 3
 T1547.001 - 4,Invoke-AtomicTest T1547.001 -TestNumbers 4
 T1547.001 - 5,Invoke-AtomicTest T1547.001 -TestNumbers 5
 T1547.001 - 6,Invoke-AtomicTest T1547.001 -TestNumbers 6
 T1547.001 - 7,Invoke-AtomicTest T1547.001 -TestNumbers 7
 T1053.005 - 1,Invoke-AtomicTest T1053.005 -TestNumbers 1
 T1053.005 - 2,Invoke-AtomicTest T1053.005 -TestNumbers 2
 T1053.005 - 3,Invoke-AtomicTest T1053.005 -TestNumbers 3
 T1053.005 - 4,Invoke-AtomicTest T1053.005 -TestNumbers 4
 T1053.005 - 5,Invoke-AtomicTest T1053.005 -TestNumbers 5
 T1053.005 - 6,Invoke-AtomicTest T1053.005 -TestNumbers 6
 T1546.002 - 1,Invoke-AtomicTest T1546.002 -TestNumbers 1
 T1547.005 - 1,Invoke-AtomicTest T1547.005 -TestNumbers 1
 T1574.011 - 1,Invoke-AtomicTest T1574.011 -TestNumbers 1
 T1574.011 - 2,Invoke-AtomicTest T1574.011 -TestNumbers 2
 T1547.009 - 1,Invoke-AtomicTest T1547.009 -TestNumbers 1
 T1547.009 - 2,Invoke-AtomicTest T1547.009 -TestNumbers 2
 T1134.001 - 1,Invoke-AtomicTest T1134.001 -TestNumbers 1
 T1134.001 - 2,Invoke-AtomicTest T1134.001 -TestNumbers 2
 T1546.003 - 1,Invoke-AtomicTest T1546.003 -TestNumbers 1
 T1543.003 - 1,Invoke-AtomicTest T1543.003 -TestNumbers 1
 T1543.003 - 2,Invoke-AtomicTest T1543.003 -TestNumbers 2
 T1543.003 - 3,Invoke-AtomicTest T1543.003 -TestNumbers 3
 T1547.004 - 1,Invoke-AtomicTest T1547.004 -TestNumbers 1
 T1547.004 - 2,Invoke-AtomicTest T1547.004 -TestNumbers 2
 T1547.004 - 3,Invoke-AtomicTest T1547.004 -TestNumbers 3
 T1055.004 - 1,Invoke-AtomicTest T1055.004 -TestNumbers 1
 T1197 - 1,Invoke-AtomicTest T1197 -TestNumbers 1
 T1197 - 2,Invoke-AtomicTest T1197 -TestNumbers 2
 T1197 - 3,Invoke-AtomicTest T1197 -TestNumbers 3
 T1197 - 4,Invoke-AtomicTest T1197 -TestNumbers 4
 T1548.002 - 1,Invoke-AtomicTest T1548.002 -TestNumbers 1
 T1548.002 - 2,Invoke-AtomicTest T1548.002 -TestNumbers 2
 T1548.002 - 3,Invoke-AtomicTest T1548.002 -TestNumbers 3
 T1548.002 - 4,Invoke-AtomicTest T1548.002 -TestNumbers 4
 T1548.002 - 5,Invoke-AtomicTest T1548.002 -TestNumbers 5
 T1548.002 - 6,Invoke-AtomicTest T1548.002 -TestNumbers 6
 T1548.002 - 7,Invoke-AtomicTest T1548.002 -TestNumbers 7
 T1548.002 - 8,Invoke-AtomicTest T1548.002 -TestNumbers 8
 T1548.002 - 9,Invoke-AtomicTest T1548.002 -TestNumbers 9
 T1548.002 - 10,Invoke-AtomicTest T1548.002 -TestNumbers 10
 T1548.002 - 11,Invoke-AtomicTest T1548.002 -TestNumbers 11
 T1548.002 - 12,Invoke-AtomicTest T1548.002 -TestNumbers 12
 T1548.002 - 13,Invoke-AtomicTest T1548.002 -TestNumbers 13
 T1548.002 - 14,Invoke-AtomicTest T1548.002 -TestNumbers 14
 T1548.002 - 15,Invoke-AtomicTest T1548.002 -TestNumbers 15
 T1548.002 - 16,Invoke-AtomicTest T1548.002 -TestNumbers 16
 T1548.002 - 17,Invoke-AtomicTest T1548.002 -TestNumbers 17
 T1218.003 - 1,Invoke-AtomicTest T1218.003 -TestNumbers 1
 T1218.003 - 2,Invoke-AtomicTest T1218.003 -TestNumbers 2
 T1574.012 - 1,Invoke-AtomicTest T1574.012 -TestNumbers 1
 T1574.012 - 2,Invoke-AtomicTest T1574.012 -TestNumbers 2
 T1574.012 - 3,Invoke-AtomicTest T1574.012 -TestNumbers 3
 T1070.003 - 10,Invoke-AtomicTest T1070.003 -TestNumbers 10
 T1070.003 - 11,Invoke-AtomicTest T1070.003 -TestNumbers 11
 T1070.001 - 1,Invoke-AtomicTest T1070.001 -TestNumbers 1
 T1070.001 - 2,Invoke-AtomicTest T1070.001 -TestNumbers 2
 T1070.001 - 3,Invoke-AtomicTest T1070.001 -TestNumbers 3
 T1027.004 - 1,Invoke-AtomicTest T1027.004 -TestNumbers 1
 T1027.004 - 2,Invoke-AtomicTest T1027.004 -TestNumbers 2
 T1218.001 - 1,Invoke-AtomicTest T1218.001 -TestNumbers 1
 T1218.001 - 2,Invoke-AtomicTest T1218.001 -TestNumbers 2
 T1218.001 - 3,Invoke-AtomicTest T1218.001 -TestNumbers 3
 T1218.001 - 4,Invoke-AtomicTest T1218.001 -TestNumbers 4
 T1218.001 - 5,Invoke-AtomicTest T1218.001 -TestNumbers 5
 T1218.001 - 6,Invoke-AtomicTest T1218.001 -TestNumbers 6
 T1218.001 - 7,Invoke-AtomicTest T1218.001 -TestNumbers 7
 T1218.002 - 1,Invoke-AtomicTest T1218.002 -TestNumbers 1
 T1134.002 - 1,Invoke-AtomicTest T1134.002 -TestNumbers 1
 T1574.001 - 1,Invoke-AtomicTest T1574.001 -TestNumbers 1
 T1574.002 - 1,Invoke-AtomicTest T1574.002 -TestNumbers 1
 T1078.001 - 1,Invoke-AtomicTest T1078.001 -TestNumbers 1
 T1078.001 - 2,Invoke-AtomicTest T1078.001 -TestNumbers 2
 T1140 - 1,Invoke-AtomicTest T1140 -TestNumbers 1
 T1140 - 2,Invoke-AtomicTest T1140 -TestNumbers 2
 T1006 - 1,Invoke-AtomicTest T1006 -TestNumbers 1
 T1562.002 - 1,Invoke-AtomicTest T1562.002 -TestNumbers 1
 T1562.002 - 2,Invoke-AtomicTest T1562.002 -TestNumbers 2
 T1562.002 - 3,Invoke-AtomicTest T1562.002 -TestNumbers 3
 T1562.002 - 4,Invoke-AtomicTest T1562.002 -TestNumbers 4
 T1562.002 - 5,Invoke-AtomicTest T1562.002 -TestNumbers 5
 T1562.004 - 1,Invoke-AtomicTest T1562.004 -TestNumbers 1
 T1562.004 - 2,Invoke-AtomicTest T1562.004 -TestNumbers 2
 T1562.004 - 3,Invoke-AtomicTest T1562.004 -TestNumbers 3
 T1562.004 - 4,Invoke-AtomicTest T1562.004 -TestNumbers 4
 T1562.004 - 5,Invoke-AtomicTest T1562.004 -TestNumbers 5
 T1562.004 - 6,Invoke-AtomicTest T1562.004 -TestNumbers 6
 T1562.001 - 10,Invoke-AtomicTest T1562.001 -TestNumbers 10
 T1562.001 - 11,Invoke-AtomicTest T1562.001 -TestNumbers 11
 T1562.001 - 12,Invoke-AtomicTest T1562.001 -TestNumbers 12
 T1562.001 - 13,Invoke-AtomicTest T1562.001 -TestNumbers 13
 T1562.001 - 14,Invoke-AtomicTest T1562.001 -TestNumbers 14
 T1562.001 - 15,Invoke-AtomicTest T1562.001 -TestNumbers 15
 T1562.001 - 16,Invoke-AtomicTest T1562.001 -TestNumbers 16
 T1562.001 - 17,Invoke-AtomicTest T1562.001 -TestNumbers 17
 T1562.001 - 18,Invoke-AtomicTest T1562.001 -TestNumbers 18
 T1562.001 - 19,Invoke-AtomicTest T1562.001 -TestNumbers 19
 T1562.001 - 20,Invoke-AtomicTest T1562.001 -TestNumbers 20
 T1562.001 - 21,Invoke-AtomicTest T1562.001 -TestNumbers 21
 T1562.001 - 22,Invoke-AtomicTest T1562.001 -TestNumbers 22
 T1562.001 - 23,Invoke-AtomicTest T1562.001 -TestNumbers 23
 T1562.001 - 24,Invoke-AtomicTest T1562.001 -TestNumbers 24
 T1055.001 - 1,Invoke-AtomicTest T1055.001 -TestNumbers 1
 T1070.004 - 4,Invoke-AtomicTest T1070.004 -TestNumbers 4
 T1070.004 - 5,Invoke-AtomicTest T1070.004 -TestNumbers 5
 T1070.004 - 6,Invoke-AtomicTest T1070.004 -TestNumbers 6
 T1070.004 - 7,Invoke-AtomicTest T1070.004 -TestNumbers 7
 T1070.004 - 9,Invoke-AtomicTest T1070.004 -TestNumbers 9
 T1070.004 - 10,Invoke-AtomicTest T1070.004 -TestNumbers 10
 T1564.001 - 3,Invoke-AtomicTest T1564.001 -TestNumbers 3
 T1564.001 - 4,Invoke-AtomicTest T1564.001 -TestNumbers 4
 T1564.003 - 1,Invoke-AtomicTest T1564.003 -TestNumbers 1
 T1564 - 1,Invoke-AtomicTest T1564 -TestNumbers 1
 T1564 - 2,Invoke-AtomicTest T1564 -TestNumbers 2
 T1564 - 3,Invoke-AtomicTest T1564 -TestNumbers 3
 T1070 - 1,Invoke-AtomicTest T1070 -TestNumbers 1
 T1202 - 1,Invoke-AtomicTest T1202 -TestNumbers 1
 T1202 - 2,Invoke-AtomicTest T1202 -TestNumbers 2
 T1202 - 3,Invoke-AtomicTest T1202 -TestNumbers 3
 T1553.004 - 4,Invoke-AtomicTest T1553.004 -TestNumbers 4
 T1553.004 - 5,Invoke-AtomicTest T1553.004 -TestNumbers 5
 T1218.004 - 1,Invoke-AtomicTest T1218.004 -TestNumbers 1
 T1218.004 - 2,Invoke-AtomicTest T1218.004 -TestNumbers 2
 T1218.004 - 3,Invoke-AtomicTest T1218.004 -TestNumbers 3
 T1218.004 - 4,Invoke-AtomicTest T1218.004 -TestNumbers 4
 T1218.004 - 5,Invoke-AtomicTest T1218.004 -TestNumbers 5
 T1218.004 - 6,Invoke-AtomicTest T1218.004 -TestNumbers 6
 T1218.004 - 7,Invoke-AtomicTest T1218.004 -TestNumbers 7
 T1218.004 - 8,Invoke-AtomicTest T1218.004 -TestNumbers 8
 T1078.003 - 1,Invoke-AtomicTest T1078.003 -TestNumbers 1
 T1127.001 - 1,Invoke-AtomicTest T1127.001 -TestNumbers 1
 T1127.001 - 2,Invoke-AtomicTest T1127.001 -TestNumbers 2
 T1553.005 - 1,Invoke-AtomicTest T1553.005 -TestNumbers 1
 T1553.005 - 2,Invoke-AtomicTest T1553.005 -TestNumbers 2
 T1553.005 - 3,Invoke-AtomicTest T1553.005 -TestNumbers 3
 T1036.004 - 1,Invoke-AtomicTest T1036.004 -TestNumbers 1
 T1036.004 - 2,Invoke-AtomicTest T1036.004 -TestNumbers 2
 T1036 - 1,Invoke-AtomicTest T1036 -TestNumbers 1
 T1112 - 1,Invoke-AtomicTest T1112 -TestNumbers 1
 T1112 - 2,Invoke-AtomicTest T1112 -TestNumbers 2
 T1112 - 3,Invoke-AtomicTest T1112 -TestNumbers 3
 T1112 - 4,Invoke-AtomicTest T1112 -TestNumbers 4
 T1112 - 5,Invoke-AtomicTest T1112 -TestNumbers 5
 T1112 - 6,Invoke-AtomicTest T1112 -TestNumbers 6
 T1218.005 - 1,Invoke-AtomicTest T1218.005 -TestNumbers 1
 T1218.005 - 2,Invoke-AtomicTest T1218.005 -TestNumbers 2
 T1218.005 - 3,Invoke-AtomicTest T1218.005 -TestNumbers 3
 T1218.005 - 4,Invoke-AtomicTest T1218.005 -TestNumbers 4
 T1218.005 - 5,Invoke-AtomicTest T1218.005 -TestNumbers 5
 T1218.005 - 6,Invoke-AtomicTest T1218.005 -TestNumbers 6
 T1218.005 - 7,Invoke-AtomicTest T1218.005 -TestNumbers 7
 T1218.005 - 8,Invoke-AtomicTest T1218.005 -TestNumbers 8
 T1218.005 - 9,Invoke-AtomicTest T1218.005 -TestNumbers 9
 T1218.005 - 10,Invoke-AtomicTest T1218.005 -TestNumbers 10
 T1218.007 - 1,Invoke-AtomicTest T1218.007 -TestNumbers 1
 T1218.007 - 2,Invoke-AtomicTest T1218.007 -TestNumbers 2
 T1218.007 - 3,Invoke-AtomicTest T1218.007 -TestNumbers 3
 T1564.004 - 1,Invoke-AtomicTest T1564.004 -TestNumbers 1
 T1564.004 - 2,Invoke-AtomicTest T1564.004 -TestNumbers 2
 T1564.004 - 3,Invoke-AtomicTest T1564.004 -TestNumbers 3
 T1564.004 - 4,Invoke-AtomicTest T1564.004 -TestNumbers 4
 T1070.005 - 1,Invoke-AtomicTest T1070.005 -TestNumbers 1
 T1070.005 - 2,Invoke-AtomicTest T1070.005 -TestNumbers 2
 T1070.005 - 3,Invoke-AtomicTest T1070.005 -TestNumbers 3
 T1027 - 2,Invoke-AtomicTest T1027 -TestNumbers 2
 T1027 - 3,Invoke-AtomicTest T1027 -TestNumbers 3
 T1027 - 4,Invoke-AtomicTest T1027 -TestNumbers 4
 T1027 - 5,Invoke-AtomicTest T1027 -TestNumbers 5
 T1027 - 6,Invoke-AtomicTest T1027 -TestNumbers 6
 T1027 - 7,Invoke-AtomicTest T1027 -TestNumbers 7
 T1027 - 8,Invoke-AtomicTest T1027 -TestNumbers 8
 T1218.008 - 1,Invoke-AtomicTest T1218.008 -TestNumbers 1
 T1134.004 - 1,Invoke-AtomicTest T1134.004 -TestNumbers 1
 T1134.004 - 2,Invoke-AtomicTest T1134.004 -TestNumbers 2
 T1134.004 - 3,Invoke-AtomicTest T1134.004 -TestNumbers 3
 T1134.004 - 4,Invoke-AtomicTest T1134.004 -TestNumbers 4
 T1134.004 - 5,Invoke-AtomicTest T1134.004 -TestNumbers 5
 T1550.002 - 1,Invoke-AtomicTest T1550.002 -TestNumbers 1
 T1550.002 - 2,Invoke-AtomicTest T1550.002 -TestNumbers 2
 T1550.003 - 1,Invoke-AtomicTest T1550.003 -TestNumbers 1
 T1556.002 - 1,Invoke-AtomicTest T1556.002 -TestNumbers 1
 T1574.009 - 1,Invoke-AtomicTest T1574.009 -TestNumbers 1
 T1055.012 - 1,Invoke-AtomicTest T1055.012 -TestNumbers 1
 T1055.012 - 2,Invoke-AtomicTest T1055.012 -TestNumbers 2
 T1055 - 1,Invoke-AtomicTest T1055 -TestNumbers 1
 T1055 - 2,Invoke-AtomicTest T1055 -TestNumbers 2
 T1216.001 - 1,Invoke-AtomicTest T1216.001 -TestNumbers 1
 T1218.009 - 1,Invoke-AtomicTest T1218.009 -TestNumbers 1
 T1218.009 - 2,Invoke-AtomicTest T1218.009 -TestNumbers 2
 T1218.010 - 1,Invoke-AtomicTest T1218.010 -TestNumbers 1
 T1218.010 - 2,Invoke-AtomicTest T1218.010 -TestNumbers 2
 T1218.010 - 3,Invoke-AtomicTest T1218.010 -TestNumbers 3
 T1218.010 - 4,Invoke-AtomicTest T1218.010 -TestNumbers 4
 T1218.010 - 5,Invoke-AtomicTest T1218.010 -TestNumbers 5
 T1036.003 - 1,Invoke-AtomicTest T1036.003 -TestNumbers 1
 T1036.003 - 3,Invoke-AtomicTest T1036.003 -TestNumbers 3
 T1036.003 - 4,Invoke-AtomicTest T1036.003 -TestNumbers 4
 T1036.003 - 5,Invoke-AtomicTest T1036.003 -TestNumbers 5
 T1036.003 - 6,Invoke-AtomicTest T1036.003 -TestNumbers 6
 T1036.003 - 7,Invoke-AtomicTest T1036.003 -TestNumbers 7
 T1036.003 - 8,Invoke-AtomicTest T1036.003 -TestNumbers 8
 T1036.003 - 9,Invoke-AtomicTest T1036.003 -TestNumbers 9
 T1207 - 1,Invoke-AtomicTest T1207 -TestNumbers 1
 T1014 - 3,Invoke-AtomicTest T1014 -TestNumbers 3
 T1218.011 - 1,Invoke-AtomicTest T1218.011 -TestNumbers 1
 T1218.011 - 2,Invoke-AtomicTest T1218.011 -TestNumbers 2
 T1218.011 - 3,Invoke-AtomicTest T1218.011 -TestNumbers 3
 T1218.011 - 4,Invoke-AtomicTest T1218.011 -TestNumbers 4
 T1218.011 - 5,Invoke-AtomicTest T1218.011 -TestNumbers 5
 T1218.011 - 6,Invoke-AtomicTest T1218.011 -TestNumbers 6
 T1218.011 - 7,Invoke-AtomicTest T1218.011 -TestNumbers 7
 T1218.011 - 8,Invoke-AtomicTest T1218.011 -TestNumbers 8
 T1574.011 - 1,Invoke-AtomicTest T1574.011 -TestNumbers 1
 T1574.011 - 2,Invoke-AtomicTest T1574.011 -TestNumbers 2
 T1218 - 1,Invoke-AtomicTest T1218 -TestNumbers 1
 T1218 - 2,Invoke-AtomicTest T1218 -TestNumbers 2
 T1218 - 3,Invoke-AtomicTest T1218 -TestNumbers 3
 T1218 - 4,Invoke-AtomicTest T1218 -TestNumbers 4
 T1218 - 5,Invoke-AtomicTest T1218 -TestNumbers 5
 T1218 - 6,Invoke-AtomicTest T1218 -TestNumbers 6
 T1218 - 7,Invoke-AtomicTest T1218 -TestNumbers 7
 T1218 - 8,Invoke-AtomicTest T1218 -TestNumbers 8
 T1216 - 1,Invoke-AtomicTest T1216 -TestNumbers 1
 T1216 - 2,Invoke-AtomicTest T1216 -TestNumbers 2
 T1497.001 - 2,Invoke-AtomicTest T1497.001 -TestNumbers 2
 T1221 - 1,Invoke-AtomicTest T1221 -TestNumbers 1
 T1070.006 - 5,Invoke-AtomicTest T1070.006 -TestNumbers 5
 T1070.006 - 6,Invoke-AtomicTest T1070.006 -TestNumbers 6
 T1070.006 - 7,Invoke-AtomicTest T1070.006 -TestNumbers 7
 T1070.006 - 8,Invoke-AtomicTest T1070.006 -TestNumbers 8
 T1134.001 - 1,Invoke-AtomicTest T1134.001 -TestNumbers 1
 T1134.001 - 2,Invoke-AtomicTest T1134.001 -TestNumbers 2
 T1222.001 - 1,Invoke-AtomicTest T1222.001 -TestNumbers 1
 T1222.001 - 2,Invoke-AtomicTest T1222.001 -TestNumbers 2
 T1222.001 - 3,Invoke-AtomicTest T1222.001 -TestNumbers 3
 T1222.001 - 4,Invoke-AtomicTest T1222.001 -TestNumbers 4
 T1222.001 - 5,Invoke-AtomicTest T1222.001 -TestNumbers 5
 T1220 - 1,Invoke-AtomicTest T1220 -TestNumbers 1
 T1220 - 2,Invoke-AtomicTest T1220 -TestNumbers 2
 T1220 - 3,Invoke-AtomicTest T1220 -TestNumbers 3
 T1220 - 4,Invoke-AtomicTest T1220 -TestNumbers 4
 T1546.008 - 1,Invoke-AtomicTest T1546.008 -TestNumbers 1
 T1546.008 - 2,Invoke-AtomicTest T1546.008 -TestNumbers 2
 T1098 - 1,Invoke-AtomicTest T1098 -TestNumbers 1
 T1098 - 2,Invoke-AtomicTest T1098 -TestNumbers 2
 T1137.006 - 1,Invoke-AtomicTest T1137.006 -TestNumbers 1
 T1546.010 - 1,Invoke-AtomicTest T1546.010 -TestNumbers 1
 T1546.011 - 1,Invoke-AtomicTest T1546.011 -TestNumbers 1
 T1546.011 - 2,Invoke-AtomicTest T1546.011 -TestNumbers 2
 T1546.011 - 3,Invoke-AtomicTest T1546.011 -TestNumbers 3
 T1053.002 - 1,Invoke-AtomicTest T1053.002 -TestNumbers 1
 T1197 - 1,Invoke-AtomicTest T1197 -TestNumbers 1
 T1197 - 2,Invoke-AtomicTest T1197 -TestNumbers 2
 T1197 - 3,Invoke-AtomicTest T1197 -TestNumbers 3
 T1197 - 4,Invoke-AtomicTest T1197 -TestNumbers 4
 T1176 - 1,Invoke-AtomicTest T1176 -TestNumbers 1
 T1176 - 2,Invoke-AtomicTest T1176 -TestNumbers 2
 T1176 - 3,Invoke-AtomicTest T1176 -TestNumbers 3
 T1176 - 4,Invoke-AtomicTest T1176 -TestNumbers 4
 T1574.012 - 1,Invoke-AtomicTest T1574.012 -TestNumbers 1
 T1574.012 - 2,Invoke-AtomicTest T1574.012 -TestNumbers 2
 T1574.012 - 3,Invoke-AtomicTest T1574.012 -TestNumbers 3
 T1546.001 - 1,Invoke-AtomicTest T1546.001 -TestNumbers 1
 T1574.001 - 1,Invoke-AtomicTest T1574.001 -TestNumbers 1
 T1574.002 - 1,Invoke-AtomicTest T1574.002 -TestNumbers 1
 T1078.001 - 1,Invoke-AtomicTest T1078.001 -TestNumbers 1
 T1078.001 - 2,Invoke-AtomicTest T1078.001 -TestNumbers 2
 T1136.002 - 1,Invoke-AtomicTest T1136.002 -TestNumbers 1
 T1136.002 - 2,Invoke-AtomicTest T1136.002 -TestNumbers 2
 T1136.002 - 3,Invoke-AtomicTest T1136.002 -TestNumbers 3
 T1133 - 1,Invoke-AtomicTest T1133 -TestNumbers 1
 T1546.012 - 1,Invoke-AtomicTest T1546.012 -TestNumbers 1
 T1546.012 - 2,Invoke-AtomicTest T1546.012 -TestNumbers 2
 T1136.001 - 3,Invoke-AtomicTest T1136.001 -TestNumbers 3
 T1136.001 - 4,Invoke-AtomicTest T1136.001 -TestNumbers 4
 T1136.001 - 6,Invoke-AtomicTest T1136.001 -TestNumbers 6
 T1078.003 - 1,Invoke-AtomicTest T1078.003 -TestNumbers 1
 T1037.001 - 1,Invoke-AtomicTest T1037.001 -TestNumbers 1
 T1546.007 - 1,Invoke-AtomicTest T1546.007 -TestNumbers 1
 T1137 - 1,Invoke-AtomicTest T1137 -TestNumbers 1
 T1137.002 - 1,Invoke-AtomicTest T1137.002 -TestNumbers 1
 T1137.004 - 1,Invoke-AtomicTest T1137.004 -TestNumbers 1
 T1556.002 - 1,Invoke-AtomicTest T1556.002 -TestNumbers 1
 T1574.009 - 1,Invoke-AtomicTest T1574.009 -TestNumbers 1
 T1547.010 - 1,Invoke-AtomicTest T1547.010 -TestNumbers 1
 T1546.013 - 1,Invoke-AtomicTest T1546.013 -TestNumbers 1
 T1547.001 - 1,Invoke-AtomicTest T1547.001 -TestNumbers 1
 T1547.001 - 2,Invoke-AtomicTest T1547.001 -TestNumbers 2
 T1547.001 - 3,Invoke-AtomicTest T1547.001 -TestNumbers 3
 T1547.001 - 4,Invoke-AtomicTest T1547.001 -TestNumbers 4
 T1547.001 - 5,Invoke-AtomicTest T1547.001 -TestNumbers 5
 T1547.001 - 6,Invoke-AtomicTest T1547.001 -TestNumbers 6
 T1547.001 - 7,Invoke-AtomicTest T1547.001 -TestNumbers 7
 T1053.005 - 1,Invoke-AtomicTest T1053.005 -TestNumbers 1
 T1053.005 - 2,Invoke-AtomicTest T1053.005 -TestNumbers 2
 T1053.005 - 3,Invoke-AtomicTest T1053.005 -TestNumbers 3
 T1053.005 - 4,Invoke-AtomicTest T1053.005 -TestNumbers 4
 T1053.005 - 5,Invoke-AtomicTest T1053.005 -TestNumbers 5
 T1053.005 - 6,Invoke-AtomicTest T1053.005 -TestNumbers 6
 T1546.002 - 1,Invoke-AtomicTest T1546.002 -TestNumbers 1
 T1547.005 - 1,Invoke-AtomicTest T1547.005 -TestNumbers 1
 T1574.011 - 1,Invoke-AtomicTest T1574.011 -TestNumbers 1
 T1574.011 - 2,Invoke-AtomicTest T1574.011 -TestNumbers 2
 T1547.009 - 1,Invoke-AtomicTest T1547.009 -TestNumbers 1
 T1547.009 - 2,Invoke-AtomicTest T1547.009 -TestNumbers 2
 T1505.002 - 1,Invoke-AtomicTest T1505.002 -TestNumbers 1
 T1505.003 - 1,Invoke-AtomicTest T1505.003 -TestNumbers 1
 T1546.003 - 1,Invoke-AtomicTest T1546.003 -TestNumbers 1
 T1543.003 - 1,Invoke-AtomicTest T1543.003 -TestNumbers 1
 T1543.003 - 2,Invoke-AtomicTest T1543.003 -TestNumbers 2
 T1543.003 - 3,Invoke-AtomicTest T1543.003 -TestNumbers 3
 T1547.004 - 1,Invoke-AtomicTest T1547.004 -TestNumbers 1
 T1547.004 - 2,Invoke-AtomicTest T1547.004 -TestNumbers 2
 T1547.004 - 3,Invoke-AtomicTest T1547.004 -TestNumbers 3
 T1531 - 1,Invoke-AtomicTest T1531 -TestNumbers 1
 T1531 - 2,Invoke-AtomicTest T1531 -TestNumbers 2
 T1531 - 3,Invoke-AtomicTest T1531 -TestNumbers 3
 T1485 - 1,Invoke-AtomicTest T1485 -TestNumbers 1
 T1486 - 5,Invoke-AtomicTest T1486 -TestNumbers 5
 T1490 - 1,Invoke-AtomicTest T1490 -TestNumbers 1
 T1490 - 2,Invoke-AtomicTest T1490 -TestNumbers 2
 T1490 - 3,Invoke-AtomicTest T1490 -TestNumbers 3
 T1490 - 4,Invoke-AtomicTest T1490 -TestNumbers 4
 T1490 - 5,Invoke-AtomicTest T1490 -TestNumbers 5
 T1490 - 6,Invoke-AtomicTest T1490 -TestNumbers 6
 T1490 - 7,Invoke-AtomicTest T1490 -TestNumbers 7
 T1490 - 8,Invoke-AtomicTest T1490 -TestNumbers 8
 T1491.001 - 1,Invoke-AtomicTest T1491.001 -TestNumbers 1
 T1489 - 1,Invoke-AtomicTest T1489 -TestNumbers 1
 T1489 - 2,Invoke-AtomicTest T1489 -TestNumbers 2
 T1489 - 3,Invoke-AtomicTest T1489 -TestNumbers 3
 T1529 - 1,Invoke-AtomicTest T1529 -TestNumbers 1
 T1529 - 2,Invoke-AtomicTest T1529 -TestNumbers 2
 T1010 - 1,Invoke-AtomicTest T1010 -TestNumbers 1
 T1217 - 4,Invoke-AtomicTest T1217 -TestNumbers 4
 T1217 - 5,Invoke-AtomicTest T1217 -TestNumbers 5
 T1217 - 6,Invoke-AtomicTest T1217 -TestNumbers 6
 T1217 - 7,Invoke-AtomicTest T1217 -TestNumbers 7
 T1087.002 - 1,Invoke-AtomicTest T1087.002 -TestNumbers 1
 T1087.002 - 2,Invoke-AtomicTest T1087.002 -TestNumbers 2
 T1087.002 - 3,Invoke-AtomicTest T1087.002 -TestNumbers 3
 T1087.002 - 4,Invoke-AtomicTest T1087.002 -TestNumbers 4
 T1087.002 - 5,Invoke-AtomicTest T1087.002 -TestNumbers 5
 T1087.002 - 6,Invoke-AtomicTest T1087.002 -TestNumbers 6
 T1087.002 - 7,Invoke-AtomicTest T1087.002 -TestNumbers 7
 T1087.002 - 8,Invoke-AtomicTest T1087.002 -TestNumbers 8
 T1087.002 - 9,Invoke-AtomicTest T1087.002 -TestNumbers 9
 T1087.002 - 10,Invoke-AtomicTest T1087.002 -TestNumbers 10
 T1069.002 - 1,Invoke-AtomicTest T1069.002 -TestNumbers 1
 T1069.002 - 2,Invoke-AtomicTest T1069.002 -TestNumbers 2
 T1069.002 - 3,Invoke-AtomicTest T1069.002 -TestNumbers 3
 T1069.002 - 4,Invoke-AtomicTest T1069.002 -TestNumbers 4
 T1069.002 - 5,Invoke-AtomicTest T1069.002 -TestNumbers 5
 T1069.002 - 6,Invoke-AtomicTest T1069.002 -TestNumbers 6
 T1069.002 - 7,Invoke-AtomicTest T1069.002 -TestNumbers 7
 T1069.002 - 8,Invoke-AtomicTest T1069.002 -TestNumbers 8
 T1482 - 1,Invoke-AtomicTest T1482 -TestNumbers 1
 T1482 - 2,Invoke-AtomicTest T1482 -TestNumbers 2
 T1482 - 3,Invoke-AtomicTest T1482 -TestNumbers 3
 T1482 - 4,Invoke-AtomicTest T1482 -TestNumbers 4
 T1482 - 5,Invoke-AtomicTest T1482 -TestNumbers 5
 T1482 - 6,Invoke-AtomicTest T1482 -TestNumbers 6
 T1482 - 7,Invoke-AtomicTest T1482 -TestNumbers 7
 T1083 - 1,Invoke-AtomicTest T1083 -TestNumbers 1
 T1083 - 2,Invoke-AtomicTest T1083 -TestNumbers 2
 T1087.001 - 8,Invoke-AtomicTest T1087.001 -TestNumbers 8
 T1087.001 - 9,Invoke-AtomicTest T1087.001 -TestNumbers 9
 T1087.001 - 10,Invoke-AtomicTest T1087.001 -TestNumbers 10
 T1069.001 - 2,Invoke-AtomicTest T1069.001 -TestNumbers 2
 T1069.001 - 3,Invoke-AtomicTest T1069.001 -TestNumbers 3
 T1069.001 - 4,Invoke-AtomicTest T1069.001 -TestNumbers 4
 T1069.001 - 5,Invoke-AtomicTest T1069.001 -TestNumbers 5
 T1069.001 - 6,Invoke-AtomicTest T1069.001 -TestNumbers 6
 T1046 - 3,Invoke-AtomicTest T1046 -TestNumbers 3
 T1046 - 4,Invoke-AtomicTest T1046 -TestNumbers 4
 T1135 - 3,Invoke-AtomicTest T1135 -TestNumbers 3
 T1135 - 4,Invoke-AtomicTest T1135 -TestNumbers 4
 T1135 - 5,Invoke-AtomicTest T1135 -TestNumbers 5
 T1135 - 6,Invoke-AtomicTest T1135 -TestNumbers 6
 T1040 - 3,Invoke-AtomicTest T1040 -TestNumbers 3
 T1040 - 4,Invoke-AtomicTest T1040 -TestNumbers 4
 T1201 - 5,Invoke-AtomicTest T1201 -TestNumbers 5
 T1201 - 6,Invoke-AtomicTest T1201 -TestNumbers 6
 T1120 - 1,Invoke-AtomicTest T1120 -TestNumbers 1
 T1057 - 2,Invoke-AtomicTest T1057 -TestNumbers 2
 T1012 - 1,Invoke-AtomicTest T1012 -TestNumbers 1
 T1018 - 1,Invoke-AtomicTest T1018 -TestNumbers 1
 T1018 - 2,Invoke-AtomicTest T1018 -TestNumbers 2
 T1018 - 3,Invoke-AtomicTest T1018 -TestNumbers 3
 T1018 - 4,Invoke-AtomicTest T1018 -TestNumbers 4
 T1018 - 5,Invoke-AtomicTest T1018 -TestNumbers 5
 T1018 - 8,Invoke-AtomicTest T1018 -TestNumbers 8
 T1018 - 9,Invoke-AtomicTest T1018 -TestNumbers 9
 T1018 - 10,Invoke-AtomicTest T1018 -TestNumbers 10
 T1018 - 11,Invoke-AtomicTest T1018 -TestNumbers 11
 T1518.001 - 1,Invoke-AtomicTest T1518.001 -TestNumbers 1
 T1518.001 - 2,Invoke-AtomicTest T1518.001 -TestNumbers 2
 T1518.001 - 5,Invoke-AtomicTest T1518.001 -TestNumbers 5
 T1518.001 - 6,Invoke-AtomicTest T1518.001 -TestNumbers 6
 T1518 - 1,Invoke-AtomicTest T1518 -TestNumbers 1
 T1518 - 2,Invoke-AtomicTest T1518 -TestNumbers 2
 T1497.001 - 2,Invoke-AtomicTest T1497.001 -TestNumbers 2
 T1082 - 1,Invoke-AtomicTest T1082 -TestNumbers 1
 T1082 - 6,Invoke-AtomicTest T1082 -TestNumbers 6
 T1082 - 8,Invoke-AtomicTest T1082 -TestNumbers 8
 T1082 - 9,Invoke-AtomicTest T1082 -TestNumbers 9
 T1082 - 10,Invoke-AtomicTest T1082 -TestNumbers 10
 T1016 - 1,Invoke-AtomicTest T1016 -TestNumbers 1
 T1016 - 2,Invoke-AtomicTest T1016 -TestNumbers 2
 T1016 - 4,Invoke-AtomicTest T1016 -TestNumbers 4
 T1016 - 5,Invoke-AtomicTest T1016 -TestNumbers 5
 T1016 - 6,Invoke-AtomicTest T1016 -TestNumbers 6
 T1016 - 7,Invoke-AtomicTest T1016 -TestNumbers 7
 T1049 - 1,Invoke-AtomicTest T1049 -TestNumbers 1
 T1049 - 2,Invoke-AtomicTest T1049 -TestNumbers 2
 T1049 - 4,Invoke-AtomicTest T1049 -TestNumbers 4
 T1033 - 1,Invoke-AtomicTest T1033 -TestNumbers 1
 T1033 - 3,Invoke-AtomicTest T1033 -TestNumbers 3
 T1007 - 1,Invoke-AtomicTest T1007 -TestNumbers 1
 T1007 - 2,Invoke-AtomicTest T1007 -TestNumbers 2
 T1124 - 1,Invoke-AtomicTest T1124 -TestNumbers 1
 T1124 - 2,Invoke-AtomicTest T1124 -TestNumbers 2
 T1071.004 - 1,Invoke-AtomicTest T1071.004 -TestNumbers 1
 T1071.004 - 2,Invoke-AtomicTest T1071.004 -TestNumbers 2
 T1071.004 - 3,Invoke-AtomicTest T1071.004 -TestNumbers 3
 T1071.004 - 4,Invoke-AtomicTest T1071.004 -TestNumbers 4
 T1573 - 1,Invoke-AtomicTest T1573 -TestNumbers 1
 T1105 - 7,Invoke-AtomicTest T1105 -TestNumbers 7
 T1105 - 8,Invoke-AtomicTest T1105 -TestNumbers 8
 T1105 - 9,Invoke-AtomicTest T1105 -TestNumbers 9
 T1105 - 10,Invoke-AtomicTest T1105 -TestNumbers 10
 T1105 - 11,Invoke-AtomicTest T1105 -TestNumbers 11
 T1105 - 12,Invoke-AtomicTest T1105 -TestNumbers 12
 T1105 - 13,Invoke-AtomicTest T1105 -TestNumbers 13
 T1105 - 15,Invoke-AtomicTest T1105 -TestNumbers 15
 T1105 - 16,Invoke-AtomicTest T1105 -TestNumbers 16
 T1105 - 17,Invoke-AtomicTest T1105 -TestNumbers 17
 T1105 - 18,Invoke-AtomicTest T1105 -TestNumbers 18
 T1090.001 - 3,Invoke-AtomicTest T1090.001 -TestNumbers 3
 T1095 - 1,Invoke-AtomicTest T1095 -TestNumbers 1
 T1095 - 2,Invoke-AtomicTest T1095 -TestNumbers 2
 T1095 - 3,Invoke-AtomicTest T1095 -TestNumbers 3
 T1571 - 1,Invoke-AtomicTest T1571 -TestNumbers 1
 T1572 - 1,Invoke-AtomicTest T1572 -TestNumbers 1
 T1572 - 2,Invoke-AtomicTest T1572 -TestNumbers 2
 T1572 - 3,Invoke-AtomicTest T1572 -TestNumbers 3
 T1219 - 1,Invoke-AtomicTest T1219 -TestNumbers 1
 T1219 - 2,Invoke-AtomicTest T1219 -TestNumbers 2
 T1219 - 3,Invoke-AtomicTest T1219 -TestNumbers 3
 T1219 - 4,Invoke-AtomicTest T1219 -TestNumbers 4
 T1219 - 5,Invoke-AtomicTest T1219 -TestNumbers 5
 T1132.001 - 2,Invoke-AtomicTest T1132.001 -TestNumbers 2
 T1071.001 - 1,Invoke-AtomicTest T1071.001 -TestNumbers 1
 T1071.001 - 2,Invoke-AtomicTest T1071.001 -TestNumbers 2
 T1053.002 - 1,Invoke-AtomicTest T1053.002 -TestNumbers 1
 T1559.002 - 1,Invoke-AtomicTest T1559.002 -TestNumbers 1
 T1559.002 - 2,Invoke-AtomicTest T1559.002 -TestNumbers 2
 T1559.002 - 3,Invoke-AtomicTest T1559.002 -TestNumbers 3
 T1204.002 - 1,Invoke-AtomicTest T1204.002 -TestNumbers 1
 T1204.002 - 2,Invoke-AtomicTest T1204.002 -TestNumbers 2
 T1204.002 - 3,Invoke-AtomicTest T1204.002 -TestNumbers 3
 T1204.002 - 4,Invoke-AtomicTest T1204.002 -TestNumbers 4
 T1204.002 - 5,Invoke-AtomicTest T1204.002 -TestNumbers 5
 T1204.002 - 6,Invoke-AtomicTest T1204.002 -TestNumbers 6
 T1204.002 - 7,Invoke-AtomicTest T1204.002 -TestNumbers 7
 T1204.002 - 8,Invoke-AtomicTest T1204.002 -TestNumbers 8
 T1204.002 - 9,Invoke-AtomicTest T1204.002 -TestNumbers 9
 T1106 - 1,Invoke-AtomicTest T1106 -TestNumbers 1
 T1059.001 - 1,Invoke-AtomicTest T1059.001 -TestNumbers 1
 T1059.001 - 2,Invoke-AtomicTest T1059.001 -TestNumbers 2
 T1059.001 - 3,Invoke-AtomicTest T1059.001 -TestNumbers 3
 T1059.001 - 4,Invoke-AtomicTest T1059.001 -TestNumbers 4
 T1059.001 - 5,Invoke-AtomicTest T1059.001 -TestNumbers 5
 T1059.001 - 6,Invoke-AtomicTest T1059.001 -TestNumbers 6
 T1059.001 - 7,Invoke-AtomicTest T1059.001 -TestNumbers 7
 T1059.001 - 8,Invoke-AtomicTest T1059.001 -TestNumbers 8
 T1059.001 - 9,Invoke-AtomicTest T1059.001 -TestNumbers 9
 T1059.001 - 10,Invoke-AtomicTest T1059.001 -TestNumbers 10
 T1059.001 - 11,Invoke-AtomicTest T1059.001 -TestNumbers 11
 T1059.001 - 12,Invoke-AtomicTest T1059.001 -TestNumbers 12
 T1059.001 - 13,Invoke-AtomicTest T1059.001 -TestNumbers 13
 T1059.001 - 14,Invoke-AtomicTest T1059.001 -TestNumbers 14
 T1059.001 - 15,Invoke-AtomicTest T1059.001 -TestNumbers 15
 T1059.001 - 16,Invoke-AtomicTest T1059.001 -TestNumbers 16
 T1059.001 - 17,Invoke-AtomicTest T1059.001 -TestNumbers 17
 T1059.001 - 18,Invoke-AtomicTest T1059.001 -TestNumbers 18
 T1059.001 - 19,Invoke-AtomicTest T1059.001 -TestNumbers 19
 T1059.001 - 20,Invoke-AtomicTest T1059.001 -TestNumbers 20
 T1059.001 - 21,Invoke-AtomicTest T1059.001 -TestNumbers 21
 T1053.005 - 1,Invoke-AtomicTest T1053.005 -TestNumbers 1
 T1053.005 - 2,Invoke-AtomicTest T1053.005 -TestNumbers 2
 T1053.005 - 3,Invoke-AtomicTest T1053.005 -TestNumbers 3
 T1053.005 - 4,Invoke-AtomicTest T1053.005 -TestNumbers 4
 T1053.005 - 5,Invoke-AtomicTest T1053.005 -TestNumbers 5
 T1053.005 - 6,Invoke-AtomicTest T1053.005 -TestNumbers 6
 T1569.002 - 1,Invoke-AtomicTest T1569.002 -TestNumbers 1
 T1569.002 - 2,Invoke-AtomicTest T1569.002 -TestNumbers 2
 T1072 - 1,Invoke-AtomicTest T1072 -TestNumbers 1
 T1059.005 - 1,Invoke-AtomicTest T1059.005 -TestNumbers 1
 T1059.005 - 2,Invoke-AtomicTest T1059.005 -TestNumbers 2
 T1059.005 - 3,Invoke-AtomicTest T1059.005 -TestNumbers 3
 T1059.003 - 1,Invoke-AtomicTest T1059.003 -TestNumbers 1
 T1059.003 - 2,Invoke-AtomicTest T1059.003 -TestNumbers 2
 T1059.003 - 3,Invoke-AtomicTest T1059.003 -TestNumbers 3
 T1047 - 1,Invoke-AtomicTest T1047 -TestNumbers 1
 T1047 - 2,Invoke-AtomicTest T1047 -TestNumbers 2
 T1047 - 3,Invoke-AtomicTest T1047 -TestNumbers 3
 T1047 - 4,Invoke-AtomicTest T1047 -TestNumbers 4
 T1047 - 5,Invoke-AtomicTest T1047 -TestNumbers 5
 T1047 - 6,Invoke-AtomicTest T1047 -TestNumbers 6
 T1047 - 7,Invoke-AtomicTest T1047 -TestNumbers 7
 T1047 - 8,Invoke-AtomicTest T1047 -TestNumbers 8
 T1047 - 9,Invoke-AtomicTest T1047 -TestNumbers 9
 T1020 - 1,Invoke-AtomicTest T1020 -TestNumbers 1
 T1048 - 3,Invoke-AtomicTest T1048 -TestNumbers 3
 T1041 - 1,Invoke-AtomicTest T1041 -TestNumbers 1
 T1048.003 - 2,Invoke-AtomicTest T1048.003 -TestNumbers 2
 T1048.003 - 4,Invoke-AtomicTest T1048.003 -TestNumbers 4
 T1048.003 - 5,Invoke-AtomicTest T1048.003 -TestNumbers 5
 T1567 - 1,Invoke-AtomicTest T1567 -TestNumbers 1
 T1021.003 - 1,Invoke-AtomicTest T1021.003 -TestNumbers 1
 T1550.002 - 1,Invoke-AtomicTest T1550.002 -TestNumbers 1
 T1550.002 - 2,Invoke-AtomicTest T1550.002 -TestNumbers 2
 T1550.003 - 1,Invoke-AtomicTest T1550.003 -TestNumbers 1
 T1563.002 - 1,Invoke-AtomicTest T1563.002 -TestNumbers 1
 T1021.001 - 1,Invoke-AtomicTest T1021.001 -TestNumbers 1
 T1021.001 - 2,Invoke-AtomicTest T1021.001 -TestNumbers 2
 T1021.001 - 3,Invoke-AtomicTest T1021.001 -TestNumbers 3
 T1021.001 - 4,Invoke-AtomicTest T1021.001 -TestNumbers 4
 T1021.002 - 1,Invoke-AtomicTest T1021.002 -TestNumbers 1
 T1021.002 - 2,Invoke-AtomicTest T1021.002 -TestNumbers 2
 T1021.002 - 3,Invoke-AtomicTest T1021.002 -TestNumbers 3
 T1021.002 - 4,Invoke-AtomicTest T1021.002 -TestNumbers 4
 T1072 - 1,Invoke-AtomicTest T1072 -TestNumbers 1
 T1021.006 - 1,Invoke-AtomicTest T1021.006 -TestNumbers 1
 T1021.006 - 2,Invoke-AtomicTest T1021.006 -TestNumbers 2
 T1021.006 - 3,Invoke-AtomicTest T1021.006 -TestNumbers 3
 T1078.001 - 1,Invoke-AtomicTest T1078.001 -TestNumbers 1
 T1078.001 - 2,Invoke-AtomicTest T1078.001 -TestNumbers 2
 T1133 - 1,Invoke-AtomicTest T1133 -TestNumbers 1
 T1078.003 - 1,Invoke-AtomicTest T1078.003 -TestNumbers 1
 T1566.001 - 1,Invoke-AtomicTest T1566.001 -TestNumbers 1
 T1566.001 - 2,Invoke-AtomicTest T1566.001 -TestNumbers 2
 ''')
 LET CommandsToRun &amp;lt;= if(condition=RunAll, then='''Invoke-AtomicTest All -Confirm:$false''', else={ SELECT Command FROM CommandTable WHERE get(field=Flag)})

 LET RemoveLog &amp;lt;= if(condition=RemoveExecLog, then={ SELECT * FROM execve(argv=["powershell.exe", "Remove-Item", ExecutionLogFile])})

 LET InstallART &amp;lt;= if(condition=InstallART, then={ SELECT * FROM execve(argv=[ 'powershell.exe', '-exec', 'bypass',
 '-Command', "IEX (IWR https://raw.githubusercontent.com/redcanaryco/invoke-atomicredteam/master/install-atomicredteam.ps1 -UseBasicParsing); Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser; Install-AtomicRedTeam -getAtomics -F"
 ])})

 LET JustDoIt &amp;lt;= SELECT * FROM foreach(row=CommandsToRun, query={
 SELECT * FROM execve(argv=[ 'powershell.exe', '-exec', 'bypass',
 '-Command', '''Import-Module "C:\AtomicRedTeam\invoke-atomicredteam\Invoke-AtomicRedTeam.psd1" -Force; ''' + Command + ''' -GetPreReqs; ''' + Command + ''' -ExecutionLogPath ''' + ExecutionLogFile + ''';''' + if(condition=Cleanup, then=Command + ''' -Cleanup''', else='''''')
 ])}

 )

 SELECT `Execution Time (UTC)`, `Execution Time (Local)`, '[' + Technique + '](https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/' + Technique + '/' + Technique + '.md)' AS Technique, `Test Number`, `Test Name`, Hostname, Username, GUID FROM parse_csv(accessor="file", filename=ExecutionLogFile)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Audit.CISCat_Lite</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.audit.ciscat_lite/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.audit.ciscat_lite/</guid><description>&lt;p&gt;This artifact runs the CISCat-Lite tool on the target machine and
uploads the html output on the velociraptor server.&lt;/p&gt;
&lt;p&gt;CIS-CAT Lite is a free tool from the Center for Internet Security
that helps in assessing and improving IT security configurations.
It enables unlimited system scans, provides compliance scores, and
offers remediation steps based on CIS Benchmarks. This tool is
useful for organizations seeking to enhance their technology
security.&lt;/p&gt;
&lt;p&gt;The artifact has been configured to perform a standard scan of a
Windows 10 Enterprise machine. To select the baseline and profiles,
execute the command &amp;ldquo;.\Assessor-CLI.bat -i&amp;rdquo;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Audit.CISCat_Lite
description: |
 This artifact runs the CISCat-Lite tool on the target machine and
 uploads the html output on the velociraptor server.

 CIS-CAT Lite is a free tool from the Center for Internet Security
 that helps in assessing and improving IT security configurations.
 It enables unlimited system scans, provides compliance scores, and
 offers remediation steps based on CIS Benchmarks. This tool is
 useful for organizations seeking to enhance their technology
 security.

 The artifact has been configured to perform a standard scan of a
 Windows 10 Enterprise machine. To select the baseline and profiles,
 execute the command ".\Assessor-CLI.bat -i"
type: CLIENT

author: Antonio Blescia (TheThMando)

implied_permissions:
 - EXECVE
 - FILESYSTEM_WRITE

parameters:
 - name: BaselinePath
 default: "./Assessor/benchmarks/CIS_Microsoft_Windows_10_Enterprise_Benchmark_v4.0.0-xccdf.xml"
 - name: ProfileName
 default: "Level 1 (L1)"

tools:
 - name: CISCat_Lite
 url: https://workbench.cisecurity.org/api/vendor/v1/cis-cat/lite/latest

sources:
 - name: CISOutput
 query: |
 -- Generate the temp dir
 LET TmpDir &amp;lt;= tempdir(remove_last=true)
 -- Upload the CISCat_Lite tool on the host
 LET Toolzip &amp;lt;= SELECT OSPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="CISCat_Lite",
 IsExecutable=FALSE)
 -- Extract the CISCat_Lite tool zip
 LET _ &amp;lt;= SELECT *
 FROM unzip(filename=Toolzip.OSPath, output_directory=TmpDir, type="zip")
 WHERE FALSE

 -- Generate the absolute path that points the the extracted tool location
 LET CISCatPath = path_join(
 components=[TmpDir, 'Assessor', 'Assessor-CLI.bat'],
 path_type='windows')

 -- Run the command
 SELECT *
 FROM execve(argv=[CISCatPath, "-b", path_join(components=[TmpDir, BaselinePath]), '-p', ProfileName])

 - query: |
 SELECT *
 FROM foreach( row={
 SELECT OSPath
 FROM glob(
 globs='/Assessor/reports/*.html', root=TmpDir)
 WHERE NOT IsDir
 }, query={
 SELECT OSPath, upload(file=OSPath) AS Upload
 FROM scope()
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Binary.Exports</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/exports/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/exports/</guid><description>&lt;p&gt;This artifact can be used to extract all binary exports to research
potential lolbins. Selecting the AllBinaryInfo tickbox will return
complete Binary information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Binary.Exports
author: Matt Green - @mgreen27
description: |
 This artifact can be used to extract all binary exports to research
 potential lolbins. Selecting the AllBinaryInfo tickbox will return
 complete Binary information.

type: CLIENT

parameters:
 - name: TargetGlob
 default: C:/ProgramData/*
 description: Glob to target
 - name: AllBinaryInfo
 type: bool
 description: Select to extract all binary info

sources:
 - query: |
 Let Targets = SELECT * FROM glob(globs=TargetGlob)
 WHERE NOT IsDir

 LET all_binary_info = SELECT
 dict(OSPath=OSPath,Name=Name,Size=Size,IsLink=IsLink) as FileDetails,
 dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as SI,
 parse_pe(file=OSPath) as BinaryInfo,
 authenticode(filename=OSPath) as Authenticode,
 hash(path=OSPath) as Hash
 FROM Targets
 WHERE BinaryInfo

 LET binary_exports = SELECT
 dict(OSPath=OSPath,Name=Name,Size=Size,IsLink=IsLink) as FileDetails,
 parse_pe(file=OSPath).Exports as Exports
 FROM Targets
 WHERE Exports

 SELECT * FROM if(condition=AllBinaryInfo,
 then=all_binary_info,
 else=binary_exports)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Bulk.File</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/bulkfile/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/bulkfile/</guid><description>&lt;p&gt;Search for some simple bulk File IOCs and upload if desired.
Typical upload workflow may be to firstly search, then if returned
rows match expectations rerun query with upload tickbox selected.&lt;/p&gt;
&lt;p&gt;NOTE: strings with comma &amp;ldquo;,&amp;rdquo; requre quotes.&lt;/p&gt;
&lt;p&gt;IocLookupTable csv details:&lt;/p&gt;
&lt;p&gt;Glob - &amp;ldquo;Quote&amp;rdquo; items with { glob } barckets.
Whitelist - Velociraptor regex to whitelist FullPath field.
Description - Free text&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Bulk.File
author: Matt Green - @mgreen27
description: |
 Search for some simple bulk File IOCs and upload if desired.
 Typical upload workflow may be to firstly search, then if returned
 rows match expectations rerun query with upload tickbox selected.

 NOTE: strings with comma "," requre quotes.

 IocLookupTable csv details:

 Glob - "Quote" items with { glob } barckets.
 Whitelist - Velociraptor regex to whitelist FullPath field.
 Description - Free text

parameters:
 - name: UploadHits
 description: Upload hits to server.
 type: bool
 - name: Accessor
 type: choices
 default: auto
 choices:
 - auto
 - ntfs
 - file
 - name: IocLookupTable
 type: csv
 default: |
 TargetGlob,IgnoreRegex,Description
 "C:\intel\Logs\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Carbanak staging location
 "C:\users\public\temp\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Carbanak staging location
 "C:\Windows\SystemApps\*\*.{ps1,vbs,js,bat,cpl}",,Carbanak staging location
 "C:\windows\temp\temp1\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Carbanak staging location
 "C:\Windows\System32\spool*\*.{ps1,vbs,js,bat,cpl}",,Common staging location
 "C:\Perflogs\**\*.{lnk,ps1,vbs,js,exe,dll,bat,cpl,zip,7z,rar}",\.(ini|txt|zip|etl|html|xml|xsl|log|blg)$,Staging location
 "C:\ProgramData\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Staging location
 "C:\ProgramData\.*\*.{bin,dat,txt,log,ps1,vbs,js,exe,dll,bat,cpl}",,Copy-Paste staging location
 "C:\Users\Public\**\*.{lnk,ps1,vbs,js,exe,dll,bat,cpl,zip,7z,rar}",C:\\Users\\Public\\Desktop\\[\\]+\.lnk,Staging location
 "C:\Users\*\Sounds\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Investigation staging
 "C:\Windows\Temp\winsyslog\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Current investigation X1002
 "C:\Windows\Help\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Staging location
 "C:\Windows\twain_32\*.{ps1,vbs,js,exe,dll,bat,cpl}",,Staging location

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

 query: |
 -- extract IOCs from lookupTable
 LET hits = SELECT * FROM foreach(
 row=IocLookupTable,
 query={
 SELECT
 OSPath,
 Name,
 dict(
 TargetGlob=TargetGlob,
 IgnoreRegex=IgnoreRegex,
 Description=Description
 ) as IocDetails,
 timestamp(epoch=Mtime) as Mtime,
 timestamp(epoch=Atime) as Atime,
 timestamp(epoch=Ctime) as Ctime,
 timestamp(epoch=Btime) as Btime,
 Size,
 IsLink
 FROM glob(globs=TargetGlob,accessor=Accessor)
 WHERE NOT IsDir
 AND NOT if(condition=IgnoreRegex,
 then=OSPath =~ IgnoreRegex,
 else=FALSE)
 })

 -- upload hits
 LET upload_hits = SELECT *, upload(file=OSPath) FROM hits

 -- output rows
 SELECT *,
 hash(path=OSPath) as Hash
 FROM if(condition=UploadHits,
 then= upload_hits,
 else= hits)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Carving.BRc4</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/brc4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/brc4/</guid><description>&lt;p&gt;This artifact extracts Brute Ratel C4 (BRc4) configuration from a byte stream,
process or file on disk. BRc4 is an emerging red-teaming and adversarial
attack simulation tool.&lt;/p&gt;
&lt;p&gt;The User can define bytes, file glob, process name or pid regex as a target.
The artifact firstly discovers BruteRatel configuration and extracts bytes,
before parsing with Velociraptor Binary Parser.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BRc4&amp;rsquo;s configuration consits of 8 characters inside several sections.&lt;/li&gt;
&lt;li&gt;Character lists reversed in order&lt;/li&gt;
&lt;li&gt;This list of characters is: either base64 + RC4 encoded or in clear text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This content simply carves the configuration and does not unpack files on
disk. That means pointing this artifact as a packed or obfuscated file may not
obtain the expected results.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Carving.BRc4
author: Matt Green - @mgreen27
description: |
 This artifact extracts Brute Ratel C4 (BRc4) configuration from a byte stream, 
 process or file on disk. BRc4 is an emerging red-teaming and adversarial 
 attack simulation tool.
 
 The User can define bytes, file glob, process name or pid regex as a target.
 The artifact firstly discovers BruteRatel configuration and extracts bytes, 
 before parsing with Velociraptor Binary Parser.
 
 * BRc4's configuration consits of 8 characters inside several sections. 
 * Character lists reversed in order
 * This list of characters is: either base64 + RC4 encoded or in clear text. 
 
 This content simply carves the configuration and does not unpack files on
 disk. That means pointing this artifact as a packed or obfuscated file may not
 obtain the expected results.

reference:
 - https://unit42.paloaltonetworks.com/brute-ratel-c4-tool/
 - https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools
 

parameters:
 - name: TargetBytes
 default:
 - name: TargetFileGlob
 default:
 - name: PidRegex
 default: .
 type: regex
 - name: ProcessRegex
 default: .
 type: regex
 - name: DecodeKey
 default: "bYXJm/3#M?:XyMBF"
 - name: FindConfig
 type: hidden
 description: Final Yara option and the default if no other options provided.
 default: |
 rule BruteRatelConfig
 {
 strings:
 $config_block = { 50 48 b8 [8] 50 68}
 $split_marker = { 50 48 b8 [8] 50 48 b8 }
 
 condition:
 $config_block and #split_marker &amp;gt; 30
 }


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

 query: |
 -- dynamic functions to reverse list order
 LET _Reverse(data) = SELECT *, count() as Count FROM foreach(row=data) ORDER BY Count desc
 LET Reverse(data) = _Reverse(data=data)._value

 -- binary parse profile to extract BRc4 configuration. NOTE: need reverse dynamic fuctions above
 LET PROFILE = '''[
 [BRc4Config, 0, [
 ["__FindConfig",0, "String",{term_hex: "5048b8"}],
 ["Reversed","x=&amp;gt;len(list=x.__FindConfig) + 3", "String", { term_hex: "5068" }],
 ["ConfigData",0,"Value",{ "value": "x=&amp;gt;join(array=Reverse(data=split(string=x.Reversed,sep_string=unhex(string='5048b8'))))" }],
 ["DecodedConfig",0,"Value",{ "value": "x=&amp;gt;crypto_rc4(string=base64decode(string=x.ConfigData),key=DecodeKey)" }],
 ["Config",0,"Value",{ "value": "x=&amp;gt;if(condition= x.DecodedConfig, then=x.DecodedConfig, else=x.ConfigData)" }],
 ]
 ]]'''
 
 -- Bytes usecase: scan DataBytes for BRc4 config
 LET ByteConfiguration = SELECT
 Rule,
 len(list=TargetBytes) as Size,
 hash(path=TargetBytes,accessor='data') as Hash,
 String.Offset as HitOffset,
 parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
 FROM yara(
 files=TargetBytes,
 accessor='data',
 rules=FindConfig,
 number=1,
 context=1000
 )
 
 -- Glob usecase: find target files
 LET TargetFiles = SELECT OSPath,Size
 FROM glob(globs=TargetFileGlob) WHERE NOT IsDir

 -- Glob usecase: Extract config from files in scope
 LET FileConfiguration = SELECT * FROM foreach(row=TargetFiles,
 query={
 SELECT 
 Rule,
 OSPath, Size,
 hash(path=OSPath) as Hash,
 String.Offset as HitOffset,
 parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
 FROM yara(
 files=OSPath,
 rules=FindConfig,
 number=1,
 context=1000
 )
 })
 
 -- find velociraptor process
 LET me &amp;lt;= SELECT * FROM if(condition= NOT ( TargetFileGlob OR TargetBytes ),
 then = { SELECT Pid FROM pslist(pid=getpid()) })

 -- find all processes and add filters
 LET processes = SELECT Name as ProcessName, Exe, CommandLine, Pid
 FROM pslist()
 WHERE
 Name =~ ProcessRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND NOT Pid in me.Pid
 
 -- scan processes in scope with our rule, limit 1 hit and extract context to parse
 LET ProcessConfiguration = SELECT * FROM foreach(
 row=processes,
 query={
 SELECT
 Rule,
 Pid, ProcessName, CommandLine,
 String.Offset as HitOffset,
 parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
 FROM yara( 
 files=format(format="/%d", args=Pid),
 accessor='process',
 rules=FindConfig,
 number=1,
 context=1000
 )
 })


 -- generate results remove any FPs
 SELECT *,
 { 
 SELECT _value 
 FROM foreach(row=split(string=_RawConfig,sep_string='|')) 
 WHERE _value 
 } as BRc4Config, 
 _RawConfig
 FROM if(condition=TargetBytes,
 then=ByteConfiguration,
 else= if(condition=TargetFileGlob,
 then= FileConfiguration,
 else= ProcessConfiguration))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Carving.BumbleBee</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/bumblebee/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/bumblebee/</guid><description>&lt;p&gt;This artficat will detect running BumbleBee processes and subsequently extract the command and control servers with the destination port 443.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Carving.BumbleBee
author: Angelo Violetti @SEC Defence
type: CLIENT
description: |
 This artficat will detect running BumbleBee processes and subsequently extract the command and control servers with the destination port 443.
reference:
 - sec-consult.com/blog/detail/bumblebee-hunting-with-a-velociraptor/
parameters:
 - name: TargetFileGlob
 default:
 - name: PidRegex
 default: .
 - name: ProcessRegex
 default: .
 - name: DetectionYara
 default: |
 rule BumbleBee_Unpacked{
 meta:
 author = "Angelo Violetti @ SEC Defence"
 date = "2023-02-23"
 
 strings:
 $s1 = {?? 83 ?? 18 10 72 03 ?? 8B ?? 44 8B ?? 48 8B ?? 48 8D 4C 24 30 E8 ?? ?? FF FF 90}
 $s2 = {48 8D 4C 24 30 E8 ?? ?? FF FF 90}
 $s3 = {48 8d 4c 24 30 e8 ?? ?? FF FF}
 
 condition:
 all of ($s*)
 }
 
 - name: ExtractIPsYara
 default: |
 rule BumbleBee_IPs{
 meta:
 author = "Angelo Violetti @ SEC Defence"
 date = "2023-02-23"
 description = "Extracts the IP addresses with the destination port equal to 443 from BumbleBee processes"
 
 strings:
 $IP = {?? ?? ?? 2e ?? ?? ?? 2e ?? ?? ?? 2e ?? ?? ?? 00 (?? | ?? ??) 00 00 00 00 00 00 00 0f 00 00 00 00 00 00 00 34 34 33 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 0F 00 00 00 00 00 00 00}
 condition:
 $IP
 }

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

 query: |
 -- Find velociraptor process
 LET me &amp;lt;= getpid()

 -- Find all processes and add filters
 LET processes = SELECT Name AS ProcessName, CommandLine, Pid
 FROM pslist()
 WHERE Name =~ ProcessRegex
 AND Pid =~ PidRegex
 AND NOT Pid in me.Pid

 -- Scan processes in scope with our DetectionYara
 LET processDetections = SELECT * FROM foreach(row=processes,
 query={
 SELECT * FROM if(condition=TargetFileGlob="",
 then={
 SELECT *, ProcessName, CommandLine, Pid, Rule AS YaraRule
 FROM proc_yara(pid=Pid, rules=DetectionYara)
 })
 })
 
 -- Scan the process for the IP addresses
 LET ipaddressDetections = SELECT ProcessName, CommandLine, Pid, Strings.Data AS IPAddresses FROM foreach(row=processDetections, query={SELECT *, ProcessName, CommandLine, Pid FROM proc_yara(pid=Pid, rules=ExtractIPsYara)})
 
 -- Extract the command and control servers
 LET CommandandControlServers = SELECT * FROM foreach(row=ipaddressDetections, query={SELECT ProcessName, CommandLine, Pid, g1 FROM parse_records_with_regex(accessor="data", file=IPAddresses, regex='''(\d+\.\d+\.\d+\.\d+)''')})

 -- Output the command and control servers
 SELECT ProcessName, CommandLine, Pid, str(str=g1) AS BumbleBeeC2 FROM CommandandControlServers

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Carving.Qakbot</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/qakbot/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/qakbot/</guid><description>&lt;p&gt;This artifact enables Qakbot payload detection and configuration extraction
from a byte stream, process or file on disk. The artifact runs a yara scan
as a detection step, then attempts to process the payload to extract
configuration.&lt;/p&gt;
&lt;p&gt;QakBot or QBot, is a modular malware first observed in 2007 that has been
historically known as a banking Trojan. Qbot is used to steal credentials,
financial, or other data, and in recent years, regularly a loader for other
malware leading to hands on keyboard ransomware.&lt;/p&gt;
&lt;p&gt;Qakbot (Qbot) payloads have an RC4 encoded configuration, located inside two
PE resources. Encoded strings and xor key can also be found inside the .data
section starting at a specific offset.&lt;/p&gt;
&lt;p&gt;Some of the options available cover changes observed in the last year in the
decryption process to allow simplified decoding workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;StringOffset - the offset of the string xor key and encoded strings.&lt;/li&gt;
&lt;li&gt;PE resource type - the configuration is typically inside 2 resources.&lt;/li&gt;
&lt;li&gt;Unescaped key string - this field is typically reused over samples&lt;/li&gt;
&lt;li&gt;Type of encoding: single or double, double being the more recent.&lt;/li&gt;
&lt;li&gt;Worker threads for bulk analysis / research use cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The decryption used is fairly simple with the first pass RC4 found in
encoded strings embedded in the malware and is often reused from previous
samples.&lt;/p&gt;
&lt;p&gt;Each decoded output includes the first 20 bytes in hex as the SHA1 of the
data as verification. The second pass RC4 key is the next 20 bytes in hex,
Second pass RC4 decoding has the same verification of decrypted data.&lt;/p&gt;
&lt;p&gt;NOTE: Requires 0.6.8 for PE dump&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Carving.Qakbot
author: Matt Green - @mgreen27
description: |
 This artifact enables Qakbot payload detection and configuration extraction
 from a byte stream, process or file on disk. The artifact runs a yara scan
 as a detection step, then attempts to process the payload to extract
 configuration.

 QakBot or QBot, is a modular malware first observed in 2007 that has been
 historically known as a banking Trojan. Qbot is used to steal credentials,
 financial, or other data, and in recent years, regularly a loader for other
 malware leading to hands on keyboard ransomware.

 Qakbot (Qbot) payloads have an RC4 encoded configuration, located inside two
 PE resources. Encoded strings and xor key can also be found inside the .data
 section starting at a specific offset.

 Some of the options available cover changes observed in the last year in the
 decryption process to allow simplified decoding workflow:

 - StringOffset - the offset of the string xor key and encoded strings.
 - PE resource type - the configuration is typically inside 2 resources.
 - Unescaped key string - this field is typically reused over samples
 - Type of encoding: single or double, double being the more recent.
 - Worker threads for bulk analysis / research use cases.

 The decryption used is fairly simple with the first pass RC4 found in
 encoded strings embedded in the malware and is often reused from previous
 samples.

 Each decoded output includes the first 20 bytes in hex as the SHA1 of the
 data as verification. The second pass RC4 key is the next 20 bytes in hex,
 Second pass RC4 decoding has the same verification of decrypted data.

 NOTE: Requires 0.6.8 for PE dump

reference:
 - https://malpedia.caad.fkie.fraunhofer.de/details/win.qakbot
 - https://docs.velociraptor.app/blog/2023/2023-04-05-qakbot/
type: CLIENT


parameters:
 - name: TargetBytes
 description: Parameter to enabling piping a byte stream of a payload dll
 default:
 type: hidden
 - name: TargetGlob
 description: Glob to target payloads on disk
 default:
 - name: PidRegex
 description: Regex of target Process ID to scan
 default: .
 type: regex
 - name: ProcessRegex
 description: Regex of target Process Name to scan
 type: regex
 - name: StringOffset
 description: Offset of beginning of encoded strings in .data section.
 default: 0x50
 type: int
 - name: ResourceRegex
 description: Regex to select targeted PE resource name.
 default: 'BITMAP|RCDATA'
 - name: Keys
 description: Lookup table of recent Keys. Add additional keys to extend capability.
 type: csv
 default: |
 Type,Key
 double,Muhcu#YgcdXubYBu2@2ub4fbUhuiNhyVtcd
 double,bUdiuy81gYguty@4frdRdpfko(eKmudeuMncueaN
 single,\System32\WindowsPowerShel1\v1.0\powershel1.exe
 single,\System32\WindowsPowerShell\v1.0\powershell.exe
 - name: Workers
 description: Number of workers to run. For bulk usecase increase to improve performance.
 default: 1
 type: int
 - name: YaraRule
 description: Yara rule to detect Qakbot payload.
 type: hidden
 default: |
 rule win_qakbot {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2023-01-25"
 description = "Detects win.qakbot."
 strings:
 $sequence_0 = { 50 e8???????? 8b06 47 }
 $sequence_1 = { e9???????? 33c0 7402 ebfa }
 $sequence_2 = { 740d 8d45fc 6a00 50 }
 $sequence_3 = { 8b06 47 59 59 }
 $sequence_4 = { eb13 e8???????? 33c9 85c0 0f9fc1 41 }
 $sequence_5 = { 7402 ebfa 33c0 7402 }
 $sequence_6 = { 0fb64903 c1e008 0bc2 c1e008 0bc1 c3 55 }
 $sequence_7 = { ebfa eb06 33c0 7402 }
 $sequence_8 = { 8d45fc 6aff 50 e8???????? 59 59 }
 $sequence_9 = { 59 59 6afb e9???????? }
 $sequence_10 = { 48 50 8d8534f6ffff 6a00 50 }
 $sequence_11 = { 5e c9 c3 55 8bec 81ecc4090000 }
 $sequence_12 = { e8???????? 83c410 33c0 7402 }
 $sequence_13 = { 7cef eb10 c644301c00 ff465c 8b465c 83f838 }
 $sequence_14 = { eb0b c644301c00 ff465c 8b465c 83f840 7cf0 }
 $sequence_15 = { c644061c00 ff465c 837e5c38 7cef eb10 c644301c00 }
 $sequence_16 = { 7507 c7466401000000 83f840 7507 }
 $sequence_17 = { 85c0 750a 33c0 7402 }
 $sequence_18 = { 72b6 33c0 5f 5e 5b c9 c3 }
 $sequence_19 = { 7402 ebfa e9???????? 6a00 }
 $sequence_20 = { c7466001000000 33c0 40 5e }
 $sequence_21 = { 6afe 8d45f4 50 e8???????? }
 $sequence_22 = { 7402 ebfa eb0d 33c0 }
 $sequence_23 = { 50 ff5508 8bf0 59 }
 $sequence_24 = { 57 ff15???????? 33c0 85f6 0f94c0 }
 $sequence_25 = { ff15???????? 85c0 750c 57 ff15???????? 6afe }
 $sequence_26 = { c3 33c9 3d80000000 0f94c1 }
 $sequence_27 = { 6a02 ff15???????? 8bf8 83c8ff }
 $sequence_28 = { 6a00 58 0f95c0 40 50 }
 $sequence_29 = { e8???????? 33c0 c3 55 8bec 51 51 }
 $sequence_30 = { 7412 8d85d8feffff 50 57 ff15???????? }
 $sequence_31 = { 00e9 8b55e4 880c1a 8a4df3 }
 $sequence_32 = { 00ca 66897c2446 31f6 8974244c }
 $sequence_33 = { 01c1 894c2430 e9???????? 55 }
 $sequence_34 = { 01c1 81e1ffff0000 83c101 8b442474 }
 $sequence_35 = { 00e9 884c0451 83c001 39d0 }
 $sequence_36 = { 01c1 8b442448 01c8 8944243c }
 $sequence_37 = { 01c1 894c2404 8b442404 8d65fc }
 $sequence_38 = { 01c1 21d1 8a442465 f6642465 }
 condition:
 7 of them and filesize &amp;lt; 1168384
 }


sources:
 - query: |
 -- parses PE and extracts EncodedStrings from the.data section
 LET encoded_strings(data) = SELECT
 strip(suffix='\x00\x00', string=_value) as Sections
 FROM foreach(row=split(sep='\x00\x00\x00\x00',string=data))
 WHERE Sections
 LET find_data(data) = SELECT
 encoded_strings(data=read_file(filename=data,accessor='data',offset=FileOffset,length=Size)[StringOffset:]).Sections as EncodedStrings
 FROM foreach(row=parse_pe(file=data,accessor='data').Sections,
 query={ SELECT * FROM _value })
 WHERE Name = '.data'

 -- decodes strings only show printable
 LET decode_strings(data) = SELECT * FROM foreach(
 row={
 SELECT count() - 1 as Index
 FROM range(start=0, end=len(list=data))},
 query={
 SELECT
 filter(
 list=split(sep='\x00',string=xor(key=data[Index],string=_value)),
 regex="^[ -~]{2,}$" ) as String
 FROM foreach(row=data[Index:])
 WHERE len(list=String) &amp;gt; 2
 AND NOT String =~ '^\\s+$'
 })

 -- parses PE and extracts resource sections
 LET find_resource(data) = SELECT Type, TypeId,
 FileOffset,
 DataSize,
 read_file(filename=data,accessor='data',offset=FileOffset,length=DataSize) as Data
 FROM foreach(row=parse_pe(file=data,accessor='data').Resources)
 WHERE Type =~ ResourceRegex
 ORDER BY DataSize

 -- first round of RC4 encoding. Verification hash is hex of first 20 bytes
 LET rc4_wth_hashed_key(data,key) =
 crypto_rc4(
 key = unhex(string=hash(path=key,accessor='data',hashselect='SHA1').SHA1),
 string = data )
 -- second round of RC4 encoding accounting for verification.
 LET advanced_method(data,key)=
 crypto_rc4(
 key = rc4_wth_hashed_key(data=data,key=key)[20:40],
 string = rc4_wth_hashed_key(data=data,key=key)[40:] )

 -- this function finds key and verifies results.
 LET decode(data) = SELECT Key,Type,
 if(condition= Type='single',
 then= rc4_wth_hashed_key(data=data,key=Key),
 else= advanced_method(data=data,key=Key)) as Data
 FROM Keys
 WHERE format(format='%x',args=Data[:20]) = hash(path=Data[20:],accessor='data',hashselect='SHA1').SHA1
 LIMIT 1

 -- find netaddress method with the most expected standard ports.
 LET find_c2(methods) = SELECT _value as C2,
 len(list=filter(list=_value,regex=':(443|80|([0-9])\1{4,})$')) as Total
 FROM foreach(row=methods) ORDER BY Total DESC
 LIMIT 1

 -- bytestream: only works on a payload dll as bytestream
 LET bytestream = SELECT Rule as Detection,
 hash(path=TargetBytes, accessor='data') as DataBytes,
 len(list=TargetBytes) as Size,
 find_resource(data=TargetBytes) as Resources,
 find_data(data=TargetBytes)[0].EncodedStrings as DecodedStrings
 FROM yara( files=TargetBytes,
 accessor='data',
 rules=YaraRule, key='X',
 number=1 )

 -- find target files
 LET target_files = SELECT OSPath, Size,
 Mtime, Btime, Ctime, Atime
 FROM glob(globs=TargetGlob)
 WHERE NOT IsDir AND Size &amp;gt; 0

 -- search for qakbot in scoped files
 LET file_payloads = SELECT * FROM foreach(row= target_files,
 query={
 SELECT
 Rule as Detection,
 OSPath,Size,
 dict(
 Mtime = Mtime,
 Atime = Atime,
 Ctime = Ctime,
 Btime = Btime
 ) as Timestamps,
 find_resource(data=read_file(filename=OSPath)) as Resources,
 find_data(data=read_file(filename=OSPath))[0].EncodedStrings as DecodedStrings
 FROM yara( files=OSPath,
 rules=YaraRule,
 end=Size, key='X',
 number=1 )
 })
 WHERE log(message="Scanning file : %v", args=OSPath)

 -- find processes in scope of query
 LET processes = SELECT int(int=Pid) AS Pid,
 Name, Exe, CommandLine, CreateTime,Username
 FROM process_tracker_pslist()
 WHERE Name =~ ProcessRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND log(message="Scanning pid %v : %v", args=[Pid, Name])

 -- find unbacked sections with xrw permission
 LET sections = SELECT * FROM foreach(
 row=processes,
 query={
 SELECT CreateTime as ProcessCreateTime,Pid,
 Name as ProcessName,
 Exe,
 CommandLine,
 Username,
 Address as Offset,
 Size,
 pathspec(
 DelegateAccessor="process",
 DelegatePath=Pid,
 Path=Address) AS _PathSpec
 FROM vad(pid=Pid)
 WHERE MappingName=~'^$'
 AND Protection='xrw'
 AND NOT State =~ 'RESERVE'
 })

 -- search for qakbot in suspicious sections
 LET process_hits = SELECT *
 FROM foreach(row= sections,
 query={
 SELECT
 Rule as Detection,
 dict(
 ProcessCreateTime = ProcessCreateTime,
 Pid = Pid,
 ProcessName = ProcessName,
 Exe = Exe,
 CommandLine = CommandLine,
 Username = Username,
 Offset = Offset,
 PayloadSize = Size
 ) as ProcessInfo,
 find_resource(data=pe_dump(in_memory=Size,pid=Pid,base_offset=Offset)) as Resources,
 find_data(data=pe_dump(in_memory=Size,pid=Pid,base_offset=Offset))[0].EncodedStrings as DecodedStrings
 FROM yara( accessor='offset',
 files=_PathSpec,
 rules=YaraRule,
 end=Size, key='X',
 number=1 )
 })

 -- decode campaign from larger resrouce
 LET decode_campaign = SELECT *,
 decode(data=Resources[0].Data)[0] as Campaign,
 decode_strings(data=DecodedStrings).String as DecodedStrings
 FROM foreach(row={ SELECT * FROM switch(
 a = if(condition=TargetBytes, then=bytestream),
 b = if(condition=TargetGlob, then=file_payloads),
 c = process_hits )
 }, workers = Workers)

 -- decode raw C2 data from larger resource
 LET decode_c2 = SELECT *
 advanced_method(data=Resources[1].Data,key=Campaign.Key)[20:] as _C2Raw
 FROM decode_campaign

 -- profile to parse Qakbot C2 data: LE netaddress with a seperator
 LET PROFILE = '''
 [
 ["Qakbot1", 0, [
 ["Method1", 0, "Array",
 { "type": "Entry","count": 200,
 "sentinel": "x=&amp;gt;x.C2 = '0.0.0.0:0'"
 }],
 ]],
 ["Entry", 8, [
 ["__IP", 1, "uint32"],
 ["__PORT", 5, "uint16b"],
 ['C2',0,'Value',{'value':"x=&amp;gt;format(format='%s:%d', args=[ip(netaddr4_le=x.__IP),x.__PORT])"}],
 ]],
 ["Qakbot2", 0, [
 ["Method2", 0, "Array",
 { "type": "Entry2", "count": 200,
 "sentinel": "x=&amp;gt;x.C2 = '0.0.0.0:0'"
 }],
 ]],
 ["Entry2", 7, [
 ["__IP", 1, "uint32"],
 ["__PORT", 5, "uint16b"],
 ['C2',0,'Value',{'value':"x=&amp;gt;format(format='%s:%d', args=[ip(netaddr4_le=x.__IP),x.__PORT])"}],
 ]]
 ]'''

 -- calculate C2 IPs using two observed methods
 LET results = SELECT *,
 Campaign.Key as Key,
 parse_string_with_regex(string=Campaign.Data,
 regex=[
 '''3=(?P&amp;lt;Timestamp&amp;gt;[ -~]*)\r\n''',
 '''10=(?P&amp;lt;Name&amp;gt;[ -~]*)\r\n'''
 ]) as Campaign,
 parse_binary(filename=_C2Raw,accessor='data', profile=PROFILE, struct="Qakbot1").Method1['C2'] as _C2method1,
 parse_binary(filename=_C2Raw,accessor='data', profile=PROFILE, struct="Qakbot2").Method2['C2'] as _C2method2
 FROM decode_c2

 -- finally determine C2 encoding and pretty timestamp then output rows and remove unwanted fields
 SELECT * FROM column_filter(
 query={
 SELECT *,
 Campaign + dict(Timestamp=timestamp(epoch=Campaign.Timestamp)) as Campaign,
 --upload(accessor='scope',file='_C2Raw') as C2RawUpload, --uncomment to troubleshoot bad C2
 find_c2(methods=[_C2method1,_C2method2])[0].C2 as C2
 FROM results
 }, exclude=["_C2method1","_C2method2","_C2Raw","Resources"])

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Carving.SquirrelWaffle</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/squirrelwaffle/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/squirrelwaffle/</guid><description>&lt;p&gt;This artifact yara-scans memory or process dumps for unpacked
SquirrelWaffle Dlls, decodes the configuration and returns the C2s
and the payload.&lt;/p&gt;
&lt;p&gt;Depending on the initial infection vector (the macro within .doc or
.xls maldoc), SquirrelWaffle packed droper will be loaded by either rundll32
or regsvr32 and unpack itself in memory.&lt;/p&gt;
&lt;p&gt;The decoded configurations found so far contain (1) a list of C2
URLS, (2*) &lt;em&gt;may&lt;/em&gt; contain a list of C2 IPs, and lastly, (3)
contains the command &amp;ldquo;regsvr32.exe -s&amp;rdquo;. The command is used to
launch its second-stage payload downloaded from its C2 addresses,
as a &amp;ldquo;.txt&amp;rdquo; file that is in fact a disguised PE, to be loaded in
memory.&lt;/p&gt;
&lt;h3 id="note"&gt;NOTE&lt;/h3&gt;
&lt;p&gt;This content simply carves the configuration and does not unpack
files on disk. That means pointing this artifact as a packed or
obfuscated file will not obtain the expected results.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Carving.SquirrelWaffle
author: "Eduardo Mattos - @eduardfir &amp;amp; Kostya Iliouk - @kostyailiouk"
description: |
 This artifact yara-scans memory or process dumps for unpacked
 SquirrelWaffle Dlls, decodes the configuration and returns the C2s
 and the payload.

 Depending on the initial infection vector (the macro within .doc or
 .xls maldoc), SquirrelWaffle packed droper will be loaded by either rundll32
 or regsvr32 and unpack itself in memory.

 The decoded configurations found so far contain (1) a list of C2
 URLS, (2*) *may* contain a list of C2 IPs, and lastly, (3)
 contains the command "regsvr32.exe -s". The command is used to
 launch its second-stage payload downloaded from its C2 addresses,
 as a ".txt" file that is in fact a disguised PE, to be loaded in
 memory.

 ### NOTE
 This content simply carves the configuration and does not unpack
 files on disk. That means pointing this artifact as a packed or
 obfuscated file will not obtain the expected results.

type: CLIENT

reference:
 - https://github.com/OALabs/Lab-Notes/blob/main/SquirrelWaffle/SquirrelWaffle.ipynb
 - https://www.zscaler.com/blogs/security-research/squirrelwaffle-new-loader-delivering-cobalt-strike

parameters:
 - name: TargetFileGlob
 default:
 - name: PidRegex
 default: .
 - name: ProcessRegex
 default: .
 - name: DetectionYara
 default: |
 rule SquirrelWaffle {
 meta:
 description = "Detects Unpacked SquirrelWaffle DLLs in Memory"
 author = "Eduardo Mattos - @eduardfir"
 reference = "https://www.malware-traffic-analysis.net/2021/09/17/index.html"
 date = "2021-09-29"
 hash = "ea4e9be41fa3f6895423e791596011f88ba45cde"
 strings:
 $s1 = { 20 48 54 54 50 2F 31 2E 31 0D 0A 48 6F 73 74 3A 20 } // HTTP/1.1 Host:
 $s2 = { 41 50 50 44 41 54 41 00 54 45 4D 50 } // APPDATA TEMP
 $s3 = { 34 30 34 00 32 30 30 00 2E 74 78 74 } // 404 200 .txt
 $s4 = { 20 03 2C 35 3E 18 58 59 48 0F 37 26 } // xored regsvr32.exe
 $s5 = "C:\\Users\\Administrator\\source\\repos\\Dll1\\Release\\Dll1.pdb"
 condition:
 4 of ($s*)
 }
sources:
 - query: |
 LET CountBlock &amp;lt;= starl(code='''
 def Main(arr):
 res=[]
 for i in range(0,len(arr),2):

 res.append({"Length":arr[i],"DataBlock":arr[i+1],"Count":i/2})

 return Pair(sorted(res, key=GetLength, reverse=True))

 def GetLength(dic):
 return dic["Length"]

 def Pair(arr):
 res=[]
 for dic in arr:
 found = False
 for tdic in arr:
 if (tdic["Count"] == dic["Count"] + 1):
 res.append({"DataBlock":dic,"Key":tdic})
 found = True
 break
 if (found == False):

 res.append(({"DataBlock":dic,"Key":0}))
 return res
 ''')
 -- find target files
 LET TargetFiles = SELECT FullPath FROM glob(globs=TargetFileGlob)

 -- find velociraptor process
 LET me &amp;lt;= SELECT Pid
 FROM pslist(pid=getpid())

 -- find all processes and add filters
 LET processes &amp;lt;= SELECT Name AS ProcessName, CommandLine, Exe, Pid
 FROM pslist()
 WHERE Name =~ ProcessRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND NOT Pid in me.Pid

 -- scan processes in scope with our Detection
 LET processDetections &amp;lt;= SELECT * FROM foreach(row=processes,
 query={
 SELECT * FROM if(condition=TargetFileGlob="",
 then={
 SELECT ProcessName, CommandLine, Exe, Pid, Rule AS YaraRule, Strings[0].Base AS BaseOffset
 FROM proc_yara(pid=Pid, rules=DetectionYara)
 GROUP BY Pid
 })
 })

 -- return the VAD region size from yara detections for later use
 LET regionDetections = SELECT *
 FROM foreach(row=processDetections,
 query={
 SELECT YaraRule, Pid, ProcessName, CommandLine, Exe, BaseOffset, Size AS VADSize
 FROM vad(pid=Pid)
 WHERE Address = BaseOffset
 })

 -- scan files in scope with our rule
 LET fileDetections = SELECT * FROM foreach(row=TargetFiles,
 query={
 SELECT * FROM if(condition=TargetFileGlob,
 then={
 SELECT * FROM switch(
 a={ -- yara detection
 SELECT FullPath, Rule AS YaraRule, (String.Offset - 1000) AS IdealOffset
 FROM yara(files=FullPath, rules=DetectionYara)
 },
 b={ -- yara miss
 SELECT FullPath, Null AS YaraRule
 FROM TargetFiles
 })
 },
 else={ -- no yara detection run
 SELECT FullPath, 'N/A' AS YaraRule
 FROM TargetFiles
 })
 })

 -- scan files in scope with our rule
 LET fileConfiguration = SELECT * FROM foreach(row=fileDetections,
 query={
 SELECT FullPath, YaraRule,
 read_file(filename=FullPath, offset=IdealOffset, length=10000) AS PEData
 FROM scope()
 })

 -- get data from the rdata section, or whole PE
 LET processConfiguration &amp;lt;= SELECT YaraRule, Pid, ProcessName, CommandLine, Exe, BaseOffset,
 read_file(filename=str(str=Pid), accessor='process', offset=BaseOffset, length=VADSize) AS PEData
 FROM regionDetections

 -- store the SquirrelWaffle configuration in blocks split by null bytes.
 LET parsedRdata = SELECT *,
 split(string=format(format="% X", args=parse_binary(filename=PEData, accessor="data", profile='''[
 ["SquirrelRdata", 0, [
 ["__prefix", 0, "String", {"length": x=&amp;gt; 100000, "term_hex":"004142434445464748494A4B4C4D4E4F505152535455565758595A6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435363738392B2F00", "max_length": x=&amp;gt; 100000}],
 ["ConfigSection", "x=&amp;gt;len(list=x.__prefix) + 66", "String", {"length": x=&amp;gt; 10000, "term_hex":"7374617274202F69"}]
 ]
 ]
 ]''', struct="SquirrelRdata").ConfigSection ), sep="00") AS SplitBlocks
 FROM if(condition=TargetFileGlob,
 then= fileConfiguration,
 else= processConfiguration)

 -- generate a list of sorted blocks and then pair encoded blocks with their keys using Starlark
 LET blocks &amp;lt;= SELECT *, CountBlock.Main(arr=array(a=enumerate(items=NewDict))) AS EnumDict
 FROM foreach(row=parsedRdata,
 query= {
 SELECT *, FullPath, YaraRule, Pid, ProcessName, CommandLine, Exe
 FROM foreach(row=SplitBlocks,
 query= {
 SELECT dict(Length=len(list=_value), DataBlock=_value) AS NewDict
 FROM scope()
 WHERE NewDict.Length &amp;gt; 45
 })
 })
 GROUP BY if(condition=TargetFileGlob,
 then= FullPath,
 else= CommandLine)

 -- store encoded blocks and their keys in separate columns, filtering out FPs based on key size
 LET finalPairs &amp;lt;= SELECT *, unhex(string=regex_replace(source=DataBlock.DataBlock, re=" ", replace="")) AS DataBlock,
 unhex(string=regex_replace(source=Key.DataBlock, re=" ", replace="")) AS Key
 FROM foreach(row=blocks,
 query= {
 SELECT *, FullPath, YaraRule, Pid, ProcessName, CommandLine, Exe FROM foreach(row=EnumDict,
 query={
 SELECT DataBlock, Key FROM scope()
 })
 })
 WHERE len(list=Key) &amp;gt; 32 AND len(list=Key) &amp;lt; 256

 -- return our results
 SELECT * FROM if(condition=TargetFileGlob,
 then= {
 SELECT YaraRule, FullPath, regex_replace(source=xor(key=Key,string=DataBlock), re="(\r)|(\\|)", replace=",\n") AS DecodedConfigs
 FROM finalPairs
 },
 else= {
 SELECT YaraRule, Pid, ProcessName, CommandLine, Exe, regex_replace(source=xor(key=Key,string=DataBlock), re="(\r)|(\\|)", replace=",\n") AS DecodedConfigs
 FROM finalPairs
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Carving.SystemBC</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/systembc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/systembc/</guid><description>&lt;p&gt;This artifact extracts SystemBC RAT configuration from a byte stream,
process or file on disk.&lt;/p&gt;
&lt;p&gt;The User can define bytes, file glob, process name or pid regex as a target.
The artifact firstly discovers configuration and extracts bytes,
before parsing with Velociraptor Binary Parser.&lt;/p&gt;
&lt;p&gt;This content simply carves the configuration and does not unpack files on
disk. That means pointing this artifact as a packed or obfuscated file may not
obtain the expected results.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Carving.SystemBC
author: Matt Green - @mgreen27
description: |
 This artifact extracts SystemBC RAT configuration from a byte stream, 
 process or file on disk.
 
 The User can define bytes, file glob, process name or pid regex as a target.
 The artifact firstly discovers configuration and extracts bytes, 
 before parsing with Velociraptor Binary Parser.
 
 This content simply carves the configuration and does not unpack files on
 disk. That means pointing this artifact as a packed or obfuscated file may not
 obtain the expected results.

reference:
 - https://malpedia.caad.fkie.fraunhofer.de/details/win.systembc
 

parameters:
 - name: TargetBytes
 default:
 - name: TargetFileGlob
 default:
 - name: PidRegex
 default: .
 type: regex
 - name: ProcessRegex
 default: .
 type: regex
 - name: FindConfig
 type: hidden
 description: Final Yara option and the default if no other options provided.
 default: |
 rule SystemBC_Config
 {
 meta:
 author = "Matt Green - @mgreen27"
 description = "SystemBC configuration"
 
 strings:
 $BEGINDATA = { 00 42 45 47 49 4e 44 41 54 41 00 } //BEGINDATA
 $ = "HOST1:" ascii wide fullword
 $ = "HOST2:" ascii wide fullword
 $ = "PORT1:" ascii wide fullword
 $ = "TOR:" ascii wide fullword
 $ = "-WindowStyle Hidden -ep bypass -file" ascii wide
 
 condition:
 $BEGINDATA and 3 of them
 }
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'

 query: |
 -- binary parse profile to extract SystemBC configuration.
 LET PROFILE = '''[
 [SystemBC, 0, [
 ["__FindHost1",0, "String",{term: "HOST1:"}],
 ["HOST1","x=&amp;gt;len(list=x.__FindHost1) + 6", "String",{term_hex: "0000"}],
 ["__FindHost2",0, "String",{term: "HOST2:"}],
 ["HOST2","x=&amp;gt;len(list=x.__FindHost2) + 6", "String",{term_hex: "0000"}],
 ["__FindPort1",0, "String",{term: "PORT1:"}],
 ["PORT1","x=&amp;gt;len(list=x.__FindPort1) + 6", "String",{term_hex: "0000"}],
 ["__FindTOR",0, "String",{term: "TOR:"}],
 ["TOR","x=&amp;gt;len(list=x.__FindTOR) + 4", "String",{term_hex: "0000"}],
 ["__FindUserAgent",0, "String",{term: "\r\nUser-Agent: "}],
 ["User-Agent","x=&amp;gt;len(list=x.__FindUserAgent) + 14", "String",{term: "\r\n"}],
 ]
 ]]'''
 
 
 -- Bytes usecase: scan DataBytes for config
 LET ByteConfiguration = SELECT
 Rule,
 len(list=TargetBytes) as Size,
 hash(path=TargetBytes,accessor='data') as Hash,
 String.Offset as HitOffset,
 read_file(accessor="data",filename=TargetBytes, offset=String.Offset, length=1000) as _RawConfig
 FROM yara(
 files=TargetBytes,
 accessor='data',
 rules=FindConfig,
 number=99,
 context=1000
 )
 GROUP BY _RawConfig
 
 -- Glob usecase: find target files
 LET TargetFiles = SELECT OSPath,Size
 FROM glob(globs=TargetFileGlob) WHERE NOT IsDir

 -- Glob usecase: Extract config from files in scope
 LET FileConfiguration = SELECT * FROM foreach(row=TargetFiles,
 query={
 SELECT 
 Rule,
 OSPath, Size,
 hash(path=OSPath) as Hash,
 String.Offset as HitOffset,
 read_file(filename=OSPath, offset=String.Offset, length=1000) as _RawConfig
 FROM yara(
 files=OSPath,
 rules=FindConfig,
 number=99,
 context=1000
 )
 GROUP BY OSPath,_RawConfig
 })
 
 -- find velociraptor process
 LET me &amp;lt;= SELECT * FROM if(condition= NOT ( TargetFileGlob OR TargetBytes ),
 then = { SELECT Pid FROM pslist(pid=getpid()) })

 -- find all processes and add filters
 LET processes = SELECT Name as ProcessName, Exe, CommandLine, Pid
 FROM pslist()
 WHERE
 Name =~ ProcessRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND NOT Pid in me.Pid
 
 -- scan processes in scope with our rule, limit 1 hit and extract context to parse
 LET ProcessConfiguration = SELECT * FROM foreach(
 row=processes,
 query={
 SELECT
 Rule,
 Pid, ProcessName, CommandLine,
 String.Offset as HitOffset,
 read_file(accessor="process", filename=format(format="/%d", args=Pid), offset=String.Offset, length=1000) as _RawConfig
 FROM yara( 
 files=format(format="/%d", args=Pid),
 accessor='process',
 rules=FindConfig,
 number=99,
 context=1000
 )
 GROUP BY Pid, ProcessName, CommandLine,_RawConfig
 })
 


 -- generate results remove any FPs
 SELECT *,
 parse_binary(accessor="data", filename=_RawConfig, profile=PROFILE, struct='SystemBC') AS SystemBC,
 _RawConfig
 FROM if(condition=TargetBytes,
 then=ByteConfiguration,
 else= if(condition=TargetFileGlob,
 then= FileConfiguration,
 else= ProcessConfiguration))
 WHERE SystemBC.HOST1 OR SystemBC.HOST2 OR SystemBC.TOR

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.BruteRatel</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.bruteratel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.bruteratel/</guid><description>&lt;p&gt;This hunt runts the Immersive Labs yara rule (&lt;a href="https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools/blob/main/BruteRatel.yar" target="_blank" &gt;https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools/blob/main/BruteRatel.yar&lt;/a&gt;
) across select files to identify the known Brute Ratel config strings.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.BruteRatel
author: Luke Fardell
description: |
 This hunt runts the Immersive Labs yara rule (https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools/blob/main/BruteRatel.yar) across select files to identify the known Brute Ratel config strings.


type: CLIENT
parameters:
 - name: PathGlob
 description: Only file names that match this glob will be scanned.
 default: C:/**/*.{exe,dll,bin,0xH,Svc,PS1}
 - name: UploadHits
 type: bool
 - name: YaraRule
 type: yara
 description: Yara Rule from https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools/blob/main/BruteRatel.yar
 default: |
 rule BruteRatelConfig {
 strings:
 $config_block = { 50 48 b8 [8] 50 68}
 $split_marker = { 50 48 b8 [8] 50 48 b8 }

 condition:
 filesize &amp;lt; 400KB and $config_block and #split_marker &amp;gt; 30
 }

sources:
 - query: |
 -- check which Yara to use
 LET yara = SELECT * FROM if(condition=YaraUrl,
 then= { SELECT Content FROM http_client( url=YaraUrl, method='GET') },
 else= { SELECT YaraRule as Content FROM scope() })

 -- time testing
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))

 -- first find all matching glob
 LET files = SELECT FullPath, Name, Size, Mtime, Atime, Ctime, Btime
 FROM glob(globs=PathGlob,nosymlink='True')
 WHERE
 NOT IsDir AND NOT IsLink
 AND if(condition=SizeMin,
 then= SizeMin &amp;lt; Size,
 else= True)
 AND if(condition=SizeMax,
 then=SizeMax &amp;gt; Size,
 else= True)
 AND
 ( time_test(stamp=Mtime)
 OR time_test(stamp=Atime)
 OR time_test(stamp=Ctime)
 OR time_test(stamp=Btime))

 -- scan files and only report a single hit.
 LET hits = SELECT * FROM foreach(row=files,
 query={
 SELECT
 FileName as FullPath,
 File.Size AS Size,
 Mtime, Atime, Ctime, Btime,
 Rule, Tags, Meta,
 str(str=String.Data) AS HitContext,
 String.Offset AS HitOffset
 FROM yara(rules=yara.Content[0],files=FullPath)
 LIMIT 1
 })

 -- upload files that have hit
 LET upload_hits=SELECT *,
 upload(file=FullPath) AS Upload
 FROM hits

 -- return rows
 SELECT * FROM if(condition=UploadHits,
 then=upload_hits,
 else=hits)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Honeyfiles</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.honeyfile/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.honeyfile/</guid><description>&lt;p&gt;This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using etw. The process tracker must be enabled, we use this to enrich etw events. Honeyfiles created by this artifact are removed at exit.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Honeyfiles
author: Zane Gittins &amp;amp; Matt Green (@mgreen27).
description: |
 This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using etw. The process tracker must be enabled, we use this to enrich etw events. Honeyfiles created by this artifact are removed at exit.
 
type: CLIENT_EVENT

parameters:
 - name: Honeyfiles
 description: | 
 The honeyfiles to generate and monitor.
 
 * TargetPath: Location to create honeyfile.
 * Enabled: Only generate the honeyfile if this is set to 'Y'
 * MagicBytes: The starting magic bytes of the honeyfile.
 * MinSize,MaxSize: The size of the honeyfile will be a random value between MinSize and MaxSize.
 type: csv
 default: |
 TargetPath,Enabled,MagicBytes,MinSize,MaxSize
 "%USERPROFILE%\Documents\KeePass\KeePass.kdbx",Y,03D9A29A67FB4BB5,10249,20899
 "%USERPROFILE%\AppData\Local\KeePass\KeePass.config.xml",Y,3C3F786D6C,512,1024
 "%USERPROFILE%\AppData\Local\LastPass\lastpass.conf",Y,3C3F786D6C,512,1024
 "%USERPROFILE%\AppData\Roaming\LastPass\loginState.xml",Y,3C3F786D6C,512,1024
 "%USERPROFILE%\AppData\Roaming\WinSCP\WinSCP.ini",Y,5B436F6E66696775726174696F6E5D,512,1024
 "%USERPROFILE%\.aws\credentials",Y,5B64656661756C745D,512,2048
 "%USERPROFILE%\.aws\config",Y,5B64656661756C745D,512,2048
 "%USERPROFILE%\.ssh\my_id_rsa",Y,2D2D2D2D2D424547494E205253412050524956415445204B45592D2D2D2D2D,1024,4096
 "%USERPROFILE%\.gcloud\credentials.db",Y,53514c69746520666f726d6174203300,512,2048
 "%USERPROFILE%\.azure\azureProfile.json",Y,7B0D0A,512,2048
 - name: Exclusions
 description: | 
 Process/thread regex pairs to exclude legitimate system activity and reduce false positives.
 Events matching both patterns are suppressed.
 type: csv
 default: |
 ProcessRegex,ThreadRegex
 ^[A-Z]:\\Windows\\explorer\.exe$,^[A-Z]:\\Windows\\System32\\ntdll\.dll$
 ^[A-Z]:\\Windows\\explorer\.exe$,^\\Device\\.*\\Windows\\System32\\ntdll\.dll$
 ^[A-Z]:\\Windows\\explorer\.exe$,^[A-Z]:\\Windows\\System32\\shcore\.dll$
 ^[A-Z]:\\Windows\\explorer\.exe$,^\\Device\\.*\\Windows\\System32\\shcore\.dll$
 .,^[A-Z]:\\Windows\\System32\\SearchProtocolHost\.exe$
 .,^\\Device\\.*\\Windows\\System32\\SearchProtocolHost\.exe$
 ^[A-Z]:\\Windows\\System32\\svchost\.exe$,^\\Device\\.*\\Windows\\System32\\defragsvc\.dll$
 ^[A-Z]:\\Windows\\System32\\svchost\.exe$,^[A-Z]:\\Windows\\System32\\defragsvc\.dll$
 ^[A-Z]:\\Program Files\\CrowdStrike\\CSFalconService\.exe$,.
 - name: HoneyUserRegex
 description: User name regex that will be used to host honeyfiles.
 type: string
 default: "."
export: |
 LET ComputerName &amp;lt;= dict(H={ SELECT Hostname FROM info() }).H[0].Hostname
 
 LET RandomChars(size) = SELECT
 format(format="%02x", args=rand(range=256)) AS HexByte
 FROM range(end=size)
 
 LET check_exist(path) = SELECT
 OSPath,
 Size,
 IsDir,
 if(condition=read_file(filename=OSPath)[-7:] =~ 'VRHoney',
 then=True,
 else=False) AS IsHoneyFile
 FROM stat(filename=path)
 
 LET enumerate_path = SELECT
 regex_replace(source=TargetPath,
 re='''\%USERPROFILE\%''',
 replace=Directory) AS TargetPath,
 *,
 check_exist(path=regex_replace(source=TargetPath,
 re='''\%USERPROFILE\%''',
 replace=Directory))[0] AS Exists,
 MaxSize - rand(range=(MaxSize - MinSize)) - len(
 list=unhex(string=MagicBytes)) - 7 AS _PaddingSize
 FROM Honeyfiles
 
 LET target_users = SELECT Name,
 Directory,
 UUID
 FROM Artifact.Windows.Sys.Users()
 WHERE NOT UUID =~ '''^(S-1-5-18|S-1-5-19|S-1-5-20)$'''
 AND Name =~ HoneyUserRegex
 
 LET show_honeyfiles = SELECT TargetPath,
 Enabled,
 MagicBytes,
 MinSize,
 MaxSize,
 _PaddingSize,
 Exists.Size AS Size,
 Exists.IsHoneyFile AS IsHoneyFile
 FROM foreach(row=target_users, query=enumerate_path)
 
 LET copy_honeyfiles = SELECT
 *, if(condition=Enabled =~ "^(Y|YES)$"
 AND (NOT Size OR IsHoneyFile),
 then=log(message="Creating file %v", dedup=-1, args=TargetPath)
 &amp;amp;&amp;amp; copy(dest=TargetPath,
 create_directories='y',
 accessor='data',
 filename=unhex(
 string=MagicBytes + join(
 array=RandomChars(size=_PaddingSize).HexByte) +
 format(format='%x', args='VRHoney'))),
 else="File does not exist") AS CreateHoneyFile
 FROM show_honeyfiles
 
 LET remove_honeyfiles = SELECT
 *, _PaddingSize,
 if(condition=IsHoneyFile,
 then=log(message="Removing %v", args=TargetPath, dedup=-1)
 &amp;amp;&amp;amp; rm(filename=TargetPath),
 else="File does not exist") AS RemoveHoneyFile
 FROM show_honeyfiles
 
 LET add_honeyfiles = SELECT
 TargetPath,
 Enabled,
 MagicBytes,
 MinSize,
 MaxSize,
 check_exist(path=TargetPath)[0].Size AS Size,
 check_exist(path=TargetPath)[0].IsHoneyFile AS IsHoneyFile
 FROM copy_honeyfiles
 
 LET ThreadInfo(tPid, tTid) = SELECT filename,
 memory_basic_info.RegionSize AS RegionSize
 FROM threads(pid=tPid)
 WHERE tid = tTid
 LIMIT 1
 
 LET get_auth_cache(Image) = authenticode(filename=Image)
 
 LET get_hash_cache(Image) = hash(path=Image, hashselect=["SHA256"]).SHA256
 
 LET WatchFiles &amp;lt;= to_dict(item={
 SELECT TargetPath AS _key,
 IsHoneyFile AS _value
 FROM add_honeyfiles
 WHERE IsHoneyFile
 })
 
 LET Keyword &amp;lt;= 5264
 
 LET CurrentPid &amp;lt;= getpid()
 
 LET ExclusionRules &amp;lt;= SELECT *
 FROM Exclusions
 
 // Function to check if an event should be excluded
 LET ShouldExclude(Process, Thread) = len(
 list=array(_={
 SELECT *
 FROM foreach(row=ExclusionRules)
 WHERE Process =~ ProcessRegex
 AND Thread =~ ThreadRegex
 LIMIT 1
 })) &amp;gt; 0

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows' AND version(plugin="dedup") &amp;gt;= 0

 query: |
 LET _ &amp;lt;= atexit(query={ SELECT * FROM remove_honeyfiles })
 
 LET TargetEvents = SELECT *
 FROM watch_etw(guid='{edd08927-9cc4-4e65-b970-c2560fb5c289}',
 description="Microsoft-Windows-Kernel-File",
 any=Keyword)
 WHERE System.ID = 12
 AND System.ProcessID != CurrentPid
 
 LET AuditEvents = SELECT
 timestamp(string=System.TimeStamp) AS Timestamp,
 get(item=WatchFiles, field=EventData.FileName) AS IsHoneyFile,
 *
 FROM TargetEvents
 WHERE IsHoneyFile != NULL
 
 LET Events = SELECT
 Timestamp,
 System.ProcessID AS Pid,
 EventData.FileName AS TargetPath,
 atoi(string=EventData.IssuingThreadId) AS Tid,
 (str(str=System.ProcessID) + EventData.FileName) AS DedupKey
 FROM AuditEvents
 
 LET DedupEvents = SELECT *, process_tracker_get(id=Pid).Data AS ProcInfo,
 ThreadInfo(tPid=Pid, tTid=Tid)[0] AS ThreadDetails,
 join(
 array=process_tracker_callchain(id=Pid).Data.Name,
 sep="-&amp;gt;") AS CallChain
 FROM dedup(query=Events, key="DedupKey")
 
 SELECT Timestamp,
 ComputerName,
 Pid,
 Tid,
 TargetPath,
 ProcInfo.Exe AS Image,
 ProcInfo.CommandLine AS Commandline,
 ProcInfo.Username AS User,
 ThreadDetails.filename AS ThreadFilename,
 ThreadDetails.RegionSize AS ThreadRegionSize,
 CallChain,
 cache(period=3600,
 func=get_auth_cache(Image=ProcInfo.Exe),
 key=str(str=ProcInfo.Exe),
 name="auth") AS Authenticode,
 cache(period=3600,
 func=get_hash_cache(Image=ProcInfo.Exe),
 key=str(str=ProcInfo.Exe),
 name="hash") AS Hash
 FROM DedupEvents
 WHERE NOT ShouldExclude(
 Process=if(condition=ProcInfo.Exe, then=ProcInfo.Exe, else=""),
 Thread=if(condition=ThreadDetails.filename,
 then=ThreadDetails.filename,
 else=""))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.HyperV</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/hyperv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/hyperv/</guid><description>&lt;p&gt;Scope suspicious Hyper-V worker process and activity on Windows workstations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checks for Hyper-V worker process, vmwp.exe, for handles to disk images.&lt;/li&gt;
&lt;li&gt;Returns Microsoft-Windows-Hyper-V-VMMS-Admin events with a VmName or VmID
referenced.&lt;/li&gt;
&lt;li&gt;Returns Microsoft-Windows-VHDMP-Operational events with a VhdFileName
matching a disk image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, this artifact targets Windows workstations only, Hyper-V is an
unusual service on Windows workstations.&lt;/p&gt;
&lt;p&gt;Windows.Search.WSLFileFinder may be used for some detection triage but VHDX
can be a complex format so collection for offline analysis may be needed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.HyperV
author: Matt Green - @mgreen27
description: |
 Scope suspicious Hyper-V worker process and activity on Windows workstations. 
 
 - Checks for Hyper-V worker process, vmwp.exe, for handles to disk images.
 - Returns Microsoft-Windows-Hyper-V-VMMS-Admin events with a VmName or VmID 
 referenced.
 - Returns Microsoft-Windows-VHDMP-Operational events with a VhdFileName 
 matching a disk image.
 
 By default, this artifact targets Windows workstations only, Hyper-V is an 
 unusual service on Windows workstations.
 
 Windows.Search.WSLFileFinder may be used for some detection triage but VHDX 
 can be a complex format so collection for offline analysis may be needed.
 
reference:
 - https://www.bitdefender.com/en-us/blog/businessinsights/curly-comrades-evasion-persistence-hidden-hyper-v-virtual-machines
type: CLIENT

parameters:
 - name: ProcessRegex
 default: vmwp\.exe
 type: regex
 - name: FileRegex
 default: \.(a?vhdx?)$
 description: "Default for Hyper-V image files: .vhdx .avhdx, .vhd"
 type: regex
 - name: DefaultLocationRegex
 default: (\\Program Files\\WSL|\\AppData\\Local)\\.+\.(a?vhdx?)$
 description: "Default location for WSL vhdx"
 type: regex
 - name: RunOnAll
 type: bool
 description: If Selected will run accross all Windows machines. By Default we filter out Windows Servers.
 
sources:
 - query: |
 LET precondition &amp;lt;= SELECT OS, Platform 
 FROM info() 
 WHERE OS = 'windows' 
 AND NOT if(condition= RunOnAll,
 then= False,
 else= Platform =~ 'Server' )

 LET process &amp;lt;= SELECT * FROM Artifact.Windows.System.Pslist(ProcessRegex=ProcessRegex)
 LET find_process(pid) = SELECT Pid,Name,CommandLine, Exe,Username 
 FROM process 
 WHERE Pid = pid
 
 LET results = SELECT ProcPid,ProcName,Exe,
 find_process(pid=ProcPid)[0].CommandLine as CommandLine,
 Name as HandleName,
 split(sep='''}\\''',string=Name)[1] as __OSPath,
 Type,
 find_process(pid=ProcPid)[0].Username as Username
 FROM Artifact.Windows.System.Handles(processRegex=ProcessRegex)
 WHERE Name =~ FileRegex
 
 SELECT *,
 { SELECT OSPath, Size, Mtime,Atime,Ctime, Btime,
 magic(path=OSPath) as FileMagic
 FROM stat(filename=__OSPath)
 } as FileInfo,
 if(condition= __OSPath=~DefaultLocationRegex,
 then= True,
 else= False ) as DefaultLocation
 FROM if(condition= precondition,
 then= results )

 - name: Microsoft-Windows-Hyper-V-VMMS-Admin
 query: |
 LET vmms = SELECT EventTime,
 Provider,
 EventID,
 UserSID,
 Username,
 UserData.VmlEventLog.VmName AS VmName,
 UserData.VmlEventLog.VmId AS VmId,
 Message,
 OSPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob="C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Hyper-V-VMMS-Admin.evtx",
 IdRegex=".")
 WHERE UserData.VmlEventLog.VmId OR UserData.VmlEventLog.VmName
 SELECT * FROM if(condition= precondition,
 then= vmms )
 
 - name: Microsoft-Windows-VHDMP-Operational
 query: |
 LET vhdmp = SELECT EventTime, Provider,EventID,UserSID,Username,
 if(condition=EventData.VhdFileName,
 then= EventData.VhdFileName,
 else= EventData.Data.Value ) as VhdFileName,
 Message,OSPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(preconditions=TRUE,
 EvtxGlob="C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-VHDMP-Operational.evtx",
 IdRegex=".")
 WHERE EventData.VhdFileName OR EventData.Data.Name = "VhdFileName"
 AND VhdFileName =~ FileRegex
 SELECT * FROM if(condition= precondition,
 then= vhdmp )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.IdatLoader</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/idatloader/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/idatloader/</guid><description>&lt;p&gt;This artifact enables running Yara over processes in memory.
Targeting detection of IDAT Loader and final payloads
observed in field.&lt;/p&gt;
&lt;p&gt;Note: may see some false positives on security tools,
add to whitelist appropriately.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.IdatLoader
author: Matt Green - @mgreen27
description: |
 This artifact enables running Yara over processes in memory.
 Targeting detection of IDAT Loader and final payloads 
 observed in field. 
 
 Note: may see some false positives on security tools, 
 add to whitelist appropriately.

type: CLIENT
reference:
 - https://www.rapid7.com/blog/post/2023/08/31/fake-update-utilizes-new-idat-loader-to-execute-stealc-and-lumma-infostealers/
 
parameters:
 - name: ProcessRegex
 default: .
 type: regex
 - name: PidRegex
 default: .
 type: regex
 - name: UploadHits
 type: bool
 - name: YaraRule
 type: yara
 description: Final Yara option and the default if no other options provided.
 default: |
 rule MAL_Loader_IDAT_August_2023
 {
 meta:
 description = "IDAT Loader August 2023"
 author = "Natalie Zargarov"
 strings:
 $trait_0 = {C6 A5 79 EA F4 B4 07 9A}
 $trait_1 = {3D ED C0 D3}
 $trait_2 = {C6 45 FC 4D C6 45 FD 5A}
 $trait_3 = {68 77 94 91 2C 8B 45 ?? 50 E8}
 condition:
 2 of ($trait_*)
 }
 
 rule MAL_Loader_IDAT_Shellcode_Dec_2023
 {
 meta:
 author = "Thomas Elkins - Rapid7"
 description = "Yara detects in memory IDAT Loader shellcode"
 date = "20-12-2023"
 
 strings:
 $stage1_32_1 = { 8B D1 8D 04 09 D1 EA 33 D0 8D 04 09 56 81 E2 55 55 55 55 33 D0 8B F2 8B C2 C1 E0 02 C1 EE 02 33 } // function from IDAT API Hashing Routine
 $stage1_32_2 = { 8A 44 0D 08 30 04 32 8D 41 01 83 E9 03 42 F7 D9 1B C9 23 C8 3B D7 72 E8 } // XOR encrpytion routine for creation of encrypted temp file
 $stage1_64_1 = { 8B 44 24 08 25 55 55 55 55 D1 E0 8B 4C 24 08 D1 E9 81 E1 55 55 55 55 0B C1 89 44 24 08 } // function from IDAT API Hashing Routine
 $stage1_64_2 = { 8B 04 24 8B 4C 24 04 0F B6 4C 0C 08 48 8B 54 24 20 0F B6 04 02 33 C1 8B 0C 24 48 8B 54 24 20 88 } // XOR encryption for creation of encrypted temp file
 $stage2_1 = { FF 57 0C 33 D2 6A 1A 59 F7 F1 66 0F BE 44 15 DC 66 89 04 73 46 3B 75 FC 72 E6 } // Function turns computer name into UpperCase only characters using srand function
 $stage2_2 = { 8B 00 33 04 8A 8B 4D E8 89 01 8B 55 E4 83 EA 01 39 55 F4 75 } // decryption loop for final payload
 
 condition:
 2 of ($stage1_32_*) or 2 of ($stage1_64_*) or 2 of ($stage2_*)
 }
 
 rule win_stealc_w0 {
 meta:
 malware = "Stealc"
 description = "Find standalone Stealc sample based on decryption routine or characteristic strings"
 reference = "https://blog.sekoia.io/stealc-a-copycat-of-vidar-and-raccoon-infostealers-gaining-in-popularity-part-1/"
 author = "crep1x"
 notes = "removed MZ header condition"
 strings:
 $dec = { 55 8b ec 8b 4d ?? 83 ec 0c 56 57 e8 ?? ?? ?? ?? 6a 03 33 d2 8b f8 59 f7 f1 8b c7 85 d2 74 04 } //deobfuscation function
 
 $str01 = "------" ascii
 $str02 = "Network Info:" ascii
 $str03 = "- IP: IP?" ascii
 $str04 = "- Country: ISO?" ascii
 $str05 = "- Display Resolution:" ascii
 $str06 = "User Agents:" ascii
 $str07 = "%s\\%s\\%s" ascii
 condition:
 ($dec or 5 of ($str*))
 }
 
 rule win_lumma_auto {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2023-07-11"
 description = "Detects win.lumma."
 strings:
 $sequence_0 = { 57 53 ff767c ff7678 }
 $sequence_1 = { 53 49 83fc00 75e8 8b4508 49 89ca }
 $sequence_2 = { e8???????? ff7614 e8???????? ff7608 e8???????? 83c414 83c8ff }
 $sequence_3 = { 4d 6be404 49 83ec04 }
 $sequence_4 = { 41 5b 41 5c }
 $sequence_5 = { c1e002 50 e8???????? 894614 8b461c c1e002 }
 $sequence_6 = { 0fb64203 83c204 33c1 c1e908 }
 $sequence_7 = { 41 5a cb 55 89e5 8b550c }
 $sequence_8 = { 4d 6bdb08 4c 01dc }
 $sequence_9 = { 50 e8???????? 894604 8b461c }
 $sequence_10 = { 41 8b0a 41 8b5204 }
 $sequence_11 = { 4d 89f3 49 83eb04 }
 $sequence_12 = { 57 8bf2 8bd9 6a2e 56 }
 $sequence_13 = { 03c0 3bc2 0f47d0 e8???????? 85c0 }
 $sequence_14 = { c1e002 50 e8???????? 89460c 8b461c c1e002 }
 condition:
 7 of them
 }
 
 rule win_amadey_auto {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2023-07-11"
 description = "Detects win.amadey."
 strings:
 $sequence_0 = { 8945f4 837df408 744f 8d85e8fdffff 890424 e8???????? c70424???????? }
 $sequence_1 = { c745fc00000000 e8???????? 84c0 750c c7042401000000 e8???????? e8???????? }
 $sequence_2 = { 89442404 891424 e8???????? 85c0 7510 8b45fc 40 }
 $sequence_3 = { 890424 e8???????? c7042400000000 e8???????? 81c424040000 }
 $sequence_4 = { e8???????? 8945f4 837df40a 0f842e010000 }
 $sequence_5 = { e8???????? c7442404???????? 8b4508 890424 e8???????? 85c0 7e75 }
 $sequence_6 = { 890424 e8???????? c7042401000000 e8???????? 89442404 8d85e8fbffff 890424 }
 $sequence_7 = { e8???????? 8b4508 c60000 c9 }
 $sequence_8 = { 68???????? e8???????? 8d4dcc e8???????? 83c418 }
 $sequence_9 = { 83fa10 722f 8b8d78feffff 42 8bc1 81fa00100000 7214 }
 $sequence_10 = { 52 51 e8???????? 83c408 8b955cfeffff }
 $sequence_11 = { 50 68???????? 83ec18 8bcc 68???????? }
 $sequence_12 = { 8b7dfc 8d4201 3bcb 7ccb 837e1410 }
 $sequence_13 = { 83c408 8b554c c7453000000000 c745340f000000 c6452000 83fa10 0f8204ffffff }
 $sequence_14 = { 68e8030000 ff15???????? 8b551c 83fa10 7228 8b4d08 }
 $sequence_15 = { 83fa10 722f 8b8d60feffff 42 }
 $sequence_16 = { 68???????? e8???????? 8d4db4 e8???????? 83c418 }
 $sequence_17 = { c78514feffff0f000000 c68500feffff00 83fa10 722f 8b8de8fdffff 42 }
 $sequence_18 = { 83c408 8b95fcfdffff c78510feffff00000000 c78514feffff0f000000 c68500feffff00 83fa10 }
 condition:
 7 of them
 }
 
 rule MALWARE_Win_RedLine {
 meta:
 author = "ditekSHen"
 description = "Detects RedLine infostealer"
 clamav_sig = "MALWARE.Win.Trojan.RedLine-1, MALWARE.Win.Trojan.RedLine-2"
 strings:
 $s1 = { 23 00 2b 00 33 00 3b 00 43 00 53 00 63 00 73 00 }
 $s2 = { 68 10 84 2d 2c 71 ea 7e 2c 71 ea 7e 2c 71 ea 7e
 32 23 7f 7e 3f 71 ea 7e 0b b7 91 7e 2b 71 ea 7e
 2c 71 eb 7e 5c 71 ea 7e 32 23 6e 7e 1c 71 ea 7e
 32 23 69 7e a2 71 ea 7e 32 23 7b 7e 2d 71 ea 7e }
 $s3 = { 83 ec 38 53 b0 ?? 88 44 24 2b 88 44 24 2f b0 ??
 88 44 24 30 88 44 24 31 88 44 24 33 55 56 8b f1
 b8 0c 00 fe ff 2b c6 89 44 24 14 b8 0d 00 fe ff
 2b c6 89 44 24 1c b8 02 00 fe ff 2b c6 89 44 24
 18 b3 32 b8 0e 00 fe ff 2b c6 88 5c 24 32 88 5c
 24 41 89 44 24 28 57 b1 ?? bb 0b 00 fe ff b8 03
 00 fe ff 2b de 2b c6 bf 00 00 fe ff b2 ?? 2b fe
 88 4c 24 38 88 4c 24 42 88 4c 24 47 c6 44 24 34
 78 c6 44 24 35 61 88 54 24 3a c6 44 24 3e 66 c6
 44 24 41 33 c6 44 24 43 ?? c6 44 24 44 74 88 54
 24 46 c6 44 24 40 ?? c6 44 24 39 62 c7 44 24 10 }
 $s4 = "B|BxBtBpBlBhBdB`B\\BXBTBPBLBHBDB@B&amp;lt;B8B4B0B,B(B$B B" fullword wide
 $s5 = " delete[]" fullword ascii
 $s6 = "constructor or from DllMain." ascii
 
 $x1 = "RedLine.Reburn" ascii
 $x2 = "RedLine.Client." ascii
 $x3 = "hostIRemotePanel, CommandLine: " fullword wide
 $u1 = "&amp;lt;ParseCoinomi&amp;gt;" ascii
 $u2 = "&amp;lt;ParseBrowsers&amp;gt;" ascii
 $u3 = "&amp;lt;GrabScreenshot&amp;gt;" ascii
 $u4 = "UserLog" ascii nocase
 $u5 = "FingerPrintT" fullword ascii
 $u6 = "InstalledBrowserInfoT" fullword ascii
 $u7 = "RunPE" fullword ascii
 $u8 = "DownloadAndEx" fullword ascii
 $u9 = ".Data.Applications.Wallets" ascii
 $u10 = ".Data.Browsers" ascii
 $u11 = ".Models.WMI" ascii
 $u12 = "DefenderSucks" wide
 
 $pat1 = "(((([0-9.])\\d)+){1})" fullword wide
 $pat2 = "^(?:2131|1800|35\\\\d{3})\\\\d{11}$" fullword wide
 $pat3 = "6(?:011|5[0-9]{2})[0-9]{12}$/C" fullword wide
 $pat4 = "Telegramprofiles^(6304|6706|6709|6771)[0-9]{12,15}$" fullword wide
 $pat5 = "host_key^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$" fullword wide
 $pat6 = "^3(?:0[0-5]|[68][0-9])[0-9]{11}$" wide
 $pat7 = "settingsprotocol^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$" wide
 $pat8 = "Opera GX4[0-9]{12}(?:[0-9]{3})?$cookies" wide
 $pat9 = "^9[0-9]{15}$Coinomi" wide
 $pat10 = "wallets^(62[0-9]{14,17})$" wide
 $pat11 = "hostpasswordUsername_value" wide
 $pat12 = "credit_cards^389[0-9]{11}$" wide
 $pat13 = "NWinordVWinpn.eWinxe*WinhostUsername_value" wide
 $pat14 = /(\/|,\s)CommandLine:/ wide
 // another variant
 $v2_1 = "ListOfProcesses" fullword ascii
 $v2_2 = /get_Scan(ned)?(Browsers|ChromeBrowsersPaths|Discord|FTP|GeckoBrowsersPaths|Screen|Steam|Telegram|VPN|Wallets)/ fullword ascii
 $v2_3 = "GetArguments" fullword ascii
 $v2_4 = "VerifyUpdate" fullword ascii
 $v2_5 = "VerifyScanRequest" fullword ascii
 $v2_6 = "GetUpdates" fullword ascii
 // yet another variant
 $v3_1 = "localhost.IUserServiceu" fullword ascii
 $v3_2 = "ParseNetworkInterfaces" fullword ascii
 $v3_3 = "ReplyAction0http://tempuri.org/IUserService/GetUsersResponse" fullword ascii
 $v3_4 = "Action(http://tempuri.org/IUserService/GetUsersT" fullword ascii
 $v3_5 = "basicCfg" fullword wide
 // more variants
 $vx4_1 = "C:\\\\Windows\\\\Microsoft.NET\\\\Framework\\\\v4.0.30319\\\\AddInProcess32.exe" fullword wide
 $v4_2 = "isWow64" fullword ascii
 $v4_3 = "base64str" fullword ascii
 $v4_4 = "stringKey" fullword ascii
 $v4_5 = "BytesToStringConverted" fullword ascii
 $v4_6 = "FromBase64" fullword ascii
 $v4_7 = "xoredString" fullword ascii
 $v4_8 = "procName" fullword ascii
 $v4_9 = "base64EncodedData" fullword ascii
 // another variant 2021-10-23
 $v5_1 = "DownloadAndExecuteUpdate" fullword ascii
 $v5_2 = "ITaskProcessor" fullword ascii
 $v5_3 = "CommandLineUpdate" fullword ascii
 $v5_4 = "DownloadUpdate" fullword ascii
 $v5_5 = "FileScanning" fullword ascii
 $v5_6 = "GetLenToPosState" fullword ascii
 $v5_7 = "RecordHeaderField" fullword ascii
 $v5_8 = "EndpointConnection" fullword ascii
 $v5_9 = "BCRYPT_KEY_LENGTHS_STRUCT" fullword ascii
 // another variant (v11?)
 $v6_1 = "%localappdata%\\" fullword wide
 $v6_2 = "GetDecoded" fullword ascii
 $v6_3 = "//settinString.Removeg[@name=\\PasswString.Removeord\\]/valuString.RemoveeROOT\\SecurityCenter" fullword wide
 $v6_4 = "AppData\\Roaming\\ //settString.Replaceing[@name=\\UString.Replacesername\\]/vaString.Replaceluemoz_cookies" wide
 $v6_5 = "&amp;lt;GetWindowsVersion&amp;gt;g__HKLM_GetString|11_0" fullword ascii
 $v6_6 = "net.tcp://" fullword wide
 
 condition:
 (all of ($s*) or 2 of ($x*) or 7 of ($u*) or 7 of ($pat*) or (1 of ($x*) and (5 of ($u*) or 2 of ($pat*))) or 5 of ($v2*) or 4 of ($v3*) or (3 of ($v2*) and (2 of ($pat*) or 2 of ($u*)) or (1 of ($vx4*) and 5 of ($v4*)) or 5 of ($v4*) or 6 of ($v5*)) or 5 of ($v6*) or (4 of ($v6*) and 3 of them )) or ((all of ($x*) and 4 of ($s*)) or (4 of ($v6*) and 4 of them))
 }

 - name: NumberOfHits
 description: THis artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int64
 - name: ExePathWhitelist
 description: Regex of ProcessPaths to exclude
 type: regex
 default: "C:\\Program Files\\Sophos\\"


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

 query: |
 SELECT Pid,ProcessName,ExePath,CommandLine,
 Rule,Meta,YaraString,HitOffset, HitContext,
 process_tracker_callchain(id=Pid).data as ProcessChain
 FROM Artifact.Windows.Detection.Yara.Process(
 PidRegex=PidRegex,
 ProcessRegex=ProcessRegex,
 YaraRule=YaraRule,
 YaraRule=YaraRule,
 NumberOfHits=str(str=NumberOfHits),
 ContextBytes=ContextBytes,
 ExePathWhitelist=ExePathWhitelist )

column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.ISOMount</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.isomount/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.isomount/</guid><description>&lt;p&gt;Following Microsoft&amp;rsquo;s decision to block macros by default on MS
Office applications, threat actors are increasingly using container
files such as ISO files to distribute malware. This artifact will
extract evidence of container files being mounted that may be
malicious from the Microsoft-Windows-VHDMP-Operational EventLog.
The artifact targets the string &amp;ldquo;.(iso|vhd|vhdx|img)$&amp;rdquo; in event
IDs: 1 (mount), 2 (unmount) and 12 (type, path, handle).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.ISOMount
author: Conor Quinn - @ConorQuinn92, updated Matt Green - @mgreen27
description: |
 Following Microsoft's decision to block macros by default on MS
 Office applications, threat actors are increasingly using container
 files such as ISO files to distribute malware. This artifact will
 extract evidence of container files being mounted that may be
 malicious from the Microsoft-Windows-VHDMP-Operational EventLog.
 The artifact targets the string ".(iso|vhd|vhdx|img)$" in event
 IDs: 1 (mount), 2 (unmount) and 12 (type, path, handle).

reference:
 - https://nasbench.medium.com/finding-forensic-goodness-in-obscure-windows-event-logs-60e978ea45a3
 - https://www.proofpoint.com/us/blog/threat-insight/how-threat-actors-are-adapting-post-macro-world

parameters:
 - name: TargetGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-VHDMP-Operational.evtx'
 - name: TargetImageRegex
 default: 'C:\\Users\\.+\.(iso|vhd|vhdx|img)$'
 type: regex
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 SELECT EventTime,
 Computer,
 Username,
 Channel,
 EventID,
 EventRecordID,
 Message,
 EventData,
 regex_replace(source=EventData.VhdFileName, re='''\\\\\?\\''', replace='') AS Filename,
 FullPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=TargetGlob,
 IdRegex='^(1|2|12|22|23)$',
 VSSAnalysisAge=VSSAnalysisAge)
 WHERE EventData.VhdFileName =~ TargetImageRegex

 notebook:
 - type: vql_suggestion
 name: ImageMount hunt summary
 template: |
 /*
 # ImageMount hunt summary

 This notebook stacks by Computer and Filename modify as required
 */
 SELECT
 min(item=EventTime) as EarliestTime,
 max(item=EventTime) as LatestTime,
 Computer, Username, EventID,Message,
 Filename,
 count() as Total
 FROM source(artifact="Exchange.Windows.Detection.ISOMount")
 GROUP BY Computer,Username, EventID, Filename

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Keylogger</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.keylogger/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.keylogger/</guid><description>&lt;p&gt;This artifact is my attempt at implementing keylogger detection based on research presented by &lt;a href="https://speakerdeck.com/asuna_jp/nullcon-goa-2025-windows-keylogger-detection-targeting-past-and-present-keylogging-techniques" target="_blank" &gt;Asuka Nakajima at NULLCON&lt;/a&gt;
 using the Microsoft-Windows-Win32k ETW provider.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Polling based keyloggers - Event id 1003 (GetAsyncKeyState) with MsSinceLastKeyEvent &amp;gt; 100 and BackgroundCallCount &amp;gt; 400&lt;/li&gt;
&lt;li&gt;Hooking based keyloggers - Event id 1002 (SetWindowsHookEx) with FilterType = WH_KEYBOARD_LL&lt;/li&gt;
&lt;li&gt;RawInput based keyloggers - Event id 1001 (RegisterRawInputDevices) with Flags = RIDEV_INPUT_SINK&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Keylogger
author: Zane Gittins
description: |
 This artifact is my attempt at implementing keylogger detection based on research presented by [Asuka Nakajima at NULLCON](https://speakerdeck.com/asuna_jp/nullcon-goa-2025-windows-keylogger-detection-targeting-past-and-present-keylogging-techniques) using the Microsoft-Windows-Win32k ETW provider.
 
 * Polling based keyloggers - Event id 1003 (GetAsyncKeyState) with MsSinceLastKeyEvent &amp;gt; 100 and BackgroundCallCount &amp;gt; 400
 * Hooking based keyloggers - Event id 1002 (SetWindowsHookEx) with FilterType = WH_KEYBOARD_LL
 * RawInput based keyloggers - Event id 1001 (RegisterRawInputDevices) with Flags = RIDEV_INPUT_SINK
# 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"
export: |
 LET SuspiciousEvents = SELECT *
 FROM delay(query={
 SELECT *
 FROM watch_etw(guid="{8c416c79-d49b-4f01-a467-e56d3aa8234c}",
 description="Microsoft-Windows-Win32k",
 level=4,
 any=5120)
 WHERE (System.ID = 1003
 AND atoi(string=EventData.MsSinceLastKeyEvent) &amp;gt; 100
 AND atoi(string=EventData.BackgroundCallCount) &amp;gt; 400) OR (
 System.ID = 1002
 AND EventData.FilterType = "0xD") OR (System.ID = 1001
 AND EventData.Flags = "256")
 },
 delay=5)
 
 // On event id 1003 we must use EventData.PID as the process PID not System.ID.
 LET EnrichEvents = SELECT *
 FROM foreach(row=SuspiciousEvents,
 query={
 SELECT *
 FROM if(condition=System.ID = 1003,
 then={
 SELECT timestamp(string=System.TimeStamp) AS Timestamp,
 System.ID AS EventID,
 EventData.PID AS Pid,
 process_tracker_get(id=atoi(string=EventData.PID)).Data AS ProcInfo,
 join(array=process_tracker_callchain(
 id=atoi(string=EventData.PID)).Data.Name,
 sep="-&amp;gt;") AS CallChain
 FROM scope()
 },
 else={
 SELECT timestamp(string=System.TimeStamp) AS Timestamp,
 System.ID AS EventID,
 System.ProcessID AS Pid,
 process_tracker_get(id=System.ProcessID).Data AS ProcInfo,
 join(array=process_tracker_callchain(
 id=System.ProcessID).Data.Name,
 sep="-&amp;gt;") AS CallChain
 FROM scope()
 })
 })
 WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex


sources:
 - precondition:
 SELECT OS From info() where OS = 'windows' AND version(plugin="dedup") &amp;gt;= 0

 query: |
 SELECT *
 FROM dedup(query={ SELECT * FROM EnrichEvents }, timeout=5, key="Pid")


 - precondition:
 SELECT OS From info() where OS = 'windows' AND version(plugin="dedup") = NULL

 query: |
 SELECT *
 FROM EnrichEvents

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.LotusBlossom.Chrysalis</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/chrysalis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/chrysalis/</guid><description>&lt;p&gt;Assists scoping IOCs related to the recent publicly disclosed Notepad++
supply chain attack.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find impacted notepad++ versions&lt;/li&gt;
&lt;li&gt;Find suspicious files in public reports&lt;/li&gt;
&lt;li&gt;Find public reported network urls in running processes&lt;/li&gt;
&lt;li&gt;Find Warbird clipc.dll shellcode loader strings&lt;/li&gt;
&lt;li&gt;Find Shellcode and loader on disk with YARA&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Untoggle unwanted collections&lt;/p&gt;
&lt;p&gt;Last updated: 2026-02-05&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.LotusBlossom.Chrysalis
author: Matt Green - @mgreen27
description: |
 Assists scoping IOCs related to the recent publicly disclosed Notepad++ 
 supply chain attack. 

 - Find impacted notepad++ versions
 - Find suspicious files in public reports
 - Find public reported network urls in running processes
 - Find Warbird clipc.dll shellcode loader strings
 - Find Shellcode and loader on disk with YARA
 
 Untoggle unwanted collections 
 
 Last updated: 2026-02-05
 

reference:
 - https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/
 - https://securelist.com/notepad-supply-chain-attack/118708/
 
type: CLIENT

parameters:
 - name: FileIoc
 description: Glob for suspicious files in public reports (lightweight)
 type: bool
 default: Y
 - name: NetworkMemory
 description: Run yara detection for Network IOCs in process memory
 type: bool
 default: Y
 - name: Warbird
 description: Run targeted yara detection for Warbird clipc.dll artifacts 
 type: bool
 default: Y
 - name: DiskYara
 description: Run targeted yara disk detection for Chrysalis shellcode and loaders in (heavy)
 type: bool
 default: N
 - name: DiskYaraGlob
 description: Glob to use in Chrysalis disk yara.
 default: 'C:/{Users,ProgramData}/**'
 
 - name: TargetGlobs
 description: Specify multiple globs to search for.
 type: csv
 default: |
 Glob,Notes
 C:\\Users\\*\\AppData\\Roaming\\Bluetooth\\BluetoothService.exe,Chrysalis loader executable
 C:\\Users\\*\\AppData\\Roaming\\Bluetooth\\log.dll,Malicious sideloaded DLL
 C:\\Users\\*\\AppData\\Roaming\\Bluetooth\\Bluetooth,Encrypted shellcode blob (no extension)
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\ProShow.exe,Stage 1 payload
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\defscr,Associated data file
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\if.dnt,Associated data file
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\proshow.crs,Associated data file
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\proshow.phd,Associated data file
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\proshow_e.bmp,Associated bitmap
 C:\\Users\\*\\AppData\\Roaming\\ProShow\\1.txt,Recon output (whoami/tasklist)
 C:\\Users\\*\\AppData\\Roaming\\Adobe\\Scripts\\script.exe,Stage 2 loader
 C:\\Users\\*\\AppData\\Roaming\\Adobe\\Scripts\\alien.dll,Malicious DLL
 C:\\Users\\*\\AppData\\Roaming\\Adobe\\Scripts\\lua5.1.dll,Bundled Lua runtime
 C:\\Users\\*\\AppData\\Roaming\\Adobe\\Scripts\\alien.ini,Configuration file
 C:\\Users\\*\\AppData\\Roaming\\Adobe\\Scripts\\a.txt,System reconnaissance output
 C:\\Users\\*\\AppData\\Local\\Temp\\update.exe,Malicious updater (multiple variants)
 C:\\Users\\*\\AppData\\Local\\Temp\\AutoUpdater.exe,Alternate malicious updater name
 C:\\Users\\*\\AppData\\Local\\Temp\\u.bat,Cleanup / self-delete script
 C:\\Users\\*\\AppData\\Local\\Temp\\*.nsi,NSIS installer artifacts
 C:\\ProgramData\\USOShared\\svchost.exe-nostdlib,Masqueraded loader binary
 C:\\ProgramData\\USOShared\\libtcc.dll,Tiny C Compiler runtime
 C:\\ProgramData\\USOShared\\conf.c,C source containing embedded shellcode
 C:\\ProgramData\\USOShared\\*.exe,Userland executables in non-standard location
 C:\\ProgramData\\USOShared\\*.dll,Userland DLLs in non-standard location
 C:\\ProgramData\\USOShared\\*.c,Source code present on victim system
 
 - name: NetworkYara
 type: yara
 default: | 
 rule APT_LotusBlossom_Chrysalis_Network_IOCs {
 meta:
 author = "Matt Green - @mgreen27"
 description = "Network/URI indicators for Notepad++ supply-chain activity (Kaspersky + Rapid7)"
 date = "2026-02-04"
 reference_rapid7 = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 reference_kaspersky = "https://securelist.com/notepad-supply-chain-attack/118708/"
 
 strings:
 /* Domains */
 $dom1 = "api.skycloudcenter.com" ascii wide
 $dom2 = "api.wiresguard.com" ascii wide
 $dom3 = "self-dns.it.com" ascii wide
 $dom4 = "cdncheck.it.com" ascii wide
 $dom5 = "safe-dns.it.com" ascii wide
 
 /* IPs */
 $ip1 = "95.179.213.0" ascii wide
 $ip2 = "59.110.7.32" ascii wide
 $ip3 = "124.222.137.114" ascii wide
 $ip4 = "45.76.155.202" ascii wide
 $ip5 = "45.32.144.255" ascii wide
 $ip6 = "45.77.31.210" ascii wide
 
 /* Ports */
 $port1 = ":8880" ascii wide
 $port2 = ":9999" ascii wide
 
 /* Metasploit / Cobalt Strike staging */
 $path1 = "/users/admin" ascii wide
 $path2 = "/users/system" ascii wide
 $path3 = "/help/Get-Start" ascii wide
 
 /* Cobalt Strike / Chrysalis beacon APIs */
 $path4 = "/update/v1" ascii wide
 $path5 = "/api/update/v1" ascii wide
 $path6 = "/api/FileUpload/submit" ascii wide
 $path7 = "/api/getInfo/v1" ascii wide
 $path8 = "/api/getBasicInfo/v1" ascii wide
 $path9 = "/api/Metadata/submit" ascii wide
 $path10 = "/api/Info/submit" ascii wide
 $path11 = "/api/updateStatus/v1" ascii wide
 $path12 = "/resolve" ascii wide
 $path13 = "/dns-query" ascii wide
 $path14 = "/a/chat/s/" ascii wide
 $path15 = "/uffhxpSy" ascii wide
 $path26 = "/3yZR31VK" ascii wide
 $path17= "/list" ascii wide
 
 condition:
 (
 (1 of ($dom*)) and (1 of ($path*))
 )
 or
 (
 (1 of ($ip*)) and (1 of ($path*, $port*))
 )
 }
 
 - name: WarbirdYara
 type: yara
 default: |
 rule APT_LotusBlossom_Chrysalis_Loader_Warbird {
 meta:
 author = "Matt Green - @mgreen27"
 description = "Detects payload bytes in first 0x490 bytes in clipc.dll Warbird technique as described by Rapid7"
 malware_family = "Chrysalis"
 reference = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 scope = "Microsoft signed DLL - clipc.dll VAD section"
 date = "2026-02-03"
 strings:
 $hex1 = { EF BE AD DE }
 $hex2 = { FE AF FE CA }
 
 condition:
 $hex1 in (0..1167) or
 $hex2 in (0..1167)
 }
 
 - name: ChrysalisYara
 type: yara
 default: | 
 rule MAL_Chrysalis_DllLoader_Feb26 {
 meta:
 description = "Detects DLL used to load Chrysalis backdoor, seen being used in the compromise of the infrastructure hosting Notepad++ by Chinese APT group Lotus Blossom"
 author = "X__Junior"
 date = "2026-02-02"
 reference = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 hash = "3bdc4c0637591533f1d4198a72a33426c01f69bd2e15ceee547866f65e26b7ad"
 score = 80
 strings:
 $op1 = { 33 D2 8B C1 F7 F6 0F B6 C1 03 55 ?? 6B C0 ?? 32 02 88 04 0F 41 83 F9 ?? 72 }
 $op2 = { 0F B6 04 31 41 33 C2 69 D0 ?? ?? ?? ?? 3B CB 72 }
 condition:
 uint16(0) == 0x5a4d and all of them
 }
 
 rule MAL_Chrysalis_Shellcode_Loader_Feb26 {
 meta:
 description = "Detects shellcode used to load Chrysalis backdoor, seen being used in the compromise of the infrastructure hosting Notepad++ by Chinese APT group Lotus Blossom"
 author = "X__Junior"
 date = "2026-02-02"
 reference = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 hash = "e2e3d78437cf9d48c2b2264e44bb36bc2235834fc45bbb50b5d6867f336711e3"
 score = 80
 strings:
 $op1 = { 8B C7 03 D7 83 E0 ?? 47 8A 4C 05 ?? 8A 04 13 02 C1 32 C1 2A C1 88 02 8B 55 ?? 3B FE 7C ?? 8B 5D ?? 8B 45 }
 $op2 = { 03 F8 8B 45 ?? 8B 50 ?? 85 C9 79 ?? 0F B7 C1 EB ?? 8D 41 ?? 03 C3 50 FF 75 ?? FF D2 89 07 85 C0 74 ?? 8B 4D ?? 46 }
 condition:
 1 of them
 }
 
 rule MAL_Chrysalis_Backdoor_Feb26 {
 meta:
 description = "Detects Chrysalis backdoor, seen being used in the compromise of the infrastructure hosting Notepad++ by Chinese APT group Lotus Blossom"
 author = "X__Junior"
 date = "2026-02-02"
 reference = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 hash = "e2e3d78437cf9d48c2b2264e44bb36bc2235834fc45bbb50b5d6867f336711e3"
 score = 80
 strings:
 $opa1 = { 8B 4D ?? C1 CF ?? C1 C1 ?? 03 F9 D1 C3 8B 4D ?? C1 C1 ?? 03 F9 03 FB 8B 5D ?? 69 CF ?? ?? ?? ?? BF ?? ?? ?? ?? 2B F9 EB }
 $opa2 = { F7 E9 [0-1] 8B C2 C1 E8 ?? 03 C2 8D 0C 40 8A C3 34 ?? [0-2] 0F B6 [1-4] 0F B6 C3 8B 5D [1-3] 0F 45 D0 }
 
 $opb1 = { 0F B6 84 35 ?? ?? ?? ?? 88 84 3D ?? ?? ?? ?? 88 8C 35 ?? ?? ?? ?? 0F B6 84 3D ?? ?? ?? ?? 8B 8D ?? ?? ?? ?? 03 C2 0F B6 C0 0F B6 84 05 ?? ?? ?? ?? 30 04 19 43 3B 9D ?? ?? ?? ?? 7C }
 condition:
 (1 of ($opa*) and $opb1)
 or
 all of ($opa*)
 }
 
 rule MAL_CobaltStrike_Beacon_Loader_Feb26 {
 meta:
 description = "Detects Cobalt Strike beacon loader"
 author = "X__Junior"
 date = "2026-02-02"
 reference = "https://www.rapid7.com/blog/post/tr-chrysalis-backdoor-dive-into-lotus-blossoms-toolkit/"
 hash = "0a9b8df968df41920b6ff07785cbfebe8bda29e6b512c94a3b2a83d10014d2fd"
 hash = "b4169a831292e245ebdffedd5820584d73b129411546e7d3eccf4663d5fc5be3"
 score = 80
 strings:
 $opa1 = { 45 33 C9 41 B8 ?? ?? ?? ?? 48 8D 94 24 ?? ?? ?? ?? 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 66 89 44 24 ?? 41 B8 ?? ?? ?? ?? 48 8D 94 24 ?? ?? ?? ?? 0F B7 4C 24 ?? FF 15 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? FF 15 }
 $opa2 = { 4C 8D 4C 24 ?? 41 B8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 48 C7 44 24 ?? ?? ?? ?? ?? C7 44 24 ?? ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? 48 89 4C 24 ?? 4C 8D 0D ?? ?? ?? ?? 45 33 C0 33 D2 48 8B C8 FF 15 }
 
 $opb1 = { 48 8D 89 ?? ?? ?? ?? 0F 10 00 0F 10 48 ?? 48 8D 80 ?? ?? ?? ?? 0F 11 41 ?? 0F 10 40 ?? 0F 11 49 ?? 0F 10 48 ?? 0F 11 41 ?? 0F 10 40 ?? 0F 11 49 ?? 0F 10 48 ?? 0F 11 41 ?? 0F 10 40 ?? 0F 11 49 ?? 0F 10 48 ?? 0F 11 41 ?? 0F 11 49 ?? 48 83 EA }
 $opb2 = { 45 33 C9 48 89 84 24 ?? ?? ?? ?? 41 B8 18 00 00 00 C7 84 24 ?? ?? ?? ?? 03 00 00 00 48 8D 94 24 ?? ?? ?? ?? 48 89 BC 24 ?? ?? ?? ?? B9 B9 00 00 00 FF 15 }
 condition:
 uint16(0) == 0x5a4d and
 all of ($opa*)
 or all of ($opb*)
 }
 
 rule MAL_POC_Microsoft_Warbird_Loader_Feb26 {
 meta:
 description = "Detects a POC to turn Microsoft Warbird into a shellcode loader"
 author = "X__Junior"
 date = "2026-02-03"
 reference = "https://cirosec.de/en/news/abusing-microsoft-warbird-for-shellcode-execution/"
 hash = "29d0467ee452752286318f350ceb28a2b04ee4c6de550ba0edc34ae0fa7cbb03"
 score = 75
 strings:
 $op = { fe af fe ca ef be ad de }
 condition:
 uint16(0) == 0x5a4d and $op
 } 
 
sources:
 - query: |
 SELECT *
 FROM Artifact.Windows.Sys.Programs()
 WHERE DisplayName =~ '''notepad\+\+'''
 AND DisplayVersion =~ "8\.8\.[2-9]"

 - name: Suspicious files
 query: |
 SELECT * FROM if(
 condition=FileIoc,
 then={
 SELECT OSPath,
 get(item=Data, field="mft") as Inode,
 Mode.String AS Mode, Size,
 Mtime AS MTime,
 Atime AS ATime,
 Btime AS BTime,
 Ctime AS CTime, 
 magic(path=OSPath) as Magic,
 hash(path=OSPath,hashselect='SHA1').SHA1 as SHA1,
 authenticode(filename=OSPath) AS CetInfo,
 parse_pe(file=OSPath) as PEInfo
 FROM glob(globs=TargetGlobs.Glob,
 accessor='ntfs')
 })

 - name: Chrysalis network indicators
 query: |
 SELECT * FROM if(
 condition=NetworkMemory,
 then={
 SELECT *
 FROM Artifact.Windows.Detection.Yara.Process(
 YaraRule=NetworkYara,
 NumberOfHits=1,
 ContextBytes=250
 )
 })
 
 - name: Warbird clipc.dll
 query: |
 SELECT * FROM if(
 condition=Warbird,
 then={
 SELECT ProcessCreateTime,
 Pid,Name,MappingName,
 AddressRange,Type,
 ProtectionMsg, 
 SectionSize,
 YaraHit.Rule as Rule,
 YaraHit.Offset as HitOffset,
 YaraHit.Name as HitName,
 HitContext,
 ProcessChain
 FROM Artifact.Windows.System.VAD(
 MappingNameRegex='''clipc\.dll$''',
 ProtectionRegex='xr-',
 SuspiciousContent=WarbirdYara)
 })
 
 - name: Disk YARA
 query: |
 SELECT * FROM if(
 condition=DiskYara,
 then={
 SELECT *
 FROM Artifact.Windows.Detection.Yara.Glob(
 PathGlob=DiskYaraGlob,
 YaraRule=ChrysalisYara
 )
 })

column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.MagicWeb</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/magicweb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/magicweb/</guid><description>&lt;p&gt;This artifact will find evidence of NOBELIUM’s MagicWeb.&lt;/p&gt;
&lt;p&gt;The artifact consists of two checks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Search for non default PublicKeyToken references in the
Microsoft.IdentityServer.Servicehost.exe.config file (31bf3856ad364e35 default).&lt;/li&gt;
&lt;li&gt;Search for untrusted authenticode Microsoft.IdentityServer.*.dll files&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.MagicWeb
author: Matt Green - @mgreen27
description: |
 This artifact will find evidence of NOBELIUM’s MagicWeb.
 
 The artifact consists of two checks:
 
 1. Search for non default PublicKeyToken references in the 
 Microsoft.IdentityServer.Servicehost.exe.config file (31bf3856ad364e35 default). 
 2. Search for untrusted authenticode Microsoft.IdentityServer.*.dll files

reference:
 - https://www.microsoft.com/security/blog/2022/08/24/magicweb-nobeliums-post-compromise-trick-to-authenticate-as-anyone/

parameters:
 - name: ConfigFileGlob
 default: C:\Windows\{AD FS,ADFS}\Microsoft.IdentityServer.Servicehost.exe.config
 description: File names to target
 - name: ExcludeToken
 default: ^31bf3856ad364e35$
 type: regex
 description: Legit tokens to exclude from results
 - name: TargetDllGlob
 default: 'C:\Windows\Microsoft.NET\assembly\**\Microsoft.IdentityServer.*.dll'
 - name: UploadHits
 description: select to upload file hits
 type: bool

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows' 
 query: |
 LET targets = SELECT OSPath,Size,Mtime,Atime,Ctime,Btime
 FROM glob(globs=ConfigFileGlob)

 LET hits = SELECT * FROM foreach(row=targets,
 query={
 SELECT 
 OSPath,Size,
 dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as Timestamps,
 PublicKeyToken,
 read_file(filename=OSPath) as Data
 FROM parse_records_with_regex(file=OSPath,regex='PublicKeyToken=(?P&amp;lt;PublicKeyToken&amp;gt;[^,]+),')
 WHERE NOT PublicKeyToken =~ ExcludeToken
 GROUP BY OSPath, PublicKeyToken
 })

 LET upload_hits = SELECT *, upload(file=OSPath) as Upload FROM hits
 
 SELECT *
 FROM if(condition=UploadHits,
 then= upload_hits,
 else= hits )

 - name: BinaryPayload
 description: Searches for untrusted Microsoft.IdentityServer dll files
 query: |
 LET binaries = SELECT 
 OSPath,Size,
 authenticode(filename=OSPath).Trusted as Authenticode,
 dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as Timestamps,
 parse_pe(file=OSPath) as PE,
 hash(path=OSPath) as Hash
 FROM glob(globs=TargetDllGlob)
 WHERE Authenticode =~ 'untrusted'

 LET upload_binaries = SELECT *, upload(file=OSPath) as Upload FROM binaries
 
 SELECT *
 FROM if(condition=UploadHits,
 then= upload_binaries,
 else= binaries )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Malfind</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/malfind/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/malfind/</guid><description>&lt;p&gt;This artifact checks the VAD for executable sections that are not maped to disk
and has suspicious content which may indicate process injection.&lt;/p&gt;
&lt;p&gt;User options allow targetting process, modifying suspicious content yara, or
upload of suspicious section.&lt;/p&gt;
&lt;p&gt;Default suspicious content includes headers: MZ, default cobalt strike stomped,
or well known suspicious strings, meterpreter and Cobalt Strike.&lt;/p&gt;
&lt;p&gt;Note: Add additional yara as desired.&lt;br&gt;
Expect some false positives and triage accordingly.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Malfind
author: Matt Green - @mgreen27
description: |
 This artifact checks the VAD for executable sections that are not maped to disk 
 and has suspicious content which may indicate process injection.
 
 User options allow targetting process, modifying suspicious content yara, or 
 upload of suspicious section.
 
 Default suspicious content includes headers: MZ, default cobalt strike stomped, 
 or well known suspicious strings, meterpreter and Cobalt Strike.
 
 Note: Add additional yara as desired. 
 Expect some false positives and triage accordingly. 
 
parameters:
 - name: ProcessRegex
 description: A regex applied to process names.
 default: .
 type: regex
 - name: PidRegex
 default: .
 type: regex
 - name: ProtectionRegex
 description: |
 Protection of section. Default is Executable but can customise for other usecases. 
 Examples: x for executable, r for read, w for write. 
 (x|r|w) or xrw for multiple.
 x-w for strict.
 default: xrw
 type: regex
 - name: SectionDataGuiSize
 description: Size of SectionData to show in gui. For large files, use UploadSection
 default: 10000
 type: int
 - name: SuspiciousContent
 description: A yara rule of suspicious section content 
 type: yara
 default: |
 rule win_cobalt_strike_auto {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2019-11-26"
 version = "1"
 description = "autogenerated rule brought to you by yara-signator"
 tool = "yara-signator 0.2a"
 malpedia_reference = "https://malpedia.caad.fkie.fraunhofer.de/details/win.cobalt_strike"
 malpedia_license = "CC BY-SA 4.0"
 malpedia_sharing = "TLP:WHITE"

 strings:
 $sequence_0 = { 3bc7 750d ff15???????? 3d33270000 }
 $sequence_1 = { e9???????? eb0a b801000000 e9???????? }
 $sequence_2 = { 8bd0 e8???????? 85c0 7e0e }
 $sequence_3 = { ffb5f8f9ffff ff15???????? 8b4dfc 33cd e8???????? c9 c3 }
 $sequence_4 = { e8???????? e9???????? 833d?????????? 7505 e8???????? }
 $sequence_5 = { 250000ff00 33d0 8b4db0 c1e908 }
 $sequence_6 = { ff75f4 ff7610 ff761c ff75fc }
 $sequence_7 = { 8903 6a06 eb39 33ff 85c0 762b 03f1 }
 $sequence_8 = { 894dd4 8b458c d1f8 894580 8b45f8 c1e818 0fb6c8 }
 $sequence_9 = { 890a 8b4508 0fb64804 81e1ff000000 c1e118 8b5508 0fb64205 }
 $sequence_10 = { 33d2 e8???????? 48b873797374656d3332 4c8bc7 488903 49ffc0 }
 $sequence_11 = { 488bd1 498d4bd8 498943e0 498943e8 }
 $sequence_12 = { b904000000 486bc90e 488b542430 4c8b442430 418b0c08 8b0402 }
 $sequence_13 = { ba80000000 e8???????? 488d4c2438 e8???????? 488d4c2420 8bd0 e8???????? }
 $sequence_14 = { 488b4c2430 8b0401 89442428 b804000000 486bc004 }
 $sequence_15 = { 4883c708 4883c304 49ffc3 48ffcd 0f854fffffff 488d4c2420 }

 condition:
 7 of them
 }

 rule win_meterpreter_auto {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2022-08-05"
 version = "1"
 description = "Detects win.meterpreter."
 info = "autogenerated rule brought to you by yara-signator"
 tool = "yara-signator v0.6.0"
 signator_config = "callsandjumps;datarefs;binvalue"
 malpedia_reference = "https://malpedia.caad.fkie.fraunhofer.de/details/win.meterpreter"
 malpedia_rule_date = "20220805"
 malpedia_hash = "6ec06c64bcfdbeda64eff021c766b4ce34542b71"
 malpedia_version = "20220808"
 malpedia_license = "CC BY-SA 4.0"
 malpedia_sharing = "TLP:WHITE"

 strings:
 $sequence_0 = { e22b e5f6 4f 1c8b }
 $sequence_1 = { 90 90 90 55 e4ec 53 8b22 }
 $sequence_2 = { 50 686cd4408e ffd6 8b0d???????? 83c18a }
 $sequence_3 = { 008b35a8c19f 006860 2f 0000 52 ffd6 }
 $sequence_4 = { 8b87047945f4 6a01 50 52 c745fc00000000 ff08 98 }
 $sequence_5 = { 57 40 388bf083c4cf 86f6 }
 $sequence_6 = { 8932 8b700c 83c204 4e 3bce 74ef ff9a0c8b5c03 }
 $sequence_7 = { 043b 8801 41 0fc2049088 0135???????? 4f 75b5 }
 $sequence_8 = { 6c 50 048b 55 1491 48 }
 $sequence_9 = { 76e1 8bf0 85f6 750e }

 condition:
 7 of them
 }
 rule suspicious {
 meta:
 author = "Matt Green - @mgreen27"
 description = "Suspicious unbacked on disk executable section content"
 date = "2022-09-30"

 strings:
 $header1 = "MZ"
 $header2 = { 00 00 41 52 55 48 } // cobalt strike stomped dll

 $body1 = "This program cannot be run in DOS mode" 
 $body2 = { FC E8 8? 00 00 00 60 } // shellcode prologe in metasploit

 condition:
 $header1 at 0 or $header2
 or any of ($body*) 
 }
 rule shellcode_get_eip
 {
 meta:
 author = "William Ballenthin"
 email = "william.ballenthin@fireeye.com"
 license = "Apache 2.0"
 copyright = "FireEye, Inc"
 description = "Match x86 that appears to fetch $PC."

 strings:
 $x86 = { e8 00 00 00 00 (58 | 5b | 59 | 5a | 5e | 5f) }

 condition:
 $x86
 }

 rule shellcode_peb_parsing
 {
 meta:
 author = "William Ballenthin"
 email = "william.ballenthin@fireeye.com"
 license = "Apache 2.0"
 copyright = "FireEye, Inc"
 description = "Match x86 that appears to manually traverse the TEB/PEB/LDR data."

 strings:
 $peb_parsing = { (64 a1 30 00 00 00 | 64 8b (1d | 0d | 15 | 35 | 3d) 30 00 00 00 | 31 (c0 | db | c9 | d2 | f6 | ff) [0-8] 64 8b ?? 30 ) [0-8] 8b ?? 0c [0-8] 8b ?? (0c | 14 | 1C) [0-8] 8b ?? (28 | 30) }
 $peb_parsing64 = { (48 65 A1 60 00 00 00 00 00 00 00 | 65 (48 | 4C) 8B ?? 60 00 00 00 | 65 A1 60 00 00 00 00 00 00 00 | 65 8b ?? ?? 00 FF FF | (48 31 (c0 | db | c9 | d2 | f6 | ff) | 4D 31 (c0 | c9)) [0-16] 65 (48 | 4d | 49 | 4c) 8b ?? 60) [0-16] (48 | 49 | 4C) 8B ?? 18 [0-16] (48 | 49 | 4C) 8B ?? (10 | 20 | 30) [0-16] (48 | 49 | 4C) 8B ?? (50 | 60) }

 condition:
 $peb_parsing or $peb_parsing64
 }

 rule shellcode_stack_strings
 {
 meta:
 author = "William Ballenthin"
 email = "william.ballenthin@fireeye.com"
 license = "Apache 2.0"
 copyright = "FireEye, Inc"
 description = "Match x86 that appears to be stack string creation."

 strings:
 // stack string near the frame pointer.
 $ss_small_bp = /(\xC6\x45.[a-zA-Z0-9 -~]){4,}\xC6\x45.\x00/

 // dword stack string near the frame pointer.
 $ss_small_bp_dword = /(\xC7\x45.[a-zA-Z0-9 -~]\x00[a-zA-Z0-9 -~]\x00){2,}\xC7\x45..\x00\x00\x00/

 // stack strings further away from the frame pointer.
 $ss_big_bp = /(\xC6\x85.[\xF0-\xFF]\xFF\xFF[a-zA-Z0-9 -~]){4,}\xC6\x85.[\xF0-\xFF]\xFF\xFF\x00/

 // stack string near the stack pointer.
 $ss_small_sp = /(\xC6\x44\x24.[a-zA-Z0-9 -~]){4,}\xC6\x44\x24.\x00/

 // stack strings further away from the stack pointer.
 $ss_big_sp = /(\xC6\x84\x24.[\x00-\x0F]\x00\x00[a-zA-Z0-9 -~]){4,}\xC6\x84\x24.[\x00-\x0F]\x00\x00\x00/

 condition:
 $ss_small_bp or $ss_small_bp_dword or $ss_big_bp or $ss_small_sp or $ss_big_sp
 }

 rule shellcode_shikataganai_encoding
 {
 meta:
 author = "Steven Miller"
 company = "FireEye"
 reference = "https://www.fireeye.com/blog/threat-research/2019/10/shikata-ga-nai-encoder-still-going-strong.html"
 strings:
 $varInitializeAndXorCondition1_XorEAX = { B8 ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 59 | 5A | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 40 | 41 | 42 | 43 | 45 | 46 | 47 ) ?? }
 $varInitializeAndXorCondition1_XorEBP = { BD ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 58 | 59 | 5A | 5B | 5C | 5E | 5F ) [0-50] 31 ( 68 | 69 | 6A | 6B | 6D | 6E | 6F ) ?? }
 $varInitializeAndXorCondition1_XorEBX = { BB ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 58 | 59 | 5A | 5C | 5D | 5E | 5F ) [0-50] 31 ( 58 | 59 | 5A | 5B | 5D | 5E | 5F ) ?? }
 $varInitializeAndXorCondition1_XorECX = { B9 ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 58 | 5A | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 48 | 49 | 4A | 4B | 4D | 4E | 4F ) ?? }
 $varInitializeAndXorCondition1_XorEDI = { BF ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 58 | 59 | 5A | 5B | 5C | 5D | 5E ) [0-50] 31 ( 78 | 79 | 7A | 7B | 7D | 7E | 7F ) ?? }
 $varInitializeAndXorCondition1_XorEDX = { BA ?? ?? ?? ?? [0-30] D9 74 24 F4 [0-10] ( 58 | 59 | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 50 | 51 | 52 | 53 | 55 | 56 | 57 ) ?? }
 $varInitializeAndXorCondition2_XorEAX = { D9 74 24 F4 [0-30] B8 ?? ?? ?? ?? [0-10] ( 59 | 5A | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 40 | 41 | 42 | 43 | 45 | 46 | 47 ) ?? }
 $varInitializeAndXorCondition2_XorEBP = { D9 74 24 F4 [0-30] BD ?? ?? ?? ?? [0-10] ( 58 | 59 | 5A | 5B | 5C | 5E | 5F ) [0-50] 31 ( 68 | 69 | 6A | 6B | 6D | 6E | 6F ) ?? }
 $varInitializeAndXorCondition2_XorEBX = { D9 74 24 F4 [0-30] BB ?? ?? ?? ?? [0-10] ( 58 | 59 | 5A | 5C | 5D | 5E | 5F ) [0-50] 31 ( 58 | 59 | 5A | 5B | 5D | 5E | 5F ) ?? }
 $varInitializeAndXorCondition2_XorECX = { D9 74 24 F4 [0-30] B9 ?? ?? ?? ?? [0-10] ( 58 | 5A | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 48 | 49 | 4A | 4B | 4D | 4E | 4F ) ?? }
 $varInitializeAndXorCondition2_XorEDI = { D9 74 24 F4 [0-30] BF ?? ?? ?? ?? [0-10] ( 58 | 59 | 5A | 5B | 5C | 5D | 5E ) [0-50] 31 ( 78 | 79 | 7A | 7B | 7D | 7E | 7F ) ?? }
 $varInitializeAndXorCondition2_XorEDX = { D9 74 24 F4 [0-30] BA ?? ?? ?? ?? [0-10] ( 58 | 59 | 5B | 5C | 5D | 5E | 5F ) [0-50] 31 ( 50 | 51 | 52 | 53 | 55 | 56 | 57 ) ?? }
 condition:
 any of them
 }
 
 - name: NumberOfHits
 description: THis artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int
 - name: UploadSection
 description: Upload suspicious section.
 type: bool


sources:
 - query: |
 LET processes = SELECT Pid, Name,Exe,CommandLine,CreateTime
 FROM pslist()
 WHERE Name =~ ProcessRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND log(message="Scanning pid %v : %v", args=[Pid, Name])

 LET hits = SELECT * FROM foreach(
 row=processes,
 query={
 SELECT CreateTime,Pid, Name,
 format(format='%x-%x', args=[Address, Address+Size]) AS AddressRange,
 Protection, Address as _Address,
 Size as SectionSize,
 pathspec(
 DelegateAccessor="process",
 DelegatePath=Pid,
 Path=Address) AS _PathSpec
 FROM vad(pid=Pid)
 WHERE NOT MappingName
 AND Protection =~ ProtectionRegex
 })
 
 LET results &amp;lt;= SELECT *,
 format(format='% x',args=read_file(
 accessor='offset',
 filename=_PathSpec,
 length=2)) as HexHeader,
 magic(path=_PathSpec, accessor='offset') as DataMagic,
 base64encode(string=read_file(
 accessor='offset',
 filename=_PathSpec,
 length= if(condition= SectionDataGuiSize &amp;gt; SectionSize,
 then= SectionSize,
 else= SectionDataGuiSize)
 )) as SectionData,
 YaraHit, _PathSpec
 FROM foreach(row=hits,
 query={
 SELECT
 CreateTime,Pid, Name,_Address, AddressRange,Protection,SectionSize,
 enumerate(items=dict(
 Rule=Rule,
 Meta=Meta,
 	Tags=Tags,
 	String=String)) as YaraHit,
 _PathSpec
 FROM yara(
 accessor='offset',
 files=_PathSpec, 
 rules=SuspiciousContent,
 end=SectionSize, key='X', 
 number=NumberOfHits,
 context=ContextBytes
 )
 GROUP BY CreateTime,Pid, Name, AddressRange
 })
 
 
 LET upload_section = SELECT *,
 upload(accessor='sparse', 
 file=pathspec(
 DelegateAccessor="process",
 DelegatePath=Pid,
 Path=[dict(Offset=_Address, Length=SectionSize),]), 
 name=format(format='%v-%v_%v.bin',args= [ Name, Pid, AddressRange ])
 ) as SectionDump
 FROM results
 GROUP BY CreateTime,Pid, Name,_Address, AddressRange
 
 SELECT *,
 process_tracker_callchain(id=Pid).Data as ProcessChain
 FROM if(condition= UploadSection,
 then= upload_section,
 else= results)
 
column_types:
 - name: SectionData
 type: base64hex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.MoveIt</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/moveit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/moveit/</guid><description>&lt;p&gt;This is an artifact to detect exploitation of a MoveIt critical vulnerability
observed in the wild. CVE-2023-34362&lt;/p&gt;
&lt;p&gt;The artifact enables detection via:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yara: webshell, assembly and IIS logs&lt;/li&gt;
&lt;li&gt;Evtx: IP ioc list and regex search&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last updated: 2023-06-05T06:46Z&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.MoveIt
author: Matt Green - @mgreen27
description: | 
 This is an artifact to detect exploitation of a MoveIt critical vulnerability 
 observed in the wild. CVE-2023-34362
 
 The artifact enables detection via:
 
 - Yara: webshell, assembly and IIS logs
 - Evtx: IP ioc list and regex search
 
 Last updated: 2023-06-05T06:46Z
 
reference:
 - https://www.rapid7.com/blog/post/2023/06/01/rapid7-observed-exploitation-of-critical-moveit-transfer-vulnerability/
 - https://community.progress.com/s/article/MOVEit-Transfer-Critical-Vulnerability-31May2023
 - https://github.com/Neo23x0/signature-base/blob/master/yara/vuln_moveit_0day_jun23.yar

type: CLIENT
resources:
 timeout: 1800

parameters:
 - name: EvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\MOVEit.evtx'
 - name: IocRegex
 type: regex
 description: "IOC Regex in evtxHunt"
 default: 'a@b\.com'
 - name: IgnoreRegex
 description: "Regex of string to ignore in Evtxhunt"
 type: regex
 - name: IpEvtxIoc
 default: |
 104.194.222.107
 146.0.77.141
 146.0.77.155
 146.0.77.183
 162.244.34.26
 162.244.35.6
 179.60.150.143
 185.104.194.156
 185.104.194.24
 185.104.194.40
 185.117.88.17
 185.162.128.75
 185.174.100.215
 185.174.100.250
 185.181.229.240
 185.181.229.73
 185.183.32.122
 185.185.50.172
 188.241.58.244
 193.169.245.79
 194.33.40.103
 194.33.40.104
 194.33.40.164
 206.221.182.106
 209.127.116.122
 209.127.4.22
 45.227.253.133
 45.227.253.147
 45.227.253.50
 45.227.253.6
 45.227.253.82
 45.56.165.248
 5.149.248.68
 5.149.250.74
 5.149.250.92
 5.188.86.114
 5.188.86.250
 5.188.87.194
 5.188.87.226
 5.188.87.27
 5.34.180.205
 62.112.11.57
 62.182.82.19
 62.182.85.234
 66.85.26.215
 66.85.26.234
 66.85.26.248
 79.141.160.78
 79.141.160.83
 84.234.96.31
 89.39.104.118
 89.39.105.108
 91.202.4.76
 91.222.174.95
 91.229.76.187
 93.190.142.131
 - name: DateAfter
 type: timestamp
 default: 1685232000
 description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: DateBefore
 type: timestamp
 description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: AllDrives
 type: bool
 description: "By default we target yara at all drives"
 default: Y
 - name: DriveLetter
 description: "Target yara drive. Default is a C: if not AllDrives"
 default: "C:"
 - name: AspxYara
 default: |
 rule WEBSHELL_ASPX_MOVEit_Jun23_1 {
 meta:
 description = "Detects ASPX web shells as being used in MOVEit Transfer exploitation"
 author = "Florian Roth"
 reference = "https://www.rapid7.com/blog/post/2023/06/01/rapid7-observed-exploitation-of-critical-moveit-transfer-vulnerability/"
 date = "2023-06-01"
 score = 85
 hash1 = "2413b5d0750c23b07999ec33a5b4930be224b661aaf290a0118db803f31acbc5"
 hash2 = "48367d94ccb4411f15d7ef9c455c92125f3ad812f2363c4d2e949ce1b615429a"
 hash3 = "e8012a15b6f6b404a33f293205b602ece486d01337b8b3ec331cd99ccadb562e"
 strings:
 $s1 = "X-siLock-Comment" ascii fullword 
 $s2 = "]; string x = null;" ascii
 $s3 = "; if (!String.Equals(pass, " ascii
 condition:
 filesize &amp;lt; 150KB and 2 of them
 }
 - name: DllYara
 default: |
 rule WEBSHELL_ASPX_DLL_MOVEit_Jun23_1 {
 meta:
 description = "Detects compiled ASPX web shells found being used in MOVEit Transfer exploitation"
 author = "Florian Roth"
 reference = "https://www.trustedsec.com/blog/critical-vulnerability-in-progress-moveit-transfer-technical-analysis-and-recommendations/?utm_content=251159938&amp;amp;utm_medium=social&amp;amp;utm_source=twitter&amp;amp;hss_channel=tw-403811306"
 date = "2023-06-01"
 score = 85
 hash1 = "6cbf38f5f27e6a3eaf32e2ac73ed02898cbb5961566bb445e3c511906e2da1fa"
 strings:
 $x1 = "human2_aspx" ascii fullword
 $x2 = "X-siLock-Comment" wide
 $x3 = "x-siLock-Step1" wide
 
 $a1 = "MOVEit.DMZ.Core.Data" ascii fullword
 condition:
 uint16(0) == 0x5a4d and
 filesize &amp;lt; 40KB and (
 1 of ($x*) and $a1
 ) or all of them
 }
 - name: LogYara
 default: |
 rule LOG_EXPL_MOVEit_Exploitation_Indicator_Jun23_1 {
 meta:
 description = "Detects a potential compromise indicator found in MOVEit Transfer logs"
 author = "Florian Roth"
 reference = "https://www.huntress.com/blog/moveit-transfer-critical-vulnerability-rapid-response"
 date = "2023-06-01"
 score = 70
 strings:
 $x1 = "POST /moveitisapi/moveitisapi.dll action=m2 " ascii
 $x2 = " GET /human2.aspx - 443 " ascii
 condition:
 1 of them
 }

 rule LOG_EXPL_MOVEit_Exploitation_Indicator_Jun23_2 {
 meta:
 description = "Detects a potential compromise indicator found in MOVEit Transfer logs"
 author = "Florian Roth"
 reference = "https://www.huntress.com/blog/moveit-transfer-critical-vulnerability-rapid-response"
 date = "2023-06-03"
 score = 70
 strings:
 $a1 = "Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/105.0.5195.102+Safari/537.36" ascii
 
 $s1 = " POST /moveitisapi/moveitisapi.dll" ascii
 $s2 = " POST /guestaccess.aspx"
 $s3 = " POST /api/v1/folders/"

 $s4 = "/files uploadType=resumable&amp;amp;"
 $s5 = " action=m2 "
 condition:
 1 of ($a*) and 3 of ($s*)
 or all of ($s*)
 }
 - name: NumberOfHits
 description: THis artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int64
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int
 - name: UploadYaraHits
 type: bool

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 
 name: Yara
 query: |
 -- check which Yara to use
 LET yara_rules &amp;lt;= AspxYara + '\n' + DllYara + '\n' + LogYara

 -- first find all matching files mft
 LET files = SELECT OSPath, IsDir
 FROM Artifact.Windows.NTFS.MFT(MFTDrive=DriveLetter, AllDrives=AllDrives,
 FileRegex='\.aspx$|^App_Web_[0-9a-z]{8}\.dll$|^u_.+\.log$',
 PathRegex='MoveIt|Microsoft\.net|temp|inetpub' )
 WHERE NOT IsDir
 AND NOT OSPath =~ '''.:\\&amp;lt;Err&amp;gt;\\'''
 AND (( FileName=~ '\.aspx$' AND OSPath =~ 'MoveIt' )
 OR (FileName=~ '^App_Web_[0-9a-z]{8}\.dll$' AND OSPath =~ 'Microsoft\.net|temp' )
 OR (FileName=~ '^u_.+\.log$' AND OSPath =~ 'inetpub' ))
 AND if(condition=DateAfter,
 then= LastRecordChange0x10 &amp;gt; DateAfter,
 else= True)
 AND if(condition=DateBefore,
 then= LastRecordChange0x10 &amp;lt; DateBefore,
 else= True)

 -- scan files and only report a single hit.
 LET hits = SELECT * FROM foreach(row=files,
 query={
 SELECT
 FileName, OSPath,
 File.Size AS Size,
 File.ModTime AS ModTime,
 Rule, Tags, Meta,
 String.Name as YaraString,
 String.Offset as HitOffset,
 upload( accessor='scope', 
 file='String.Data', 
 name=format(format="%v-%v-%v", 
 args=[
 OSPath,
 if(condition= String.Offset - ContextBytes &amp;lt; 0,
 then= 0,
 else= String.Offset - ContextBytes),
 if(condition= String.Offset + ContextBytes &amp;gt; File.Size,
 then= File.Size,
 else= String.Offset + ContextBytes) ]
 )) as HitContext
 FROM yara(rules=yara_rules, files=OSPath, context=ContextBytes,number=NumberOfHits)
 })

 -- upload files that have hit
 LET upload_hits=SELECT *,
 upload(file=OSPath) AS Upload
 FROM hits
 GROUP BY OSPath

 -- return rows
 SELECT * FROM if(condition=UploadYaraHits,
 then={ SELECT * FROM upload_hits},
 else={ SELECT * FROM hits})

 - name: Evtx
 query: |
 LET EvtxIPs &amp;lt;= SELECT _value as IP FROM foreach(row=split(string=IpEvtxIoc,sep='\\s')) WHERE _value
 LET EvtxHunterRegex = strip(string=join(array=EvtxIPs.IP + dict(Ioc=IocRegex).Ioc, sep='|'), suffix='|',prefix='|')
 LET Parse(X) = to_dict(
 item={
 SELECT split(sep=":", string=Column0)[0] AS _key,
 regex_replace(re="^\\s+|\\s+$", replace="", source=split(sep=":", string=Column0)[1]) AS _value
 FROM split_records(accessor="data", filenames=X, regex="\r\n")
 WHERE Column0 =~ "^[a-zA-Z0-9]+:"
 }) + parse_string_with_regex(regex="User '(?P&amp;lt;User&amp;gt;[^']+)'", string=X)

 SELECT EventTime,Computer,Channel,Provider,EventID,EventRecordID,
 Parse(X=split(string=EventData.Data[0],sep="\r\n\r\n")[1]) as EventData,
 split(string=EventData.Data[0],sep="\r\n\r\n")[0] as Message,
 FullPath,
 EventData.Data[0] as _RawData
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 IocRegex=EvtxHunterRegex,
 WhitelistRegex=IgnoreRegex,
 DateAfter=DateAfter,
 DateBefore=DateBefore )
 WHERE EventData.IPAddress in EvtxIPs.IP OR _RawData =~ IocRegex

column_types:
 - name: HitContext
 type: preview_upload
 - name: ModTime
 type: timestamp
 - name: EventTime
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.MsdtFollina</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/msdtfollina/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/msdtfollina/</guid><description>&lt;p&gt;This artifact will search Microsoft Support Diagnostic Tool logs for evidence
of ms-msdt Follina exploitation (CVE-2022-30190).&lt;/p&gt;
&lt;p&gt;The exploit appears to add a recursive path &amp;ldquo;../../&amp;rdquo; to a TargetPath field
inside the PCW.debugreport.xml.&lt;/p&gt;
&lt;p&gt;PCW.debugreport.xml can be found inside %localappdata%\Diagnostics or
%localappdata%\ElevatedDiagnostics for elevated instances.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.MsdtFollina
author: Matt Green - @mgreen27
description: |
 This artifact will search Microsoft Support Diagnostic Tool logs for evidence 
 of ms-msdt Follina exploitation (CVE-2022-30190).
 
 The exploit appears to add a recursive path "../../" to a TargetPath field 
 inside the PCW.debugreport.xml.
 
 PCW.debugreport.xml can be found inside %localappdata%\Diagnostics or 
 %localappdata%\ElevatedDiagnostics for elevated instances.
 
reference:
 - https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e
 - https://twitter.com/nas_bench/status/1531718490494844928
 

parameters:
 - name: TargetGlob
 default: C:\Users\*\AppData\Local\{Diagnostics,ElevatedDiagnostics}\**\PCW.debugreport.xml
 - name: MsdtYara
 default: |
 rule msdt
 {
 meta:
 description = "Simple yara to detect folder traversal string used in MSDT follina exploitation"
 date = "2022/06/01"
 strings:
 $a = "../../"
 condition:
 $a
 }

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

 query: |
 SELECT FullPath, Size,Mtime,Atime,Ctime,Btime,Rule,Meta,
 read_file(filename=FullPath) as Content
 FROM Artifact.Generic.Detection.Yara.Glob(PathGlob=TargetGlob,YaraRule=MsdtYara)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Network.Changed</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.network.changed/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.network.changed/</guid><description>&lt;p&gt;Detects when a new network is added or removed from the system via the NetworkList registry keys.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Network.Changed
author: Zane Gittins
description: |
 Detects when a new network is added or removed from the system via the NetworkList registry keys.

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT_EVENT


parameters:
 - name: Period
 default: 60
 type: int64
 description: The period to check the registry.
 - name: Globs
 type: string
 default: "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles\\**\\*"
 description: The registry path to search


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


 query: |
 SELECT * FROM diff(key="NetworkName", period=Period, query={
 SELECT Data.value as NetworkName from glob(accessor="reg",globs=Globs) WHERE Name=~"ProfileName" 
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Ntdsutil</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ntdsutil/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ntdsutil/</guid><description>&lt;p&gt;This artifact will extract evidence of Ntdsutil abuse from the application
eventlog. The artifact targets the string &amp;ldquo;ntds.dit&amp;rdquo; in event IDs: 216, 325,
326 and 327.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Ntdsutil
author: Matt Green - @mgreen27
description: |
 This artifact will extract evidence of Ntdsutil abuse from the application
 eventlog. The artifact targets the string "ntds.dit" in event IDs: 216, 325,
 326 and 327.

reference:
 - https://lolbas-project.github.io/lolbas/OtherMSBinaries/Ntdsutil/

parameters:
 - name: TargetGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 SELECT EventTime,
 Computer,Channel,EventID,EventRecordID,Message,EventData,FullPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=TargetGlob,
 IdRegex='^(216|325|326|327)$',
 IocRegex='ntds\.dit',
 VSSAnalysisAge=VSSAnalysisAge)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Onenote</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/onenote/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/onenote/</guid><description>&lt;p&gt;This artifact enables detection of malicious .one files and can also be used
as an embedded file and metadata parser.&lt;/p&gt;
&lt;p&gt;The artifact uses glob targeting and checks file headers to detect .one file
types in scope. Secondly the artifact looks for EmbeddedFile and Metadata headers.&lt;br&gt;
Finally the artifact will parse the .one file from discovered offsets and
enable filters to determine rows returned.&lt;/p&gt;
&lt;p&gt;By default filters target suspicious file content and metadata title text
observed in the wild.
Modify ContentRegex to &lt;code&gt;.&lt;/code&gt; to include all.&lt;/p&gt;
&lt;p&gt;The artifact also allows upload of both embedded files and source .one files.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Onenote
author: Matt Green - @mgreen27
description: |
 This artifact enables detection of malicious .one files and can also be used 
 as an embedded file and metadata parser.
 
 The artifact uses glob targeting and checks file headers to detect .one file 
 types in scope. Secondly the artifact looks for EmbeddedFile and Metadata headers. 
 Finally the artifact will parse the .one file from discovered offsets and 
 enable filters to determine rows returned. 
 
 By default filters target suspicious file content and metadata title text 
 observed in the wild.
 Modify ContentRegex to ```.``` to include all. 
 
 The artifact also allows upload of both embedded files and source .one files.
 
reference:
 - https://github.com/volexity/threat-intel/tree/main/tools/one-extract
 - https://blog.didierstevens.com/2023/01/22/analyzing-malicious-onenote-documents/
 
type: CLIENT

parameters:
 - name: TargetGlob
 description: Glob to target .one files
 default: C:\Users\**
 - name: ContentRegex
 description: Regex to filter for on embedded files or Title Metadata
 default: ^MZ|^TV(oA|pB|pQ|qA|qQ|ro)|^PK|This program cannot be run in dos mode.|@echo|&amp;lt;HTA:APPLICATION|/vbscript|WmiExec|Win32_Process|Powershell|comspec
 - name: PreviewBytes
 description: Number of bytes of embedded files to preview in hex
 type: int64
 default: 10000
 - name: ContentExclude
 description: Regex to filter out on embedded files or Title Metadata
 - name: IncludeAllMetadata
 type: bool
 description: Select to include all Metadata entries
 - name: UploadEmbedded
 type: bool
 description: Select to upload embedded files
 - name: UploadOriginal
 type: bool
 description: Upload original OneNote file
 
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows' OR OS = 'linux' OR OS = 'darwin'

 query: |
 LET YaraRule = '''rule onenote_headers {
 strings:
 $EmbeddedFile = { E7 16 E3 BD 65 26 11 45 A4 C4 8D 4D 0B 7A 9E AC }
 $Metadata = { F3 1C 00 1C 30 1C 00 1C FF 1D 00 14 82 1d 00 14 }
 
 condition:
 any of them
 }'''
 
 LET PROFILE = '''[[Metadata, 0, [
 ["__Adjust", 2, "uint16"],
 ["__SizeOffset",0,"Value",{"value":"x=&amp;gt;4 + (4 * x.__Adjust)"}],
 ["Size", "x=&amp;gt;x.__SizeOffset", "uint16"],
 ["__Title","x=&amp;gt;x.__SizeOffset + 4","String",{length: "x=&amp;gt;x.Size","term":"$$$_NOTERM_$$$"}],
 ["Title",0,"Value",{"value":"x=&amp;gt;regex_replace(source=x.__Title,re='\\x00',replace='')"}],
 ["CreateDate", "x=&amp;gt;x.__SizeOffset + 4 + x.Size + 32","WinFileTime"],
 # TODO remove recursion lookup and find specific details... 
 ["__FindOffset1", "x=&amp;gt;x.__SizeOffset + 4 + x.Size + 48","String",{length: 100, term_hex: "010100000000"}],
 ["__FindOffset2", "x=&amp;gt;x.__SizeOffset + 4 + x.Size + 48","String",{length: 100, term_hex: "010000000000"}],
 ["__ModificationOffset", 0,"Value",{"value":"x=&amp;gt;if(condition= len(list=x.__FindOffset1) &amp;lt; 100 OR len(list=x.__FindOffset2) &amp;lt; 100,
 then= if(condition= len(list=x.__FindOffset1) &amp;lt; len(list=x.__FindOffset2),
 then= x.__SizeOffset + 4 + x.Size + 48 + len(list=x.__FindOffset1) - 7,
 else= x.__SizeOffset + 4 + x.Size + 48 + len(list=x.__FindOffset2) - 7 ),
 else= null )"}],
 ["__ModificationDate", "x=&amp;gt;x.__ModificationOffset","WinFileTime"],
 ["ModificationDate", 0,"Value",{"value":"x=&amp;gt;if(condition= x.__ModificationOffset, 
 then= x.__ModificationDate,
 else= null)"}],
 ]],
 [EmbeddedFile, 0, [
 ["Size", 16, "uint32"],
 ["Magic",0,"Value",{"value":"x=&amp;gt;magic(accessor='data',path=read_file(filename=FileName,offset=String.Offset + 36,length=int(int=x.Size)))"}],
 ["Extension",0,"Value",{"value":"x=&amp;gt;magic(type='extension',accessor='data',path=read_file(filename=FileName,offset=String.Offset + 36,length=int(int=x.Size)))"}],
 ["SHA256",0,"Value",{"value":"x=&amp;gt;hash(hashselect='SHA256',accessor='data',path=read_file(filename=FileName,offset=String.Offset + 36,length=int(int=x.Size))).SHA256"}],
 ]]]'''
 
 -- firstly we want to find all target files in scope by confirming header
 LET target_files = SELECT OSPath,Name,Size,Mtime,Btime,Ctime,Atime	,
 hash(path=OSPath) as OneFileHash,
 format(format='% x',args=[read_file(filename=OSPath,length=16),]) as _Header
 FROM glob(globs=TargetGlob)
 WHERE NOT IsDir
 AND _Header = 'e4 52 5c 7b 8c d8 a7 4d ae b1 53 78 d0 29 96 d3'
 
 -- Hash source file here for performance
 LET target_files_hash = SELECT *, hash(path=OSPath) as Hash FROM target_files
 
 -- finally find all headers and parse from offset
 LET results = SELECT *,
 if(condition= Type='EmbeddedFile',
 then= read_file(filename=OSPath,offset=Offset,length= int(int=Extracted.Size)),
 else= null ) as _EmbeddedFile 
 FROM foreach(row=target_files_hash, query={
 SELECT OSPath,Name,Size,
 dict(Mtime=Mtime,Btime=Btime,Ctime=Ctime,Atime=Atime) as Timestamps,
 OneFileHash,
 if(condition= String.Name=~ 'metadata',
 then= String.Offset - 4,
 else= String.Offset + 36 ) as Offset,
 strip(string=String.Name,prefix='\$') as Type,
 parse_binary(filename=FileName, profile=PROFILE,
 offset=if(condition= String.Name=~ 'metadata',
 then= String.Offset - 4,
 else= String.Offset), 
 struct=if(condition= String.Name=~ 'metadata',
 then= 'Metadata',
 else= 'EmbeddedFile')) as Extracted
 FROM yara(files=OSPath,rules=YaraRule,number=9999)
 ORDER BY Offset
 })
 WHERE ( _EmbeddedFile =~ ContentRegex OR Extracted.Title =~ ContentRegex
 AND NOT if(condition= ContentExclude,
 then= _EmbeddedFile =~ ContentExclude,
 else = False ) )
 OR if(condition= IncludeAllMetadata, then= Type='Metadata')

 LET upload_embedded = SELECT OSPath,Name,Size,Timestamps,
 OneFileHash,
 Offset, Type, Extracted,
 if(condition= Type='EmbeddedFile',
 then= read_file(filename=_EmbeddedFile,accessor='data',length=PreviewBytes ),
 else= null ) as EmbeddedPreview,
 if(condition= Type='EmbeddedFile',
 then= upload(accessor='scope',file="_EmbeddedFile",
 name=format(format='%v_%v.extracted',args=[Name,Offset])),
 else= null ) as EmbeddedUpload 
 FROM results
 
 LET no_embedded_upload = SELECT OSPath,Name,Size,Timestamps,
 OneFileHash, Offset, Type, Extracted,
 if(condition= Type='EmbeddedFile',
 then= read_file(filename=_EmbeddedFile,accessor='data',length=PreviewBytes ),
 else= null ) as EmbeddedPreview
 FROM results
 
 -- output rows, hidden fields dropped
 LET final_results = SELECT * FROM if(condition=UploadEmbedded,
 then= upload_embedded,
 else= no_embedded_upload )
 
 -- finally we may want upload original OneNote file but only once for optimisation..
 LET lookup &amp;lt;= dict()
 LET upload_ospath = SELECT *,
 if(condition=get(item=lookup, field=OSPath.String), 
 else=if(condition=set(item=lookup, field=OSPath.String, value=TRUE),
 then=upload(file=OSPath))) AS OneFileUpload
 FROM final_results
 
 SELECT * FROM if(condition=UploadOriginal,
 then= upload_ospath,
 else= final_results )
 
column_types:
 - name: EmbeddedPreview
 type: base64hex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.PipeHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.pipehunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.pipehunter/</guid><description>&lt;p&gt;Takes a pipe name and returns the owning process and access rights. The primary
motivation for this artifact is a vulnerability in RemCom. RemCom is most
notably used by impacket psexec.py. It creates a null DACL for its
communication pipe. This means a low privileged user
could use a stale pipe to get remote execution as SYSTEM. If you uncover any
named pipes with the name RemCom_communication, investigate the owning proc
and remove it from the system.
#impacket&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.PipeHunter
author: ACEResponder.com
description: |
 Takes a pipe name and returns the owning process and access rights. The primary
 motivation for this artifact is a vulnerability in RemCom. RemCom is most 
 notably used by impacket psexec.py. It creates a null DACL for its 
 communication pipe. This means a low privileged user
 could use a stale pipe to get remote execution as SYSTEM. If you uncover any
 named pipes with the name RemCom_communication, investigate the owning proc
 and remove it from the system.
 #impacket

reference:
 - https://twitter.com/bugch3ck

parameters:
 - name: pipe_name
 default: "RemCom_communicaton"

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

 query: |
 LET ps = '''Add-Type -TypeDefinition @"
 using System;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
 
 public static class Kernel32
 {
 [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 public static extern IntPtr CreateFile(
 string filename,
 System.IO.FileAccess access,
 System.IO.FileShare share,
 IntPtr securityAttributes,
 System.IO.FileMode creationDisposition,
 uint flagsAndAttributes,
 IntPtr templateFile);
 [DllImport("kernel32.dll", SetLastError = true)]
 public static extern bool GetNamedPipeServerProcessId(IntPtr hPipe, out int ClientProcessId);
 
 [DllImport("kernel32.dll", SetLastError=true)]
 public static extern bool CloseHandle(IntPtr hObject);
 }
 "@
 $remcom=$null
 $pipeOwner=0

 try {
 #gci directly on the pipe does not work in some versions of posh for some reason
 $remcom = Get-ChildItem -ErrorAction Stop \\.\pipe\ -Filter '''
 LET ps2='''
 $output = New-Object PSObject -Property @{
 ProcessId = $null;
 ProcessName = $null;
 NamedPipe = $remcom.FullName;
 AccessControlType = $null;
 IdentityReference = $null;
 }
 try {
 $acl = $remcom.GetAccessControl();
 $output.AccessControlType = $acl.Access.AccessControlType;
 $output.IdentityReference = $acl.Access.IdentityReference.Value;
 }
 catch {
 }
 $hPipe = [Kernel32]::CreateFile($remcom.FullName, [System.IO.FileAccess]::Read, [System.IO.FileShare]::None, [System.IntPtr]::Zero, [System.IO.FileMode]::Open, [System.UInt32]::0x80, [System.IntPtr]::Zero);
 $pipeOwnerFound = [Kernel32]::GetNamedPipeServerProcessId([System.IntPtr]$hPipe, [ref]$pipeOwner);
 if ($pipeOwnerFound) {
 # Now that we have the process id, Get process name
 $processName = Get-WmiObject -Query "SELECT Caption FROM Win32_Process WHERE ProcessID = $pipeOwner" | select -ExpandProperty Caption;
 
 # Add to the name and ID to output
 $output.ProcessID = $pipeOwner;
 $output.ProcessName = $processName;
 
 }
 if($output.NamedPipe){
 $output | ConvertTo-JSON
 }
 #close the handle to the pipe
 $closed = [Kernel32]::CloseHandle($hPipe);
 
 }
 catch {
 write-host $_;
 }
 
 '''

 SELECT * FROM execve(argv=["Powershell", "-ExecutionPolicy",
 "unrestricted", "-c", ps+pipe_name+ps2]) 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.PrefetchHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/prefetchhunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/prefetchhunter/</guid><description>&lt;p&gt;This artifact enables hunting prefetch entries for accessed files of interest.&lt;/p&gt;
&lt;p&gt;Returned results include relevant prefetch information like executable, accessed
file, and prefetch metadata.&lt;/p&gt;
&lt;p&gt;For example hunting MSBuild template files generated by an attack framework:&lt;br&gt;
ExecutableRegex = msbuild.exe&lt;br&gt;
TargetRegex = \Windows\Temp\&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.PrefetchHunter
author: Matt Green - @mgreen27
description: |
 This artifact enables hunting prefetch entries for accessed files of interest. 
 
 Returned results include relevant prefetch information like executable, accessed 
 file, and prefetch metadata. 
 
 For example hunting MSBuild template files generated by an attack framework: 
 ExecutableRegex = msbuild.exe 
 TargetRegex = \\Windows\\Temp\\
 
parameters:
 - name: PrefetchGlobs
 description: "Target prefetch files"
 default: C:\Windows\Prefetch\*.pf
 - name: DateAfter
 description: "search for prefetch files with M or B time after this date. YYYY-MM-DDTmm:hh:ssZ"
 type: timestamp
 - name: DateBefore
 description: "search for prefetch files with M or B before this date. YYYY-MM-DDTmm:hh:ssZ"
 type: timestamp
 - name: ExecutableRegex
 description: "Regex of executable name. e.g msbuild.exe"
 default: .
 type: regex
 - name: TargetRegex
 description: "Regex of accessed files to hunt for. e.g \\.tmp$"
 default: .
 type: regex
 - name: TargetWhitelist
 description: "A regex to apply as a whitelist to exclude from accessed files."
 type: regex
 
sources:
 - query: |
 -- Parse prefetch files and applying artifact level filters
 LET prefetch = SELECT * 
 Executable,
 FilesAccessed,
 OSPath,
 Hash,
 Binary,
 ModificationTime,CreationTime
 FROM Artifact.Windows.Forensics.Prefetch(
 prefetchGlobs=PrefetchGlobs,binaryRegex=ExecutableRegex,
 dateAfter=DateAfter,dateBefore=DateBefore,
 IncludeFilesAccessed='Y')
 
 -- flattern FilesAccessed and apply filter
 SELECT Executable,
 FilesAccessed as FileAccessed,
 OSPath,
 ModificationTime,CreationTime,
 Hash,
 Binary
 FROM flatten(query=prefetch)
 WHERE 
 FileAccessed =~ TargetRegex
 AND NOT if(condition=TargetWhitelist,
 then= FileAccessed =~ TargetWhitelist,
 else= False)
 GROUP BY Executable,FileAccessed,Binary
 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.PrintNightmare</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/printnightmare/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/printnightmare/</guid><description>&lt;p&gt;This artifact returns any binaries in the Windows/spool/drivers/**
folders with an untrusted Authenticode entry.&lt;/p&gt;
&lt;p&gt;It can be used to hunt for dll files droped during exploitation of
CVE-2021-1675 - PrintNightmare.&lt;/p&gt;
&lt;p&gt;To query all attached ntfs drives: check the AllDrives switch.&lt;/p&gt;
&lt;p&gt;I have added several filters to uplift search capabilities from the
original MFT artifact. Due to the multi-drive features, the MFTPath
will output the MFT path of the entry.&lt;/p&gt;
&lt;p&gt;Available filters include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FullPath regex&lt;/li&gt;
&lt;li&gt;FileName regex&lt;/li&gt;
&lt;li&gt;Time bounds to select files with a timestamp within time ranges&lt;/li&gt;
&lt;li&gt;FileSize bounds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;






&lt;figure id="acda82c2e312808909aff4937560beef"&gt;
 &lt;div data-featherlight="#acda82c2e312808909aff4937560beef" class="figure"&gt;
 &lt;img src="https://docs.velociraptor.app/exchange/artifacts/pages/printnightmare/https://github.com/mgreen27/velociraptor-docs/raw/patch-5/content/exchange/artifacts/PrintNightmare.png" alt="Sample output" /&gt;
 &lt;/div&gt;
 &lt;figcaption&gt;
 Sample output
 &lt;/figcaption&gt;
&lt;/figure&gt;


&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.PrintNightmare
author: "Matt Green - @mgreen27"
description: |
 This artifact returns any binaries in the Windows/spool/drivers/**
 folders with an untrusted Authenticode entry.

 It can be used to hunt for dll files droped during exploitation of
 CVE-2021-1675 - PrintNightmare.

 To query all attached ntfs drives: check the AllDrives switch.

 I have added several filters to uplift search capabilities from the
 original MFT artifact. Due to the multi-drive features, the MFTPath
 will output the MFT path of the entry.

 Available filters include:
 - FullPath regex
 - FileName regex
 - Time bounds to select files with a timestamp within time ranges
 - FileSize bounds

 ![Sample output](https://github.com/mgreen27/velociraptor-docs/raw/patch-5/content/exchange/artifacts/PrintNightmare.png)

parameters:
 - name: MFTFilename
 default: "C:/$MFT"
 - name: Accessor
 default: ntfs
 type: hidden
 - name: PathRegex
 description: "Regex search over FullPath."
 default: Windows/System32/spool/drivers
 - name: FileRegex
 description: "Regex search over File Name"
 default: .
 - name: AllAuthenticode
 type: bool
 description: "Show all binaries despite Authenticode trusted status (default shows only untrusted)."
 - 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 under this size in bytes."
 - name: SizeMin
 type: int64
 description: "Entries in the MFT over this size in bytes."
 - name: AllDrives
 type: bool
 description: "Select MFT search on all attached ntfs drives."


sources:
 - query: |
 -- time testing
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))


 -- find all ntfs drives
 LET ntfs_drives = SELECT FullPath + '/$MFT'as Path
 FROM glob(globs="/*", accessor="ntfs")


 -- function returning MFT entries
 LET mftsearch(MFTPath) = SELECT
 split(sep='\\$',string=MFTPath)[0] + FullPath as FullPath,
 InUse,FileName,FileSize,
 dict(
 Created0x10 = Created0x10,
 LastModified0x10 = LastModified0x10,
 LastRecordChange0x10 = LastRecordChange0x10,
 LastAccess0x10 = LastAccess0x10
 ) as SI,
 dict(
 Created0x30 = Created0x10,
 LastModified0x30 = LastModified0x10,
 LastRecordChange0x30 = LastRecordChange0x10,
 LastAccess0x30 = LastAccess0x10
 ) as FN
 FROM parse_mft(filename=MFTPath, accessor=Accessor)
 WHERE NOT IsDir
 AND FullPath =~ PathRegex
 AND FileName =~ FileRegex
 AND if(condition=SizeMax,
 then=FileSize &amp;lt; atoi(string=SizeMax),
 else=TRUE)
 AND if(condition=SizeMin,
 then=FileSize &amp;gt; atoi(string=SizeMin),
 else=TRUE)
 AND
 ( time_test(stamp=Created0x10)
 OR time_test(stamp=Created0x30)
 OR time_test(stamp=LastModified0x10)
 OR time_test(stamp=LastModified0x30)
 OR time_test(stamp=LastRecordChange0x10)
 OR time_test(stamp=LastRecordChange0x30)
 OR time_test(stamp=LastAccess0x10)
 OR time_test(stamp=LastAccess0x30))


 -- include all attached drives
 LET all_drives = SELECT * FROM foreach(row=ntfs_drives,
 query={
 SELECT *
 FROM mftsearch(MFTPath=Path)
 WHERE log(message="Processing " + Path)
 })


 -- return rows
 SELECT *,
 parse_pe(file=FullPath) as PE,
 authenticode(filename=FullPath) as Authenticode,
 hash(path=FullPath) as Hash
 FROM if(condition=AllDrives,
 then= all_drives,
 else= {
 SELECT * FROM mftsearch(MFTPath=MFTFilename)
 })
 WHERE PE
 AND if(condition=AllAuthenticode,
 then=TRUE,
 else= NOT Authenticode.Trusted = 'trusted')

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.ProxyHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/proxyhunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/proxyhunter/</guid><description>&lt;p&gt;This artifact detects evidence of several common proxy tools.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hunt through Event Logs for potential evidence of proxy tool commandline.&lt;/li&gt;
&lt;li&gt;Checks active connections for proxy tool commandline (for active threat)&lt;/li&gt;
&lt;li&gt;Checks port proxy registry key for OS level forwarding&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;NOTE: this artifact is Windows only. Similar queries for 2. can be run on linux and macos&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.ProxyHunter
author: Matt Green - @mgreen27
description: |
 This artifact detects evidence of several common proxy tools.

 1. Hunt through Event Logs for potential evidence of proxy tool commandline.
 2. Checks active connections for proxy tool commandline (for active threat)
 3. Checks port proxy registry key for OS level forwarding

 NOTE: this artifact is Windows only. Similar queries for 2. can be run on linux and macos

type: CLIENT

parameters:
 - name: TargetGlob
 description: Glob target for event log regex search
 default: '%SystemRoot%\\System32\\Winevt\\Logs\\*{Powershell,Security,Sysmon}*.evtx'
 - name: ProxyCliRegex
 type: regex
 description: Regex to detect proxy tool cli. Default example includes plink.
 default: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}:\d{1,5}\s+-p|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5} :\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}:socks
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 -- firstly hunt through Event Logs for potential evidence of proxy tool commandline
 SELECT EventTime, Computer, Channel, Provider,
 EventID, EventData, UserData, Message, FullPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 IocRegex=ProxyCliRegex,
 EvtxGlob=TargetGlob,
 VSSAnalysisAge=VSSAnalysisAge)

 - name: ActiveConnections
 query: |
 -- Secondly check for proxy CLI with potential active network connections by CLI.
 SELECT * FROM Artifact.Windows.Network.NetstatEnriched(CommandLineRegex=ProxyCliRegex,ProcessNameRegex='.')

 - name: PortProxy
 query: |
 -- next we check for Windows inbuilt proxy config usually empty
 SELECT * FROM Artifact.Windows.Registry.PortProxy()

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.ProxyLogon.ProxyShell</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.proxylogon.proxyshell/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.proxylogon.proxyshell/</guid><description>&lt;p&gt;This artifact hunts for CVE-2021-27065 (Microsoft Exchange ProxyLogon RCE)
and CVE-2021-31207 (Microsoft Exchange ProxyShell RCE) exploitation by parsing
entries in the &amp;lsquo;MSExchange Management.evtx&amp;rsquo; log.&lt;/p&gt;
&lt;p&gt;This log file is unique to Exchange and can be useful when ECP logs are
no longer available.&lt;/p&gt;
&lt;p&gt;ProxyLogon webshell detection syntax is specific to
&amp;lsquo;China Chopper&amp;rsquo; via the PowerShell &amp;lsquo;Set-OabVirtualDirectory&amp;rsquo; cmdlet.&lt;/p&gt;
&lt;p&gt;ProxyShell webshell detection syntax is specific to PowerShell
&amp;lsquo;New-MailboxExportRequest&amp;rsquo; and &amp;lsquo;New-ExchangeCertificate&amp;rsquo; cmdlets.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.ProxyLogon.ProxyShell
description: |
 This artifact hunts for CVE-2021-27065 (Microsoft Exchange ProxyLogon RCE)
 and CVE-2021-31207 (Microsoft Exchange ProxyShell RCE) exploitation by parsing 
 entries in the 'MSExchange Management.evtx' log.

 This log file is unique to Exchange and can be useful when ECP logs are
 no longer available. 
 
 ProxyLogon webshell detection syntax is specific to 
 'China Chopper' via the PowerShell 'Set-OabVirtualDirectory' cmdlet.
 
 ProxyShell webshell detection syntax is specific to PowerShell 
 'New-MailboxExportRequest' and 'New-ExchangeCertificate' cmdlets.

author: Deepak Sharma - @rxurien

type: CLIENT

reference:
 - https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microsoft-exchange-zero-day-vulnerabilities/
 - https://www.mandiant.com/resources/change-tactics-proxyshell-vulnerabilities

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

parameters:
 - name: LogFile
 default: C:/Windows/System32/Winevt/Logs/MSExchange Management.evtx
 description: Default EVTX Path

sources:
 - queries:
 - SELECT timestamp(epoch=int(int=System.TimeCreated.SystemTime)) as CreationTime,
 System.Channel as Channel,
 System.EventID.Value as EventID,
 Message,
 EventData.Data[0] as Cmdlet,
 EventData.Data[1] as Payload,
 EventData
 
 FROM parse_evtx(filename=LogFile)

 WHERE (((Message =~ "new-mailboxexportrequest"or Message =~ "new-exchangecertificate") and Message =~ "aspx") or 
 ((Cmdlet =~ "new-mailboxexportrequest" or Cmdlet =~ "new-exchangecertificate") and Payload =~ "aspx") or 
 (Message =~ "set-oabvirtualdirectory" and Message =~ "script") or (Cmdlet =~ "set-oabvirtualdirectory" and Payload =~ "script"))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.PublicIP</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/publicip/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/publicip/</guid><description>&lt;p&gt;This artifact queries for RDP and Authentication events with a Public IP
source. The artifact uses Windows.EventLogs.RDPAuth and has several built in
notebooks for analysis.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.PublicIP
author: Matt Green - @mgreen27
description: |
 This artifact queries for RDP and Authentication events with a Public IP
 source. The artifact uses Windows.EventLogs.RDPAuth and has several built in
 notebooks for analysis.

type: CLIENT

parameters:
 - name: IncludeLocalhost
 description: include localhost and 127.0.0.1 events (may be noisy)
 type: bool
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 SELECT * FROM Artifact.Windows.EventLogs.RDPAuth(
 SourceIPRegex='''\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|localhost''',
 VSSAnalysisAge=VSSAnalysisAge )
 WHERE NOT SourceIP =~ '''^0\.''' -- Current network
 AND NOT SourceIP =~ '''^10\.''' -- Private network
 AND NOT SourceIP =~ '''^100\.(6[4-9]|[7-9][0-9]|1([0-1][0-9]|2[0-7]))\.''' -- Private network
 AND NOT if(condition= IncludeLocalhost,
 then= False,
 else= SourceIP =~ '''^127\.|localhost''' )-- Localhost
 AND NOT SourceIP =~ '''^169.254\.''' -- Link local
 AND NOT SourceIP =~ '''^172.(1[6-9]|2[0-9]|3[0-1])\.''' -- Private network
 AND NOT SourceIP =~ '''^192\.0\.0''' -- Private network
 AND NOT SourceIP =~ '''^192\.0\.2''' -- Documentation
 AND NOT SourceIP =~ '''^192\.88\.99\.''' -- Internet relay
 AND NOT SourceIP =~ '''^192\.168\.''' -- Private network
 AND NOT SourceIP =~ '''^198\.1[8-9]\.''' -- Private network
 AND NOT SourceIP =~ '''^198\.51\.100\.''' -- Documentation
 AND NOT SourceIP =~ '''^203\.0\.113\.''' -- Documentation
 AND NOT SourceIP =~ '''^2(2[4-9]|3[0-9])\.''' -- IP multicast
 AND NOT SourceIP =~ '''^233\.252\.''' -- Documentation
 AND NOT SourceIP =~ '''^2(4[0-9]|5[0-5])\.\d{1,3}\.\d{1,3}\.\d{1,2}[0-4]''' -- reserved
 AND NOT SourceIP =~ '''^255\.255\.255\.255$''' -- Broadcast

 notebook:
 - type: vql_suggestion
 name: Public IP
 template: |
 /*
 ### IPublic IP
 Triage view with suggested WHERE Lines

 */

 SELECT EventTime,Computer,Channel,
 EventID,LogonType,Description,
 DomainName +'/' + UserName as User,
 SourceIP,
 Message
 FROM source(artifact="Windows.Detection.PublicIP")
 WHERE True
 --AND EventTime &amp;gt; '2022-10'
 --AND EventTime &amp;lt; '2022-12'
 --AND SourceIP =~ '^127\\.|localhost'
 --AND NOT SourceIP =~ '^127\\.|localhost'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.ReflectedAssemblies</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/reflectedassemblies/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/reflectedassemblies/</guid><description>&lt;p&gt;Collects current running .NET assemblies and replicates ProcessHacker&amp;rsquo;s .NET
Assemblies view.&lt;/p&gt;
&lt;p&gt;By Default, the artifact will filter out assemblies with a ModulePath on disk
and built in Modules with Dynamic flag which indicate reflectively loaded
assemblies.&lt;/p&gt;
&lt;p&gt;Typical workflow would be to run once and scope the target ModuleID the rerun
and specifiy ModuleIDRegex to pull back module information.&lt;/p&gt;
&lt;p&gt;Queries the Microsoft-Windows-DotNETRuntimeRundown ETW provider so ensure
timeout path is sufficient.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.ReflectedAssemblies
author: "Matt Green - @mgreen27"
description: |
 Collects current running .NET assemblies and replicates ProcessHacker's .NET 
 Assemblies view.
 
 By Default, the artifact will filter out assemblies with a ModulePath on disk 
 and built in Modules with Dynamic flag which indicate reflectively loaded 
 assemblies.
 
 Typical workflow would be to run once and scope the target ModuleID the rerun 
 and specifiy ModuleIDRegex to pull back module information.
 
 Queries the Microsoft-Windows-DotNETRuntimeRundown ETW provider so ensure 
 timeout path is sufficient.
 
type: CLIENT

parameters:
 - name: ProcessRegex
 default: .
 type: regex
 - name: PidRegex
 default: .
 type: regex
 - name: Timeout
 default: 60
 type: int
 - name: AssemblyNameRegex
 default: .
 type: regex
 - name: ModuleIDRegex
 description: Regex of ModuleID to return Module Methods. Module Methods will not return unless configured.
 type: regex
 - name: ModulePathExclusion
 default: 'C:\\|\.dll$'
 type: regex
 - name: ShowAll
 description: By default we only show unmapped assemblies. This will ignore ModulePathExclusion to show all.
 type: bool

precondition: SELECT OS From info() where OS = 'windows'
sources:
 - query: |
 LET VQL_MATERIALIZE_ROW_LIMIT &amp;lt;= 27000
 
 LET collected &amp;lt;= SELECT System.ID AS EventID,
 System.ProcessID AS ProcessID,
 *
 FROM watch_etw(description="CLR Rundown Provider",
 guid="{A669021C-C450-4609-A035-5AF59AF4DF18}",
 any=if(condition= ModuleIDRegex,
 then= 0x78,
 else= 0x48),
 timeout=Timeout)
 WHERE ProcessID =~ PidRegex
 AND EventID in (151,153,155,157,187,143)
 AND log(message="CLR Rundown Provider any=" + if(condition=ModuleIDRegex,
 then="0x78",
 else="0x48"))
 
 LET ordered = SELECT *,
 format(format='%v_%v',
 args=[System.ProcessID,System.ID]) AS __OrderMe
 FROM collected
 WHERE NOT EventID = 143
 ORDER BY __OrderMe DESC
 
 LET Cache &amp;lt;= lru()
 
 LET results = SELECT
 process_tracker_get(id=ProcessID) AS ProcessDetails,
 get(item=Cache,
 field=format(format="AppDomainName%v_%v",
 args=[ProcessID, EventData.AppDomainID])) ||
 get(item=Cache,
 field=format(format="AppDomainName%v_%v",
 args=[ProcessID, get(
 item=Cache,
 field=format(
 format="AppDomainID%v_%v",
 args=[ProcessID, EventData.AssemblyID]))])) AS AppDomainName,
 EventData.ModuleID AS ModuleID,
 EventData.AssemblyID AS AssemblyID,
 EventData.ModuleFlags AS ModuleFlags,
 get(
 item=Cache,
 field=format(
 format="FullyQualifiedAssemblyName%v_%v",
 args=[ProcessID, EventData.AssemblyID])) AS FullyQualifiedAssemblyName,
 EventData.ModuleILPath AS ModuleILPath,
 get(
 item=Cache,
 field=format(
 format="ClrDetails%v",
 args=ProcessID)) AS ClrDetails
 FROM ordered
 WHERE (EventID = 157
 &amp;amp;&amp;amp; set(
 item=Cache,
 field=format(
 format="AppDomainName%v_%v",
 args=[ProcessID, EventData.AppDomainID]),
 value=EventData.AppDomainName), 
 EventID = 155
 &amp;amp;&amp;amp; set(
 item=Cache,
 field=format(
 format="FullyQualifiedAssemblyName%v_%v",
 args=[ProcessID, EventData.AssemblyID]),
 value=EventData.FullyQualifiedAssemblyName),
 EventID = 155
 &amp;amp;&amp;amp; set(
 item=Cache,
 field=format(
 format="AppDomainID%v_%v",
 args=[ProcessID, EventData.AssemblyID]),
 value=EventData.AppDomainID), 
 EventID = 187
 &amp;amp;&amp;amp; set(
 item=Cache,
 field=format(
 format="ClrDetails%v",
 args=ProcessID),
 value=dict(
 ClrInstanceID=EventData.ClrInstanceID,
 ClrVersion=format(
 format='%s.%s.%s.%s',
 args=[
 EventData.VMMajorVersion, 
 EventData.VMMinorVersion,
 EventData.VMBuildNumber, 
 EventData.VMQfeNumber]),
 RuntimeDllPath=EventData.RuntimeDllPath
 )),
 EventID = 151, 
 EventID = 153)
 AND EventID IN (151, 153)
 AND ProcessDetails.Data.Name =~ ProcessRegex
 
 -- match process hacker ModuleFlags
 LET PROFILE = '''[
 ["ClrDeets", 0, [
 ["ModuleFlags", 0, "Flags", {
 type: "uint32b",
 bitmap: {
 "DomainNeutral": 0,
 "Native": 1,
 "Dynamic": 2,
 }
 }],
 ]],
 ]'''

 LET hex_value(number) = format(format='0x%08x',args=int(int=number))
 
 LET final &amp;lt;= SELECT 
 dict(
 StartTime=ProcessDetails.StartTime,
 Pid=ProcessDetails.Id,
 Name=ProcessDetails.Data.Name,
 Exe=ProcessDetails.Data.Exe,
 CommandLine=ProcessDetails.Data.CommandLine,
 Username=ProcessDetails.Data.Username ) AS ProcessDetails, 
 AppDomainName,
 ModuleID,
 AssemblyID,
 join(array=parse_binary(accessor='data',filename=unhex(string=hex_value(number=ModuleFlags)),
 profile=PROFILE,struct='ClrDeets').ModuleFlags,sep=',') as ModuleFlags,
 FullyQualifiedAssemblyName,
 ModuleILPath,
 ClrDetails
 FROM results
 WHERE NOT ModuleILPath =~ ModulePathExclusion
 AND NOT ModuleFlags = 'Dynamic'
 AND FullyQualifiedAssemblyName =~ AssemblyNameRegex
 GROUP BY Address, AppDomainName, FullyQualifiedAssemblyName
 
 SELECT * FROM final
 
 - name: Module Methods
 query: |
 LET lookup &amp;lt;= SELECT * FROM final
 
 LET ModuleIDRegex2 &amp;lt;= join(array=final.ModuleID,sep='|')
 
 LET final_lookup(moduleid) = SELECT AppDomainName,AssemblyID,FullyQualifiedAssemblyName
 FROM lookup WHERE ModuleID = moduleid
 
 LET module_results = SELECT ProcessID,
 process_tracker_get(id=System.ProcessID).Data.Name AS ProcessName,
 EventData.MethodID as MethodID,
 EventData.ModuleID as ModuleID,
 EventData.MethodStartAddress as MethodStartAddress,
 EventData.MethodSize as MethodSize,
 EventData.MethodToken as MethodToken,
 EventData.MethodFlags as MethodFlags,
 EventData.MethodNamespace as MethodNamespace,
 EventData.MethodName as MethodName,
 EventData.MethodSignature as MethodSignature
 FROM collected
 WHERE System.ID = 143 
 AND ProcessName =~ ProcessRegex
 AND ModuleID =~ ModuleIDRegex
 AND ModuleID =~ ModuleIDRegex2
 
 SELECT ProcessID, ProcessName,
 final_lookup(moduleid=ModuleID )[0] as AssemblyDetails,
 ModuleID,
 MethodID,
 MethodStartAddress,
 MethodSize,
 MethodToken,
 MethodFlags,
 MethodNamespace,
 MethodName,
 MethodSignature
 FROM module_results

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.RemoteIconForcedAuth</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/remoteiconforcedauth/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/remoteiconforcedauth/</guid><description>&lt;p&gt;Attackers plant SCF, URL, and LNK files with malicious icon file paths
on file shares to escalate privileges or maintain persistence. This attack
only requires the user to browse to the location of the malicious file.
This artifact enumerates file shares and returns an event for each file with a
remote icon. It can also scan a target root directory since attackers commonly
use other locations like desktops.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.RemoteIconForcedAuth
author: ACEResponder.com
description: |
 Attackers plant SCF, URL, and LNK files with malicious icon file paths
 on file shares to escalate privileges or maintain persistence. This attack
 only requires the user to browse to the location of the malicious file.
 This artifact enumerates file shares and returns an event for each file with a
 remote icon. It can also scan a target root directory since attackers commonly
 use other locations like desktops.
reference:
 - https://www.cisa.gov/news-events/alerts/2017/10/20/advanced-persistent-threat-activity-targeting-energy-and-other
 - https://attack.mitre.org/techniques/T1187/
 - https://github.com/mdsecactivebreach/Farmer

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: AllShares
 description: Scan all file shares on the host (excluding hidden shares). This option will ignore TargetFolder.
 type: bool
 default: Y
 - name: AllowList
 description: Each entry in the AllowList is checked against the TargetHost field. Matches are omitted.
 type: csv
 default: |
 TargetHost
 - name: TargetFolder
 description: Root folder to search for SCF, URL, and LNK files. Uncheck AllShares to run. Backslashes should be escaped.
 default: C:\\


imports:
 - Windows.Forensics.Lnk

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

 query: |
 LET script = '''
 $out = @()
 (Get-SmbShare | Where-Object {-not $_.Name.endswith('$')} | Select-Object -property Path) | %{
 $out += New-Object PSObject -Property @{
 Path = $_.Path + '\**\*.lnk'
 }
 $out += New-Object PSObject -Property @{
 Path = $_.Path + '\**\*.url'
 }
 $out += New-Object PSObject -Property @{
 Path = $_.Path + '\**\*.scf'
 }
 }
 $out | ConvertTo-Json
 '''

 LET paths = SELECT * FROM if(
 condition=AllShares,
 then={SELECT * FROM foreach(row={SELECT Stdout FROM execve(argv=["Powershell", "-ExecutionPolicy","unrestricted", "-c", script], length=1000000)}, query = {SELECT * FROM parse_json_array(data=Stdout)})},
 else={SELECT * FROM parse_json_array(data='[{"Path":"'+TargetFolder+'\**\*"}]')}

 )


 LET hits = SELECT *, {
 SELECT *
 FROM Artifact.Windows.Forensics.Lnk(TargetGlob=FullPath)
 WHERE FullPath =~ "lnk$"
 } as lnk_file,
 {
 SELECT Data,
 parse_string_with_regex(
 string=Data,
 regex=['IconFile=(?P&amp;lt;IconLocation&amp;gt;.*)']) AS parsed

 FROM read_file(filenames=[FullPath])
 WHERE FullPath =~ '(scf|url)'
 } AS url_file

 FROM glob(globs=array(a={SELECT * FROM paths}))
 WHERE FullPath =~ "(scf|url|lnk)$" AND (lnk_file.Icons=~'^\\\\' OR url_file.parsed.IconLocation=~'^\\\\')

 LET final = SELECT *, parse_string_with_regex(string=IconLocation,regex=['^\\\\\\\\(?P&amp;lt;host&amp;gt;\[^\\\\\]+)']).host AS TargetHost FROM foreach(row={SELECT * FROM hits}, query={
 SELECT * FROM if(
 condition=lnk_file,
 then={SELECT Name, ModTime, FullPath, OSPath, Mtime, Btime, Ctime, Atime, lnk_file.Icons AS IconLocation FROM hits WHERE lnk_file.Icons},
 else={SELECT Name, ModTime, FullPath, OSPath, Mtime, Btime, Ctime, Atime, url_file.parsed.IconLocation AS IconLocation, url_file.Data AS Data FROM hits}
 )
 }) WHERE NOT TargetHost IN AllowList.TargetHost AND IconLocation

 SELECT * FROM final

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.ScmanagerBackdoor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.scmanagerbackdoor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.scmanagerbackdoor/</guid><description>&lt;p&gt;Checks for overly permissive DACLs on scmanager. Low priv Users with
KA - SDDL_KEY_ALL could launch SYSTEM services.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.ScmanagerBackdoor
author: ACEResponder.com
description: |
 Checks for overly permissive DACLs on scmanager. Low priv Users with
 KA - SDDL_KEY_ALL could launch SYSTEM services. 

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

 query: |
 LET ps = '''
 $sid_const_json = '{"AA":"SDDL_ACCESS_CONTROL_ASSISTANCE_OPS",
 "AC":"SDDL_ALL_APP_PACKAGES",
 "AN":"SDDL_ANONYMOUS",
 "AO":"SDDL_ACCOUNT_OPERATORS",
 "AP":"SDDL_PROTECTED_USERS",
 "AU":"SDDL_AUTHENTICATED_USERS",
 "BA":"SDDL_BUILTIN_ADMINISTRATORS",
 "BG":"SDDL_BUILTIN_GUESTS",
 "BO":"SDDL_BACKUP_OPERATORS",
 "BU":"SDDL_BUILTIN_USERS",
 "CA":"SDDL_CERT_SERV_ADMINISTRATORS",
 "CD":"SDDL_CERTSVC_DCOM_ACCESS",
 "CG":"SDDL_CREATOR_GROUP",
 "CN":"SDDL_CLONEABLE_CONTROLLERS",
 "CO":"SDDL_CREATOR_OWNER",
 "CY":"SDDL_CRYPTO_OPERATORS",
 "DA":"SDDL_DOMAIN_ADMINISTRATORS",
 "DC":"SDDL_DOMAIN_COMPUTERS",
 "DD":"SDDL_DOMAIN_DOMAIN_CONTROLLERS",
 "DG":"SDDL_DOMAIN_GUESTS",
 "DU":"SDDL_DOMAIN_USERS",
 "EA":"SDDL_ENTERPRISE_ADMINS",
 "ED":"SDDL_ENTERPRISE_DOMAIN_CONTROLLERS",
 "EK":"SDDL_ENTERPRISE_KEY_ADMINS",
 "ER":"SDDL_EVENT_LOG_READERS",
 "ES":"SDDL_RDS_ENDPOINT_SERVERS",
 "HA":"SDDL_HYPER_V_ADMINS",
 "HI":"SDDL_ML_HIGH",
 "IS":"SDDL_IIS_USERS",
 "IU":"SDDL_INTERACTIVE",
 "KA":"SDDL_KEY_ADMINS",
 "LA":"SDDL_LOCAL_ADMIN",
 "LG":"SDDL_LOCAL_GUEST",
 "LS":"SDDL_LOCAL_SERVICE",
 "LU":"SDDL_PERFLOG_USERS",
 "LW":"SDDL_ML_LOW",
 "ME":"SDDL_ML_MEDIUM",
 "MP":"SDDL_ML_MEDIUM_PLUS",
 "MU":"SDDL_PERFMON_USERS",
 "NO":"SDDL_NETWORK_CONFIGURATION_OPS",
 "NS":"SDDL_NETWORK_SERVICE",
 "NU":"SDDL_NETWORK",
 "OW":"SDDL_OWNER_RIGHTS",
 "PA":"SDDL_GROUP_POLICY_ADMINS",
 "PO":"SDDL_PRINTER_OPERATORS",
 "PS":"SDDL_PERSONAL_SELF",
 "PU":"SDDL_POWER_USERS",
 "RA":"SDDL_RDS_REMOTE_ACCESS_SERVERS",
 "RC":"SDDL_RESTRICTED_CODE",
 "RD":"SDDL_REMOTE_DESKTOP",
 "RE":"SDDL_REPLICATOR",
 "RM":"SDDL_RMS__SERVICE_OPERATORS",
 "RO":"SDDL_ENTERPRISE_RO_DCs",
 "RS":"SDDL_RAS_SERVERS",
 "RU":"SDDL_ALIAS_PREW2KCOMPACC",
 "SA":"SDDL_SCHEMA_ADMINISTRATORS",
 "SI":"SDDL_ML_SYSTEM",
 "SO":"SDDL_SERVER_OPERATORS",
 "SS":"SDDL_SERVICE_ASSERTED",
 "SU":"SDDL_SERVICE",
 "SY":"SDDL_LOCAL_SYSTEM",
 "UD":"SDDL_USER_MODE_DRIVERS",
 "WD":"SDDL_EVERYONE",
 "WR":"SDDL_WRITE_RESTRICTED_CODE"}'
 
 $sid_const = ConvertFrom-Json $sid_const_json
 
 $ace = ((&amp;amp; (Get-Command "$($env:SystemRoot)\System32\sc.exe") @('sdshow', 'scmanager'))[1])
 $dacl_string = [regex]::match($ace, '.*D:(.*)S:').Groups[1].value
 $dacls = [regex]::match($dacl_string, '(?:\(([^\)]*?)\))+').Groups[1].Captures
 foreach ($dacl in $dacls) {
 $descriptors = $dacl.Value.split(';')
 $ace_type = $descriptors[0]
 $rights = $descriptors[2] -split '(\w{2})'
 $acct_sid = $descriptors[5]
 if ($ace_type -eq 'A' -and $rights -contains 'KA' -and $acct_sid -notin $('BA', 'DA', 'EA', 'LA', 'SY')) {
 $output = New-Object PSObject -Property @{
 dacl = $dacl.Value;
 sid = $acct_sid;
 message = '';
 }
 if ($acct_sid.Length -eq 2) {
 $output.message = 'Suspicious scmanager DACL identified. Users with ' + ($sid_const | select -ExpandProperty $acct_sid) + ' can start SYSTEM services.'
 
 }
 else {
 $output.message = 'Suspicious scmanager DACL identified. User with SID ' + $acct_sid + ' can start SYSTEM services.'
 }
 $output | ConvertTo-Json
 }
 
 }
 
 '''

 SELECT * FROM execve(argv=["Powershell", "-ExecutionPolicy",
 "unrestricted", "-c", ps]) 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.SmoothOperator</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/smoothoperator/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/smoothoperator/</guid><description>&lt;p&gt;This artifact searches for evidence of trojanised 3CXDesktopApp.&lt;/p&gt;
&lt;p&gt;Currently Windows specific, Yara glob can be repurposed for MacOS.
Targeting /Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib&lt;/p&gt;
&lt;p&gt;There are three methods of detection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Yara glob - searches known install paths and applies yara looking for binary attributes.&lt;/li&gt;
&lt;li&gt;Process Memory - Searches for compromised 3CXDesktopApp running using Windows.System.VAD.&lt;/li&gt;
&lt;li&gt;AMCache - Searches for compromised 3CXDesktopApp.exe versions in AMCache.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Impacted 3CXDesktopApp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows: 18.12.407 &amp;amp; 18.12.416&lt;/li&gt;
&lt;li&gt;MacOS: 18.11.1213, 18.12.402, 18.12.407 &amp;amp; 18.12.416&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: artifact tested on 0.6.8 - should also work on on 0.6.7.&lt;br&gt;
Be aware that the YARA rules are intentionally written in a way that is less strict &amp;amp; may&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;detect other malicious samples created in the time frame in which the known malicious samples were created&lt;/li&gt;
&lt;li&gt;lead to some FPs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thank you to @cyb3rops for sharing rules.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.SmoothOperator
author: "Matt Green - @mgreen27"
description: |
 This artifact searches for evidence of trojanised 3CXDesktopApp.
 
 Currently Windows specific, Yara glob can be repurposed for MacOS. 
 Targeting /Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib 
 
 There are three methods of detection:
 
 1. Yara glob - searches known install paths and applies yara looking for binary attributes.
 2. Process Memory - Searches for compromised 3CXDesktopApp running using Windows.System.VAD.
 3. AMCache - Searches for compromised 3CXDesktopApp.exe versions in AMCache.
 
 Impacted 3CXDesktopApp:
 
 - Windows: 18.12.407 &amp;amp; 18.12.416
 - MacOS: 18.11.1213, 18.12.402, 18.12.407 &amp;amp; 18.12.416
 
 NOTE: artifact tested on 0.6.8 - should also work on on 0.6.7. 
 Be aware that the YARA rules are intentionally written in a way that is less strict &amp;amp; may

 1. detect other malicious samples created in the time frame in which the known malicious samples were created
 2. lead to some FPs
 
 Thank you to @cyb3rops for sharing rules.

reference:
 - https://raw.githubusercontent.com/Neo23x0/signature-base/master/yara/gen_mal_3cx_compromise_mar23.yar
 - https://twitter.com/cyb3rops/status/1641130326830333984
 - https://www.sentinelone.com/blog/smoothoperator-ongoing-campaign-trojanizes-3cx-software-in-software-supply-chain-attack/
 - https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/
type: CLIENT


parameters:
 - name: TargetGlob
 default: C:\Users\*\AppData\*\Programs\3CXDesktopApp\**.{dll,exe}
 - name: UploadHits
 description: Select to upload hits to server.
 type: bool
 - name: TargetYara
 default: |
 import "pe"
 
 rule APT_MAL_NK_3CX_Malicious_Samples_Mar23_1 {
 meta:
 description = "Detects malicious DLLs related to 3CX compromise"
 author = "X__Junior, Florian Roth (Nextron Systems)"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 date = "2023-03-29"
 score = 85
 hash1 = "7986bbaee8940da11ce089383521ab420c443ab7b15ed42aed91fd31ce833896"
 hash2 = "c485674ee63ec8d4e8fde9800788175a8b02d3f9416d0e763360fff7f8eb4e02"
 strings:
 $op1 = { 4C 89 F1 4C 89 EA 41 B8 40 00 00 00 FF 15 ?? ?? ?? ?? 85 C0 74 ?? 4C 89 F0 FF 15 ?? ?? ?? ?? 4C 8D 4C 24 ?? 45 8B 01 4C 89 F1 4C 89 EA FF 15 } /* VirtualProtect and execute payload*/
 $op2 = { 48 C7 44 24 ?? 00 00 00 00 4C 8D 7C 24 ?? 48 89 F9 48 89 C2 41 89 E8 4D 89 F9 FF 15 ?? ?? ?? ?? 41 83 3F 00 0F 84 ?? ?? ?? ?? 0F B7 03 3D 4D 5A 00 00} /* ReadFile and MZ compare*/
 $op3 = { 41 80 7C 00 ?? FE 75 ?? 41 80 7C 00 ?? ED 75 ?? 41 80 7C 00 ?? FA 75 ?? 41 80 3C 00 CE} /* marker */
 $op4 = { 44 0F B6 CD 46 8A 8C 0C ?? ?? ?? ?? 45 30 0C 0E 48 FF C1} /* xor part in RC4 decryption*/
 condition:
 uint16(0) == 0x5a4d
 and filesize &amp;lt; 3MB 
 and pe.characteristics &amp;amp; pe.DLL
 and 2 of them
 }

 rule APT_MAL_NK_3CX_Malicious_Samples_Mar23_2 {
 meta:
 description = "Detects malicious DLLs related to 3CX compromise (decrypted payload)"
 author = "Florian Roth (Nextron Systems)"
 reference = "https://twitter.com/dan__mayer/status/1641170769194672128?s=20"
 date = "2023-03-29"
 score = 80
 hash1 = "aa4e398b3bd8645016d8090ffc77d15f926a8e69258642191deb4e68688ff973"
 strings:
 $s1 = "raw.githubusercontent.com/IconStorages/images/main/icon%d.ico" wide fullword
 $s2 = "https://raw.githubusercontent.com/IconStorages" wide fullword
 $s3 = "icon%d.ico" wide fullword
 $s4 = "__tutmc" ascii fullword

 $op1 = { 2d ee a1 00 00 c5 fa e6 f5 e9 40 fe ff ff 0f 1f 44 00 00 75 2e c5 fb 10 0d 46 a0 00 00 44 8b 05 7f a2 00 00 e8 0a 0e 00 00 }
 $op4 = { 4c 8d 5c 24 71 0f 57 c0 48 89 44 24 60 89 44 24 68 41 b9 15 cd 5b 07 0f 11 44 24 70 b8 b1 68 de 3a 41 ba a4 7b 93 02 }
 $op5 = { f7 f3 03 d5 69 ca e8 03 00 00 ff 15 c9 0a 02 00 48 8d 44 24 30 45 33 c0 4c 8d 4c 24 38 48 89 44 24 20 }
 condition:
 uint16(0) == 0x5a4d and
 filesize &amp;lt; 900KB and 3 of them
 or 5 of them
 }

 rule APT_MAL_NK_3CX_Malicious_Samples_Mar23_3 {
 meta:
 description = "Detects malicious DLLs related to 3CX compromise (decrypted payload)"
 author = "Florian Roth , X__Junior"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 date = "2023-03-29"
 score = 80
 hash1 = "aa4e398b3bd8645016d8090ffc77d15f926a8e69258642191deb4e68688ff973"
 strings:
 $opa1 = { 41 81 C0 ?? ?? ?? ?? 02 C8 49 C1 E9 ?? 41 88 4B ?? 4D 03 D1 8B C8 45 8B CA C1 E1 ?? 33 C1 41 69 D0 ?? ?? ?? ?? 8B C8 C1 E9 ?? 33 C1 8B C8 C1 E1 ?? 81 C2 ?? ?? ?? ?? 33 C1 43 8D 0C 02 02 C8 49 C1 EA ?? 41 88 0B 8B C8 C1 E1 ?? 33 C1 44 69 C2 ?? ?? ?? ?? 8B C8 C1 E9 ?? 33 C1 8B C8 C1 E1 ?? 41 81 C0 } /*lcg chunk */
 $opa2 = { 8B C8 41 69 D1 ?? ?? ?? ?? C1 E1 ?? 33 C1 45 8B CA 8B C8 C1 E9 ?? 33 C1 81 C2 ?? ?? ?? ?? 8B C8 C1 E1 ?? 33 C1 41 8B C8 4C 0F AF CF 44 69 C2 ?? ?? ?? ?? 4C 03 C9 45 8B D1 4C 0F AF D7} /*lcg chunk */

 $opb1 = { 45 33 C9 48 89 6C 24 ?? 48 8D 44 24 ?? 48 89 6C 24 ?? 8B D3 48 89 B4 24 ?? ?? ?? ?? 48 89 44 24 ?? 45 8D 41 ?? FF 15 } /* base64 decode */
 $opb2 = { 44 8B 0F 45 8B C6 48 8B 4D ?? 49 8B D7 44 89 64 24 ?? 48 89 7C 24 ?? 44 89 4C 24 ?? 4C 8D 4D ?? 48 89 44 24 ?? 44 89 64 24 ?? 4C 89 64 24 ?? FF 15} /* AES decryption */
 $opb3 = { 48 FF C2 66 44 39 2C 56 75 ?? 4C 8D 4C 24 ?? 45 33 C0 48 8B CE FF 15 ?? ?? ?? ?? 85 C0 0F 84 ?? ?? ?? ?? 44 0F B7 44 24 ?? 33 F6 48 8B 54 24 ?? 45 33 C9 48 8B 0B 48 89 74 24 ?? 89 74 24 ?? C7 44 24 ?? ?? ?? ?? ?? 48 89 74 24 ?? FF 15 } /* internet connection */
 $opb4 = { 33 C0 48 8D 6B ?? 4C 8D 4C 24 ?? 89 44 24 ?? BA ?? ?? ?? ?? 48 89 44 24 ?? 48 8B CD 89 44 24 ?? 44 8D 40 ?? 8B F8 FF 15} /* VirtualProtect */
 condition:
 ( all of ($opa*) )
 or
 ( 1 of ($opa*) and 1 of ($opb*) )
 or
 ( 3 of ($opb*) )
 }

 rule SUSP_APT_MAL_NK_3CX_Malicious_Samples_Mar23_1 {
 meta:
 description = "Detects marker found in malicious DLLs related to 3CX compromise"
 author = "X__Junior, Florian Roth (Nextron Systems)"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 date = "2023-03-29"
 score = 75
 hash1 = "7986bbaee8940da11ce089383521ab420c443ab7b15ed42aed91fd31ce833896"
 hash2 = "c485674ee63ec8d4e8fde9800788175a8b02d3f9416d0e763360fff7f8eb4e02"
 strings:
 $opx1 = { 41 80 7C 00 FD FE 75 ?? 41 80 7C 00 FE ED 75 ?? 41 80 7C 00 FF FA 75 ?? 41 80 3C 00 CE } 
 condition:
 $opx1
 }

 rule APT_SUSP_NK_3CX_RC4_Key_Mar23_1 {
 meta:
 description = "Detects RC4 key used in 3CX binaries known to be malicious"
 author = "Florian Roth (Nextron Systems)"
 date = "2023-03-29"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 score = 70
 hash1 = "7986bbaee8940da11ce089383521ab420c443ab7b15ed42aed91fd31ce833896"
 hash2 = "59e1edf4d82fae4978e97512b0331b7eb21dd4b838b850ba46794d9c7a2c0983"
 hash3 = "aa124a4b4df12b34e74ee7f6c683b2ebec4ce9a8edcf9be345823b4fdcf5d868"
 hash4 = "c485674ee63ec8d4e8fde9800788175a8b02d3f9416d0e763360fff7f8eb4e02"
 strings:
 $x1 = "3jB(2bsG#@c7"
 condition:
 ( uint16(0) == 0xcfd0 or uint16(0) == 0x5a4d )
 and $x1
 }

 rule SUSP_3CX_App_Signed_Binary_Mar23_1 {
 meta:
 description = "Detects 3CX application binaries signed with a certificate and created in a time frame in which other known malicious binaries have been created"
 author = "Florian Roth (Nextron Systems)"
 date = "2023-03-29"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 score = 65
 hash1 = "fad482ded2e25ce9e1dd3d3ecc3227af714bdfbbde04347dbc1b21d6a3670405"
 hash2 = "dde03348075512796241389dfea5560c20a3d2a2eac95c894e7bbed5e85a0acc"
 strings:
 $sa1 = "3CX Ltd1"
 $sa2 = "3CX Desktop App" wide
 $sc1 = { 1B 66 11 DF 9C 9A 4D 6E CC 8E D5 0C 9B 91 78 73 } // Known compromised cert
 condition:
 uint16(0) == 0x5a4d
 and pe.timestamp &amp;gt; 1669680000 // 29.11.2022 earliest known malicious sample 
 and pe.timestamp &amp;lt; 1680108505 // 29.03.2023 date of the report
 and all of ($sa*)
 and $sc1 // serial number of known compromised certificate
 }

 rule SUSP_3CX_MSI_Signed_Binary_Mar23_1 {
 meta:
 description = "Detects 3CX MSI installers signed with a known compromised certificate and signed in a time frame in which other known malicious binaries have been signed"
 author = "Florian Roth (Nextron Systems)"
 date = "2023-03-29"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 score = 60
 hash1 = "aa124a4b4df12b34e74ee7f6c683b2ebec4ce9a8edcf9be345823b4fdcf5d868"
 hash2 = "59e1edf4d82fae4978e97512b0331b7eb21dd4b838b850ba46794d9c7a2c0983"
 strings:
 $a1 = { 84 10 0C 00 00 00 00 00 C0 00 00 00 00 00 00 46 } // MSI marker

 $sc1 = { 1B 66 11 DF 9C 9A 4D 6E CC 8E D5 0C 9B 91 78 73 } // Known compromised cert

 $s1 = "3CX Ltd1"
 $s2 = "202303" // in 
 condition:
 uint16(0) == 0xcfd0
 and $a1 
 and $sc1 
 and (
 $s1 in (filesize-20000..filesize)
 and $s2 in (filesize-20000..filesize)
 )
 }

 rule APT_MAL_macOS_NK_3CX_Malicious_Samples_Mar23_1 {
 meta:
 description = "Detects malicious macOS application related to 3CX compromise (decrypted payload)"
 author = "Florian Roth (Nextron Systems)"
 reference = "https://www.reddit.com/r/crowdstrike/comments/125r3uu/20230329_situational_awareness_crowdstrike/"
 date = "2023-03-30"
 score = 80
 hash1 = "b86c695822013483fa4e2dfdf712c5ee777d7b99cbad8c2fa2274b133481eadb"
 hash2 = "ac99602999bf9823f221372378f95baa4fc68929bac3a10e8d9a107ec8074eca"
 hash3 = "51079c7e549cbad25429ff98b6d6ca02dc9234e466dd9b75a5e05b9d7b95af72"
 strings:
 $s1 = "20230313064152Z0"
 $s2 = "Developer ID Application: 3CX (33CF4654HL)"
 condition:
 uint16(0) == 0xfeca and all of them
 }

 /* 30.03.2023 */

 rule APT_MAL_MacOS_NK_3CX_DYLIB_Mar23_1 {
 meta:
 description = "Detects malicious DYLIB files related to 3CX compromise"
 author = "Florian Roth"
 reference = "https://www.sentinelone.com/blog/smoothoperator-ongoing-campaign-trojanizes-3cx-software-in-software-supply-chain-attack/"
 date = "2023-03-30"
 score = 80
 hash1 = "a64fa9f1c76457ecc58402142a8728ce34ccba378c17318b3340083eeb7acc67"
 hash2 = "fee4f9dabc094df24d83ec1a8c4e4ff573e5d9973caa676f58086c99561382d7"
 strings:
 /* XORed UA 0x7a */
 $xc1 = { 37 15 00 13 16 16 1B 55 4F 54 4A 5A 52 2D 13 14 
 1E 15 0D 09 5A 34 2E 5A 4B 4A 54 4A 41 5A 2D 13
 14 4C 4E 41 5A 02 4C 4E 53 5A 3B 0A 0A 16 1F 2D
 1F 18 31 13 0E 55 4F 49 4D 54 49 4C 5A 52 31 32
 2E 37 36 56 5A 16 13 11 1F 5A 3D 1F 19 11 15 53
 5A 39 12 08 15 17 1F 55 4B 4A 42 54 4A 54 4F 49
 4F 43 54 4B 48 42 5A 29 1B 1C 1B 08 13 55 4F 49
 4D 54 49 4C 7A }
 /* /;3cx_auth_token_content=%s;__tutma= */
 $xc2 = { 41 49 19 02 25 1b 0f 0e 12 25 0e 15 11 1f 14 25 19 15 14 0e 1f 14 0e 47 5f 09 41 25 25 0e 0f 0e 17 1b 47 }
 /* /System/Library/CoreServices/SystemVersion.plist */
 $xc3 = { 55 29 03 09 0e 1f 17 55 36 13 18 08 1b 08 03 55 39 15 08 1f 29 1f 08 0c 13 19 1f 09 55 29 03 09 0e 1f 17 2c 1f 08 09 13 15 14 54 0a 16 13 09 0e }
 condition:
 1 of them
 }

 rule APT_SUSP_NK_3CX_Malicious_Samples_Mar23_1 {
 meta:
 description = "Detects indicator (event name) found in samples related to 3CX compromise"
 author = "Florian Roth"
 reference = "https://www.sentinelone.com/blog/smoothoperator-ongoing-campaign-trojanizes-3cx-software-in-software-supply-chain-attack/"
 date = "2023-03-30"
 score = 70
 hash1 = "7986bbaee8940da11ce089383521ab420c443ab7b15ed42aed91fd31ce833896"
 hash2 = "59e1edf4d82fae4978e97512b0331b7eb21dd4b838b850ba46794d9c7a2c0983"
 hash3 = "aa124a4b4df12b34e74ee7f6c683b2ebec4ce9a8edcf9be345823b4fdcf5d868"
 hash4 = "c485674ee63ec8d4e8fde9800788175a8b02d3f9416d0e763360fff7f8eb4e02"
 strings:
 $a1 = "AVMonitorRefreshEvent" wide fullword
 condition:
 1 of them
 }

 rule APT_MAL_NK_3CX_Malicious_Samples_Mar23_4 {
 meta:
 author = "MalGamy"
 reference = "https://twitter.com/WhichbufferArda/status/1641404343323688964?s=20"
 description = "Detects decrypted payload loaded inside 3CXDesktopApp.exe which downloads info stealer"
 date = "2023-03-29"
 hash = "851c2c99ebafd4e5e9e140cfe3f2d03533846ca16f8151ae8ee0e83c692884b7" 
 score = 80
 strings:
 $op1 = {41 69 D0 [4] 8B C8 C1 E9 ?? 33 C1 8B C8 C1 E1 ?? 81 C2 [4] 33 C1 43 8D 0C 02 02 C8 49 C1 EA ?? 41 88 0B 8B C8 C1 E1 ?? 33 C1 44 69 C2 [4] 8B C8 C1 E9 ?? 33 C1 8B C8 C1 E1 ?? 41 81 C0 [4] 33 C1 4C 0F AF CF 4D 03 CA 45 8B D1 4C 0F AF D7 41 8D 0C 11 49 C1 E9 ?? 02 C8} // // xor with mul operation
 $op2 = {4D 0F AF CC 44 69 C2 [4] 4C 03 C9 45 8B D1 4D 0F AF D4 41 8D 0C 11 41 81 C0 [4] 02 C8 49 C1 E9 ?? 41 88 4B ?? 4D 03 D1 8B C8 45 8B CA C1 E1 ?? 33 C1} // xor with mul operation
 $op3 = {33 C1 4C 0F AF C7 8B C8 C1 E1 ?? 4D 03 C2 33 C1} // shift operation
 condition: 
 2 of them
 }

 rule MAL_3CXDesktopApp_MacOS_Backdoor_Mar23 {
 meta:
 author = "X__Junior"
 reference = "https://www.volexity.com/blog/2023/03/30/3cx-supply-chain-compromise-leads-to-iconic-incident/"
 description = "Detects 3CXDesktopApp MacOS Backdoor component"
 date = "2023-03-30"
 hash = "a64fa9f1c76457ecc58402142a8728ce34ccba378c17318b3340083eeb7acc67"
 score = 80
 strings:
 $sa1 = "%s/.main_storage" ascii fullword
 $sa2 = "%s/UpdateAgent" ascii fullword

 $op1 = { 31 C0 41 80 34 06 ?? 48 FF C0 48 83 F8 ?? 75 ?? BE ?? ?? ?? ?? BA ?? ?? ?? ?? 4C 89 F7 48 89 D9 E8 ?? ?? ?? ?? 48 89 DF E8 ?? ?? ?? ?? 48 89 DF E8 ?? ?? ?? ?? 4C 89 F7 5B 41 5E 41 5F E9 ?? ?? ?? ?? 5B 41 5E 41 5F C3} /* string decryption */
 $op2 = { 0F 11 84 24 ?? ?? ?? ?? 0F 28 05 ?? ?? ?? ?? 0F 29 84 24 ?? ?? ?? ?? 0F 28 05 ?? ?? ?? ?? 0F 29 84 24 ?? ?? ?? ?? 31 C0 80 B4 04 ?? ?? ?? ?? ?? 48 FF C0} /* string decryption */
 condition:
 ( uint16(0) == 0xfeca and filesize &amp;lt; 6MB
 and
 (
 ( 1 of ($sa*) and 1 of ($op* ) )
 or all of ($sa*)
 )
 )
 or ( all of ($op*) )
 }

 - name: VersionRegex
 description: Known comromised 3CXDesktopApp.exe Windows versions to search AMCache.
 default: ^(18\.12\.407\.0|18\.12\.416)$

sources:
 - query: |
 SELECT * FROM Artifact.Generic.Detection.Yara.Glob(
 PathGlob=TargetGlob,
 YaraRule=TargetYara,
 UploadHits=UploadHits )

 - name: VAD - 3CX process
 precondition: |
 SELECT OS From info() where OS = 'windows'
 query: |
 SELECT * FROM Artifact.Windows.System.VAD(
 ProcessRegex='3cxdesktopapp.exe',
 SuspiciousContent=TargetYara )

 - name: AMCache
 precondition: |
 SELECT OS From info() where OS = 'windows'
 query: |
 LET X = scope()
 SELECT FileId,
 Key.OSPath.Path as Key,
 Key.OSPath.DelegatePath AS Hive,
 Key.Mtime as LastModified,
 X.LowerCaseLongPath as Binary,
 X.Name AS Name,
 X.Size AS Size,
 X.ProductName AS ProductName,
 X.Publisher AS Publisher,
 X.Version AS Version,
 X.BinFileVersion AS BinFileVersion
 FROM foreach(
 row={
 SELECT FullPath FROM glob(globs=expand(path="%SYSTEMROOT%/appcompat/Programs/Amcache.hve"))
 WHERE log(message="Processing "+FullPath)
 }, query={
 SELECT * FROM read_reg_key(
 globs="/Root/InventoryApplicationFile/*",
 root=pathspec(DelegatePath=FullPath),
 accessor='raw_reg' )
 })
 WHERE Name = '3cxdesktopapp.exe'
 AND ( Version =~ VersionRegex
 OR BinVersion =~ VersionRegex )
 
column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.SysAid</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sysaid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sysaid/</guid><description>&lt;p&gt;Detects artifacts associated with post exploitation activity of
LaceTempest related to the SysAid 0day.&lt;/p&gt;
&lt;p&gt;There are several sub artifact scopes, with configurable regex parameters to
target.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yara.Process: Targets observed malware and cobalt strike via process yara&lt;/li&gt;
&lt;li&gt;Disk.Ntfs: targets known disk IOCs via Windows.ntfs.mft&lt;/li&gt;
&lt;li&gt;Forensic.Usn: targets known disk IOCs via USN journal&lt;/li&gt;
&lt;li&gt;Evtx.Defender: Searches Defender event logs for evidence of associated alerts&lt;/li&gt;
&lt;li&gt;Evtx.NetworkIOC: targets known strings of network IOCs in Firewall, Sysmon logs.&lt;/li&gt;
&lt;li&gt;Evtx.PowershellIOC: targets known strings of powershell IOCs in Powershell logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.SysAid
author: Matt Green - @mgreen27
description: |
 Detects artifacts associated with post exploitation activity of 
 LaceTempest related to the SysAid 0day.
 
 There are several sub artifact scopes, with configurable regex parameters to 
 target.
 
 - Yara.Process: Targets observed malware and cobalt strike via process yara
 - Disk.Ntfs: targets known disk IOCs via Windows.ntfs.mft
 - Forensic.Usn: targets known disk IOCs via USN journal
 - Evtx.Defender: Searches Defender event logs for evidence of associated alerts
 - Evtx.NetworkIOC: targets known strings of network IOCs in Firewall, Sysmon logs.
 - Evtx.PowershellIOC: targets known strings of powershell IOCs in Powershell logs.
 
type: CLIENT
resources:
 timeout: 1800
 
parameters:
 - name: FileNameRegex
 description: FileName disk IOC regex
 type: regex
 default: ^(usersfiles\.war|user\.exe|leave)$
 - name: PathRegex
 description: Path disk IOC regex
 type: regex
 default: \\Program Files\\SysAidServer\\tomcat\\webapps\\
 - name: AllDrives
 type: bool
 description: target all drives.
 - name: DefenderDetection
 description: Regex of Defender strings to hunt in Defender evtx
 type: regex
 default: Win32/Clop|Win32/TurtleLoader
 - name: NetworkIoc
 description: Regex of network IOCs to hunt evtx
 default: 81\.19\.138\.52|45\.182\.189\.100|179\.60\.150\.34|45\.155\.37\.105
 - name: PowershellIoc
 description: Regex of Powershell string IOCs to hunt evtx
 default: STOP-PROCs FOUND\! Exiting|userentry\|getLogo\\\.jsp\|Go|179\.60\.150\.34
 - name: UploadYaraHits
 type: bool
 - name: YaraRule
 type: yara
 default: |
 rule Windows_Trojan_HazelCobra_6a9fe48a {
 meta:
 author = "Elastic Security"
 id = "6a9fe48a-6fd9-4bce-ac43-254c02d6b3a4"
 fingerprint = "4dc883be5fb6aae0dac0ec5d64baf24f0f3aaded6d759ec7dccb1a2ae641ae7b"
 creation_date = "2023-11-01"
 last_modified = "2023-11-01"
 threat_name = "Windows.Trojan.HazelCobra"
 reference_sample = "b5acf14cdac40be590318dee95425d0746e85b1b7b1cbd14da66f21f2522bf4d"
 severity = 100
 arch_context = "x86"
 scan_context = "file, memory"
 license = "Elastic License v2"
 os = "windows"
 strings:
 $a1 = { 83 E9 37 48 63 C2 F6 C2 01 75 0C C0 E1 04 48 D1 F8 88 4C 04 40 EB 07 }
 $s1 = "Data file loaded. Running..." fullword
 $s2 = "No key in args" fullword
 $s3 = "Can't read data file" fullword
 condition:
 $a1 or all of ($s*)
 }
 rule Windows_Trojan_FlawedGrace_8c5eb04b {
 meta:
 author = "Elastic Security"
 id = "8c5eb04b-301b-4d05-a010-3329e5b764c6"
 fingerprint = "46ce025974792cdefe9d4f4493cee477c0eaf641564cd44becd687c27d9e7c30"
 creation_date = "2023-11-01"
 last_modified = "2023-11-02"
 threat_name = "Windows.Trojan.FlawedGrace"
 reference_sample = "966112f3143d751a95c000a990709572ac8b49b23c0e57b2691955d6fda1016e"
 severity = 100
 arch_context = "x86"
 scan_context = "file, memory"
 license = "Elastic License v2"
 os = "windows"
 strings:
 $a1 = "Grace finalized, no more library calls allowed." ascii fullword
 $a2 = ".?AVReadThread@TunnelIO@NS@@" ascii fullword
 $a3 = ".?AVTunnelClientDirectIO@NS@@" ascii fullword
 $a4 = ".?AVWireClientConnectionThread@NS@@" ascii fullword
 $a5 = ".?AVWireParam@NS@@" ascii fullword
 condition:
 3 of them
 }
 rule win_cobalt_strike_auto {
 meta:
 author = "Felix Bilstein - yara-signator at cocacoding dot com"
 date = "2023-07-11"
 description = "Detects win.cobalt_strike."
 malpedia_reference = "https://malpedia.caad.fkie.fraunhofer.de/details/win.cobalt_strike"
 malpedia_license = "CC BY-SA 4.0"
 malpedia_sharing = "TLP:WHITE"
 strings:
 $sequence_0 = { e9???????? eb0a b801000000 e9???????? }
 $sequence_1 = { 3bc7 750d ff15???????? 3d33270000 }
 $sequence_2 = { ff15???????? 03c6 59 8bf0 }
 $sequence_3 = { ff05???????? 891e 8937 894f08 894604 c7470408000000 5b }
 $sequence_4 = { ff15???????? 03f8 03f0 83f8ff 740b 3b750c 7ce0 }
 $sequence_5 = { eb0b 8b45d4 83c010 8945d4 eb84 e9???????? 837d0c18 }
 $sequence_6 = { ff13 83c40c 3bc7 7545 }
 $sequence_7 = { eb0c 890d???????? e8???????? 59 5f 5e 5d }
 $sequence_8 = { 85c0 741d ff15???????? 85c0 7513 }
 $sequence_9 = { e8???????? e9???????? 833d????????01 7505 e8???????? }
 $sequence_10 = { 8bd0 e8???????? 85c0 7e0e }
 $sequence_11 = { 85c0 7405 e8???????? 8b0d???????? 85c9 }
 $sequence_12 = { e8???????? 488d4c2420 41b800200000 488bd3 e8???????? 4533c0 488bd3 }
 $sequence_13 = { c1e810 25ff000000 b901000000 486bc901 488b542448 88040a 8b0424 }
 $sequence_14 = { 83f835 741d ff15???????? 413bc6 7312 b9e8030000 ff15???????? }
 $sequence_15 = { 7514 488b4f20 ff15???????? 488b4f20 ff15???????? 488b7f30 4885ff }

 condition:
 7 of them
 }
 
reference:
 - https://profero.io/posts/sysaidonpremvulnerability/
 - https://www.sysaid.com/blog/service-desk/on-premise-software-security-vulnerability-notification

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

sources:
 - name: Yara.Process
 query: |
 SELECT * FROM Artifact.Windows.Detection.Yara.Process(
 YaraRule=YaraRule,
 UploadHits=UploadYaraHits )
 - name: Disk.Ntfs
 query: |
 SELECT * FROM Artifact.Windows.NTFS.MFT( AllDrives=AllDrives,
 FileRegex=FileNameRegex,
 PathRegex=PathRegex )
 - name: Forensic.Usn
 query: |
 SELECT * FROM Artifact.Windows.Forensics.Usn( AllDrives=AllDrives,
 FileNameRegex=FileNameRegex,
 PathRegex=PathRegex )
 - name: Evtx.Defender
 query: |
 SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob='%SystemRoot%\\System32\\Winevt\\Logs\\*Defender*.evtx',
 IocRegex= DefenderDetection )
 
 - name: Evtx.NetworkIOC
 query: |
 SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob='%SystemRoot%\\System32\\Winevt\\Logs\\*{Firewall,Sysmon}*.evtx',
 IocRegex= NetworkIoc )

 - name: Evtx.Powershell
 query: |
 SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob='%SystemRoot%\\System32\\Winevt\\Logs\\*Powershell*.evtx',
 IocRegex= PowershellIoc )
 
 
column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.TeamViewerLanguage</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/teamviewerlanguage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/teamviewerlanguage/</guid><description>&lt;p&gt;This artifact enables collection of TeamViewer log entries for keyboard layout
changes.&lt;/p&gt;
&lt;p&gt;The artifact firstly searches for TeamViewer log filenames, then applies yara
to extract log lines. The artifact by default hunts for Chinese, Vietnamese
and Russian language changes as priority, then uses a catch all for generic
changes. You can add additional targeted yara as desired to sort output.&lt;/p&gt;
&lt;p&gt;In each log entry there are two language codes, the first being keyboard
layout of the connecting system and the second one the default input profile
of the target host. The same language codes could indicate legitimate support.&lt;/p&gt;
&lt;p&gt;Lookup Language codes at the Microsoft link for references. Examples below:&lt;/p&gt;
&lt;p&gt;0409 - US English&lt;br&gt;
0419 - Russian&lt;br&gt;
0804 - Chinese Simplified&lt;br&gt;
0404 - Chinese Traditional&lt;br&gt;
042a - Vietnamese&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.TeamViewerLanguage
author: Matt Green - @mgreen27
description: |
 This artifact enables collection of TeamViewer log entries for keyboard layout 
 changes. 
 
 The artifact firstly searches for TeamViewer log filenames, then applies yara 
 to extract log lines. The artifact by default hunts for Chinese, Vietnamese 
 and Russian language changes as priority, then uses a catch all for generic 
 changes. You can add additional targeted yara as desired to sort output. 
 
 In each log entry there are two language codes, the first being keyboard 
 layout of the connecting system and the second one the default input profile 
 of the target host. The same language codes could indicate legitimate support.
 
 Lookup Language codes at the Microsoft link for references. Examples below: 
 
 0409 - US English 
 0419 - Russian 
 0804 - Chinese Simplified 
 0404 - Chinese Traditional 
 042a - Vietnamese 
 
reference:
 - https://twitter.com/cyb3rops/status/1600157565148483584
 - https://github.com/Neo23x0/signature-base/blob/master/yara/log_teamviewer_keyboard_layouts.yar
 - https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-input-locales-for-windows-language-packs?view=windows-11
 
type: CLIENT

parameters:
 - name: TargetFileRegex
 default: ^TeamViewer.._Logfile.*\.log$
 description: target teamviewer log filenames.
 - name: DriveLetter
 default: "C:"
 - name: AllDrives
 type: bool
 - name: LayoutRegex
 default: .
 description: Regex of Layout to filter for
 - name: YaraToScan
 description: Yata to scan. High priority rules first then catch all for generic changes at end.
 default: |
 rule LOG_TeamViewer_Connect_Chinese_Keyboard_Layout {
 meta:
 description = "Detects a suspicious TeamViewer log entry stating that the remote systems had a Chinese keyboard layout"
 author = "Florian Roth"
 date = "2019-10-12"
 modified = "2020-12-16"
 score = 60
 limit = "Logscan"
 reference = "https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-input-locales-for-windows-language-packs"
 strings:
 /* Source has Chinese simplified keyboard layout */
 $x1 = "Changing keyboard layout to: 0804" ascii
 $x2 = "Changing keyboard layout to: 042a"
 /* Avoiding Chinese to Chinese support cases */
 $fp1 = "Changing keyboard layout to: 08040804" ascii
 $fp2 = "Changing keyboard layout to: 042a042a" ascii
 condition:
 ( #x1 + #x2 ) &amp;gt; ( #fp1 + #fp2 )
 }
 rule LOG_TeamViewer_Connect_Russian_Keyboard_Layout {
 meta:
 description = "Detects a suspicious TeamViewer log entry stating that the remote systems had a Russian keyboard layout"
 author = "Florian Roth"
 date = "2019-10-12"
 modified = "2022-12-07"
 score = 60
 limit = "Logscan"
 reference = "https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-input-locales-for-windows-language-packs"
 strings:
 /* Source has Russian keyboard layout */
 $x1 = "Changing keyboard layout to: 0419" ascii
 /* Avoiding Russian to Russian support cases */
 $fp1 = "Changing keyboard layout to: 04190419" ascii
 condition:
 #x1 &amp;gt; #fp1
 }
 rule LOG_TeamViewer_Connect_any_Keyboard_Layout {
 meta:
 description = "Detects a generic TeamViewer log entry stating change in keyboard layout"
 strings:
 $x1 = "Changing keyboard layout to:" ascii
 condition:
 any of them
 }


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

 query: |
 LET hits = SELECT OSPath,Rule,
 Meta.description as RuleDescription,
 filter(list=split(string=HitContext,sep='\r\n'),regex='Changing keyboard layout to')[0] as HitContent
 FROM Artifact.Windows.Detection.Yara.NTFS(
 FileNameRegex=TargetFileRegex,PathRegex='.',
 AllDrives=AllDrives,
 DriveLetter=DriveLetter,
 NumberOfHits=9999999, 
 ContextBytes=50,
 YaraRule=YaraToScan )
 

 LET details = SELECT*,
 parse_string_with_regex(string=HitContent,
 regex=[
 '^(?P&amp;lt;EventTime&amp;gt;\\d{4}.\\d{2}.\\d{2}.\\d{2}:\\d{2}:\\d{2}[^\\s]+)',
 'Changing keyboard layout to: (?P&amp;lt;KeyboardLayout&amp;gt;[^\\s]+)']) as Details
 FROM hits

 SELECT
 timestamp(string=Details.EventTime) as EventTime,
 Rule,
 Details.KeyboardLayout as KeyboardLayout,
 HitContent, 
 RuleDescription,
 OSPath
 FROM details
 WHERE KeyboardLayout =~ LayoutRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.Termsrv</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/termsrv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/termsrv/</guid><description>&lt;p&gt;This artifact detects patched TerminalService / Remote Desktop (RDP) dynamic link library or ServiceDll -
termsrv.dll.&lt;/p&gt;
&lt;p&gt;ATT&amp;amp;CK T1505.005. Non Terminal Services Windows systems (e.g Windows 10 or 11) do not allow
concurrent users to RDP into the machine at the same time. Typically a notice
is displayed to the logged-on user requesting access and notifying of the
impending log off. As a defence evasion technique threat actors have been
known to patch termsrv.dll to evade detections.&lt;/p&gt;
&lt;p&gt;The artifact collects 3 potential detection points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In memory - targeting termsrv.dll mapped file for the patch bytes&lt;/li&gt;
&lt;li&gt;On disk - targeting and file named termsrv.dll&lt;/li&gt;
&lt;li&gt;Services - targeting any unutual ServiceDll path or an untrusted authenticode ServiceDll&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.Termsrv
author: Matt Green - @mgreen27
description: |
 This artifact detects patched TerminalService / Remote Desktop (RDP) dynamic link library or ServiceDll - 
 termsrv.dll.
 
 ATT&amp;amp;CK T1505.005. Non Terminal Services Windows systems (e.g Windows 10 or 11) do not allow 
 concurrent users to RDP into the machine at the same time. Typically a notice 
 is displayed to the logged-on user requesting access and notifying of the 
 impending log off. As a defence evasion technique threat actors have been 
 known to patch termsrv.dll to evade detections.
 
 The artifact collects 3 potential detection points:
 
 1. In memory - targeting termsrv.dll mapped file for the patch bytes
 2. On disk - targeting and file named termsrv.dll
 3. Services - targeting any unutual ServiceDll path or an untrusted authenticode ServiceDll
 
reference:
 - https://attack.mitre.org/techniques/T1505/005/
 - https://www.mysysadmintips.com/windows/clients/545-multiple-rdp-remote-desktop-sessions-in-windows-10
 
type: CLIENT
 
parameters:
 - name: FileNameRegex
 description: Only file names that match this regular expression will be scanned.
 default: termsrv\.dll$
 - name: MappingRegex
 description: Only mapped sections that match this regular expression will be scanned.
 default: termsrv\.dll$
 - name: UploadHits
 type: bool
 description: If selected will upload any yara hits
 - name: YaraRule
 type: yara
 description: Patched RDP yara
 default: |
 rule termsrv_modified
 {
 meta:
 description = "Finds hex of termsrv.dll patch"
 strings:
 $patch = { B8 00 01 00 00 89 81 38 06 00 00 90 }
 
 condition:
 $patch
 }
 - name: ExpectedServiceDll
 description: Expected service dll location regex
 default: '''^C:\\Windows\\System32\\termsrv\.dll$'''
 
precondition: SELECT OS From info() where OS = 'windows'

sources:
 - name: VAD
 query: |
 SELECT ProcessCreateTime,Pid,Name,MappingName,AddressRange,State,Type,
 ProtectionMsg,Protection,SectionSize,YaraHit,HitContext,ProcessChain
 FROM Artifact.Windows.System.VAD(
 ProcessRegex='svchost\.exe',
 MappingNameRegex=MappingRegex,
 SuspiciousContent=YaraRule,
 UploadSection=UploadHits )

 - name: Yara.NTFS
 query: |
 SELECT OSPath,Size,ModTime,Rule,Meta,YaraString,HitOffset,HitContext
 FROM Artifact.Windows.Detection.Yara.NTFS(
 FileNameRegex=FileNameRegex,
 PathRegex=".",
 YaraRule=YaraRule,
 UploadHits=UploadHits,
 NumberOfHits=1 )
 
 - name: Services
 query: |
 SELECT State,Name,DisplayName,Status,Pid,ExitCode,StartMode,PathName,
 ServiceType,UserAccount,Created,FailureCommand,FailureActions,
 AbsoluteExePath, ServiceDll,
 HashServiceDll, CertinfoServiceDll,
 parse_pe(file=ServiceDll) as PEInfo
 FROM Artifact.Windows.System.Services(
 DisplayNameRegex='Remote Desktop Services',
 Calculate_hashes='Y',
 CertificateInfo='Y')
 WHERE Name =~ 'TermService'
 AND ( NOT ServiceDll =~ ExpectedServiceDll OR CertinfoServiceDll.Trusted = 'untrusted' )
 
column_types:
 - name: HitContext
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.UnattendXML</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/unattendxml/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/unattendxml/</guid><description>&lt;p&gt;This artifact will find unscrubbed passwords in unattend.xml answer files. This
file is used for non interactive Windows installation.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.UnattendXML
author: Matt Green - @mgreen27
description: |
 This artifact will find unscrubbed passwords in unattend.xml answer files. This 
 file is used for non interactive Windows installation.

reference:
 - https://twitter.com/malmoeb/status/1561443455095771136
 - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/update-windows-settings-and-scripts-create-your-own-answer-file-sxs?view=windows-11

parameters:
 - name: TargetFileName
 default: ^(unattend\.xml|autounattend\.xml|sysprep\.xml)$
 type: regex
 description: File names to target for unattend xml files.
 - name: ExcludeString
 default: ^\*SENSITIVE\*DATA\*DELETED\*$
 description: regex to exclude
 - name: UploadHits
 description: select to upload file
 type: bool

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

 query: |
 LET targets = SELECT OSPath,FileName,LastModified0x10,Created0x10 FROM Artifact.Windows.NTFS.MFT(FileRegex=TargetFileName)

 LET hits = SELECT * FROM foreach(row=targets,
 query={
 SELECT 
 Type,Value,OSPath,
 LastModified0x10 as ModificationTime,
 Created0x10 as CreationTime,
 parse_xml(file=OSPath).unattend as Xml
 FROM parse_records_with_regex(file=OSPath,regex='\\&amp;lt;(?P&amp;lt;Type&amp;gt;.*Password.*)\\&amp;gt;(?P&amp;lt;Value&amp;gt;[^&amp;lt;]+)\\&amp;lt;/.*Password.*\\&amp;gt;')
 WHERE NOT Value =~ ExcludeString 
 })

 LET upload_hits = SELECT *, upload(file=OSPath) as Upload FROM hits
 
 SELECT * FROM if(condition=UploadHits,
 then= upload_hits,
 else= hits )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.USBYara</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/usbyara/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/usbyara/</guid><description>&lt;p&gt;Run yara over usb when USB is plugged into machine. Return context
and hit details.&lt;/p&gt;
&lt;p&gt;This artifact requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows.Monitor.USBPlugIn (imported from Exchange)&lt;/li&gt;
&lt;li&gt;Generic.Detection.Yara.Glob&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yara rule deployed and target path can be modified.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.USBYara
author: Matt Green - @mgreen27
description: |
 Run yara over usb when USB is plugged into machine. Return context
 and hit details.

 This artifact requires:

 * Windows.Monitor.USBPlugIn (imported from Exchange)
 * Generic.Detection.Yara.Glob

 Yara rule deployed and target path can be modified.

type: CLIENT_EVENT

parameters:
 - name: TargetGlob
 default: '/**.lnk'
 - name: PayloadYara
 default: |
 rule recyclebin_lnk{
 meta:
 description = "AvastSvcpCP lnkfile"
 author = "@mgreen27"
 date = "2021-11-18"

 strings:
 $s1 = "AvastSvcpCP" wide nocase
 $s2 = "cefhelper.exe" wide nocase
 $s3 = "RECYCLER.BIN" wide nocase
 $s4 = "wsc.zip" wide nocase
 $s6 = "/q /c" wide nocase
 $s8 = "S-1-5-21-1063499884-3365855816-3691837489-1000" wide nocase
 $s9 = "Xayemarlwin-pc" wide nocase

 condition:
 int16(0) == 0x004c and any of them
 }

sources:
 - query: |
 SELECT * FROM foreach(
 row={
 SELECT DriveName,TimeCreated
 FROM Artifact.Windows.Monitor.USBPlugIn()
 }, query={
 SELECT
 TimeCreated as EventTime,
 { SELECT Fqdn from info() } as Hostname,
 FullPath,Size,
 dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime) as SITimestamps,
 Rule,Meta,
 HitContext,HitOffset,
 {
 SELECT Name, FileSystem,Description,FreeSpace,Size,VolumeSerialNumber,VolumeName
 FROM wmi(query='SELECT * FROM Win32_logicaldisk WHERE DeviceID = "' + DriveName + '"',namespace='ROOT/CIMV2')
 } as DiskInfo
 FROM Artifact.Generic.Detection.Yara.Glob(PathGlob=DriveName + TargetGlob,YaraRule=PayloadYara)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.WonkaVision</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.wonkavision/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.wonkavision/</guid><description>&lt;p&gt;This artifact analyzes Kerberos tickets and attempts to determine if they are forged, using WonkaVision by @4ndr3w6s and @exploitph.&lt;/p&gt;
&lt;p&gt;After analysis, notable events are documented in the native Windows Application log, and are easily reviewable using the &lt;code&gt;Exhange.Windows.EventLogs.WonkaVision&lt;/code&gt; artifact.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/0xe7/WonkaVision" target="_blank" &gt;https://github.com/0xe7/WonkaVision&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Detection.WonkaVision
description: |
 
 This artifact analyzes Kerberos tickets and attempts to determine if they are forged, using WonkaVision by @4ndr3w6s and @exploitph.
 
 After analysis, notable events are documented in the native Windows Application log, and are easily reviewable using the `Exhange.Windows.EventLogs.WonkaVision` artifact.
 
 https://github.com/0xe7/WonkaVision
 
author: Wes Lambert -- @therealwlambert
reference:
 - https://github.com/0xe7/WonkaVision
tools:
 - name: WonkaVision
 url: https://github.com/weslambert/WonkaVision/releases/download/testing/WonkaVision.exe

sources:
 - name: RunWonkaVison
 query: |
 LET WV &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="WonkaVision", IsExecutable=FALSE)
 LET KeyDir &amp;lt;= tempdir(remove_last=true)
 LET DumpDir &amp;lt;= tempdir(remove_last=true)
 LET CreateKeys = SELECT * FROM execve(argv=[WV.FullPath[0], '/createkeys', '/outdir:' + KeyDir])
 LET DumpIt = SELECT * FROM execve(argv=[WV.FullPath[0], '/dump', '/publickey:' + KeyDir + '/public.key', '/dumpdir:' + DumpDir])
 LET AnalyzeIt = SELECT * FROM execve(argv=[WV.FullPath[0], '/analyze', '/privatekey:' + KeyDir + '/private.key', '/dumpdir:' + DumpDir])
 SELECT * FROM chain(
 a=CreateKeys,
 b=DumpIt,
 c=AnalyzeIt
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Detection.WS_FTP</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ws_ftp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ws_ftp/</guid><description>&lt;p&gt;This is an artifact to detect exploitation of a Progress Software&amp;rsquo;s WS_FTP
critical vulnerability observed in the wild.&lt;/p&gt;
&lt;p&gt;CVE-2023–40044 is a severe .NET deserialization vulnerability in WS_FTP
Server’s Ad Hoc Transfer module, allowing a pre-authenticated attacker to
execute remote commands on the server’s operating system.&lt;/p&gt;
&lt;p&gt;CVE-2023–42657 is a directory traversal vulnerability, enabling attackers to
perform file operations outside their authorized WS_FTP folder path and
operate on the underlying OS.&lt;/p&gt;
&lt;p&gt;Both vulnerabilities are critical, with CVSS scores of 8.8 and 9.9
respectively, and affect versions prior to 8.7.4 and 8.8.2​.&lt;/p&gt;
&lt;p&gt;The artifact enables detection via:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yara: IIS logs&lt;/li&gt;
&lt;li&gt;Evtx: Application Event Logs IIS exception&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both methods target observed IPs and the string /AHT/AhtApiService.asmx which
is part of the vulnerable module.
Note: no direct evidence of exploitation observed in application logs, only
exceptions that otherwise seem rare around the time of exploitation.&lt;/p&gt;
&lt;p&gt;Last updated: 2023-10-01T13:15Z&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;

name: Windows.Detection.WS_FTP
author: Matt Green - @mgreen27
description: | 
 This is an artifact to detect exploitation of a Progress Software's WS_FTP 
 critical vulnerability observed in the wild.
 
 CVE-2023–40044 is a severe .NET deserialization vulnerability in WS_FTP 
 Server’s Ad Hoc Transfer module, allowing a pre-authenticated attacker to 
 execute remote commands on the server’s operating system. 
 
 CVE-2023–42657 is a directory traversal vulnerability, enabling attackers to 
 perform file operations outside their authorized WS_FTP folder path and 
 operate on the underlying OS. 
 
 Both vulnerabilities are critical, with CVSS scores of 8.8 and 9.9 
 respectively, and affect versions prior to 8.7.4 and 8.8.2​.
 
 The artifact enables detection via:
 
 - Yara: IIS logs
 - Evtx: Application Event Logs IIS exception 
 
 Both methods target observed IPs and the string /AHT/AhtApiService.asmx which 
 is part of the vulnerable module.
 Note: no direct evidence of exploitation observed in application logs, only 
 exceptions that otherwise seem rare around the time of exploitation.
 
 
 Last updated: 2023-10-01T13:15Z
 
reference:
 - https://www.rapid7.com/blog/post/2023/09/29/etr-critical-vulnerabilities-in-ws_ftp-server/

type: CLIENT
resources:
 timeout: 1800

parameters:
 - name: EvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
 - name: IocRegex
 type: regex
 description: "IOC Regex in evtxHunt"
 default: '/AHT/|86\.48\.3\.172'
 - name: DateAfter
 type: timestamp
 default: 1685232000
 description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: DateBefore
 type: timestamp
 description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
 - name: AllDrives
 type: bool
 description: "By default we target yara at all drives"
 default: Y
 - name: DriveLetter
 description: "Target yara drive. Default is a C: if not AllDrives"
 default: "C:"
 - name: LogYara
 default: |
 rule LOG_ws_ftp_exploit {
 meta:
 description = "Detects potential exploitation of Progress Software WS_FTP Server in IIS logs"
 author = "Matt Green - @mgreen27"
 reference = "https://www.rapid7.com/blog/post/2023/09/29/etr-critical-vulnerabilities-in-ws_ftp-server/"
 date = "2023-10-01"
 score = 80
 
 strings:
 $post = /\n.{1,50} POST \/AHT\/.{1,250}\n/
 $ip = " 86.48.3.172 " ascii
 
 condition:
 any of them
 }
 - name: NumberOfHits
 description: This artifact will stop by default at one hit. This setting allows additional hits
 default: 1
 type: int64
 - name: ContextBytes
 description: Include this amount of bytes around hit as context.
 default: 0
 type: int
 - name: UploadYaraHits
 type: bool

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 
 name: Yara
 query: |
 -- check which Yara to use
 LET yara_rules &amp;lt;= LogYara

 -- first find all matching files mft
 LET files = SELECT OSPath, IsDir
 FROM Artifact.Windows.NTFS.MFT(MFTDrive=DriveLetter, AllDrives=AllDrives,
 FileRegex='^u_.+\.log$',
 PathRegex='inetpub' )
 WHERE NOT IsDir
 AND NOT OSPath =~ '''.:\\&amp;lt;Err&amp;gt;\\'''
 AND (FileName=~ '^u_.+\.log$' AND OSPath =~ 'inetpub' )
 AND if(condition=DateAfter,
 then= LastRecordChange0x10 &amp;gt; DateAfter,
 else= True)
 AND if(condition=DateBefore,
 then= LastRecordChange0x10 &amp;lt; DateBefore,
 else= True)

 -- scan files and only report a single hit.
 LET hits = SELECT * FROM foreach(row=files,
 query={
 SELECT
 FileName, OSPath,
 File.Size AS Size,
 File.ModTime AS ModTime,
 Rule, Tags, Meta,
 String.Name as YaraString,
 String.Offset as HitOffset,
 upload( accessor='scope', 
 file='String.Data', 
 name=format(format="%v-%v-%v", 
 args=[
 OSPath,
 if(condition= String.Offset - ContextBytes &amp;lt; 0,
 then= 0,
 else= String.Offset - ContextBytes),
 if(condition= String.Offset + ContextBytes &amp;gt; File.Size,
 then= File.Size,
 else= String.Offset + ContextBytes) ]
 )) as HitContext
 FROM yara(rules=yara_rules, files=OSPath, context=ContextBytes,number=NumberOfHits)
 })

 -- upload files that have hit
 LET upload_hits=SELECT *,
 upload(file=OSPath) AS Upload
 FROM hits
 GROUP BY OSPath

 -- return rows
 SELECT * FROM if(condition=UploadYaraHits,
 then={ SELECT * FROM upload_hits},
 else={ SELECT * FROM hits})


 - name: Evtx
 query: |
 SELECT EventTime,Computer,Channel,Provider,EventID,EventRecordID,
 EventData,
 OSPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=EvtxGlob,
 IocRegex=IocRegex,
 IdRegex='^1309$',
 DateAfter=DateAfter,
 DateBefore=DateBefore )
 
column_types:
 - name: HitContext
 type: preview_upload
 - name: ModTime
 type: timestamp
 - name: EventTime
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ESET.Logs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/esetlogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/esetlogs/</guid><description>&lt;p&gt;Parse logs from ESET antivirus products. This log contains information about detections made by the ESET modules such as Real-time filesystem proteciton, Firewall, HIPS, Device Control, HTTP filter, AMSI Scanner etc.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ESET.Logs
author: Ján Trenčanský - j91321@infosec.exchange
description: |
 Parse logs from ESET antivirus products. This log contains information about detections made by the ESET modules such as Real-time filesystem proteciton, Firewall, HIPS, Device Control, HTTP filter, AMSI Scanner etc.
 
type: CLIENT
 
tools:
 - name: ESETLogCollector
 url: https://download.eset.com/com/eset/tools/diagnosis/log_collector/latest/esetlogcollector.exe
 expected_hash: c5c9b4ec7feca3f3ac43c71454e7e51f13f19ce52a0583d34b32f7df4bbea5db
 serve_locally: true
 
precondition: SELECT OS From info() where OS = 'windows'
 
parameters:
 - name: LogTargets
 default: "Threat,Hips,Fw,Web,Dev,BlkF"
 description: Selection of log targets to collect
 
required_permissions:
- EXECVE
 
sources:
 - name: Antivirus
 query: |
 LET tool &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(ToolName="ESETLogCollector")
 LET tempfolder &amp;lt;= tempdir(remove_last=true)
 LET exe &amp;lt;= SELECT * FROM execve(argv= [ tool[0].OSPath,
 "/accepteula", "/OType:xml", "/Targets:"+LogTargets, tempfolder+'\\logstmp.zip' ], length=10000000)
 LET zip &amp;lt;= SELECT * FROM unzip(filename=tempfolder+'\\logstmp.zip',output_directory=tempfolder+'\\logs')
 
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Common\\virlog.dat.xml')
 SELECT * FROM foreach(
 row=xml.entries,
 query={SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'virlog.dat' AS Log, _value.Threat AS Threat, _value.AttrLevel AS Level, _value.Action AS Action, _value.Name AS Object, _value.Col7 AS SHA1, _value.Info AS Information, _value.Col8 AS Firstseen, _value.Scanner AS Scanner, _value.Object AS ObjectType, _value.User AS User, _value.AttrDeleted AS DeletedInLog FROM foreach(row=_value)})
 
 - name: HIPS
 query: |
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Common\\hipslog.dat.xml')
 SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'hipslog.dat' AS Log, _value.Rule AS RuleName, _value.AttrLevel AS Level, _value.Action AS Action, _value.Application AS Application, _value.Application_Hash AS ApplicationSHA1, _value.Target AS Target, _value.Target_Hash AS TargetSHA1, _value.AttrDeleted AS DeletedInLog FROM foreach(
 row=xml.entries,
 query={SELECT * FROM foreach(row=_value)}) 
 
 - name: Firewall
 query: |
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Net\\epfwlog.dat.xml')
 SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'epfwlog.dat' AS Log, _value.Event AS Event, _value.Rule_worm_name AS RuleName, _value.AttrLevel AS Level, _value.Action AS Action, _value.Source AS Source, _value.Target AS Target, _value.Protocol AS Protocol, _value.Application AS Application, _value.Hash AS SHA1, _value.User AS User, _value.AttrDeleted AS DeletedInLog FROM foreach(
 row=xml.entries,
 query={SELECT * FROM foreach(row=_value)})
 
 - name: FilteredWebsites
 query: |
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Net\\urllog.dat.xml')
 SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'urllog.dat' AS Log, _value.URL AS URL, _value.Status AS Action, _value.Detection AS Threat, _value.AttrLevel AS Level, _value.Application AS Application, _value.Hash AS SHA1, _value.User AS User, _value.IP_address AS IPAddress, _value.AttrDeleted AS DeletedInLog FROM foreach(
 row=xml.entries,
 query={SELECT * FROM foreach(row=_value)})
 
 - name: BlockedFiles
 query: |
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Common\\blocked.dat.xml')
 SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'blocked.dat' AS Log, _value.File AS File, _value.Source AS Blocker, _value.Reason AS Reason, _value.AttrLevel AS Level, _value.Application AS Application, _value.Hash AS SHA1, _value.User AS User, _value.First_seen_here AS FirstSeen, _value.AttrDeleted AS DeletedInLog FROM foreach(
 row=xml.entries,
 query={SELECT * FROM foreach(row=_value)})
 
 - name: DeviceControl
 query: |
 LET xml &amp;lt;= SELECT get(item=parse_xml(file=OSPath), member='Events.Event') AS entries FROM glob(globs=tempfolder+'\\logs\\ESET\\Logs\\Common\\devctrllog.dat.xml')
 SELECT _value.AttrIdx AS ID, _value.AttrTime AS Timestamp, 'devctrllog.dat' AS Log, _value.Device AS Device, _value.Status AS Action, _value.AttrLevel AS Level, _value.User AS User, _value.User_SID AS SID, _value.Group AS Group, _value.Group_SID AS GroupSID, _value.Device_details AS DeviceDetails, _value.Event_details AS EventDetails, _value.AttrDeleted AS DeletedInLog FROM foreach(
 row=xml.entries,
 query={SELECT * FROM foreach(row=_value)})
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.AMSI</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/amsi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/amsi/</guid><description>&lt;p&gt;This artifact uses the ETW provider:
(Microsoft-Antimalware-Scan-Interface - {2A576B87-09A7-520E-C21A-4942F0271D67}&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ETW.AMSI
description: |
 This artifact uses the ETW provider:
 (Microsoft-Antimalware-Scan-Interface - {2A576B87-09A7-520E-C21A-4942F0271D67}

type: CLIENT_EVENT

parameters:
 - name: IocRegex
 description: "Regex of strings to filter for"
 default: .
 - name: WhitelistRegex
 description: "Regex of strings to witelist"
 - name: AppNameRegex
 description: "Application name Regex to enable filtering on source."
 default: .
 - name: ExcludeAmsiHashList
 description: "Line seperated list of AMSI hashes to exclude"
 default: |
 0xB95D39DB18570A2A6DB329A3FF0BB87B17720279A0AC6862C7D5BA66C8270BB1
 0x9281522E94E9F3D4FBF4F679335D8A891B1FAE9933DCD993A0E2AE7CD8789953

sources:
 - query: |
 -- split out Hash exclusions into array
 LET HashExclusions &amp;lt;= SELECT _value as AmsiHash
 FROM foreach(row=split(sep='\\s+',string=ExcludeAmsiHashList))
 WHERE AmsiHash
 
 -- watch ETW provider and first round data manipulation
 LET hits = SELECT
 timestamp(epoch=timestamp(string=System.TimeStamp).unix) as EventTime,
 System,
 get(member="EventData") AS EventData
 FROM watch_etw(guid="{2A576B87-09A7-520E-C21A-4942F0271D67}")
 WHERE EventData.appname =~ AppNameRegex
 AND NOT EventData.hash in HashExclusions.AmsiHash

 -- print rows
 SELECT
 EventTime,
 EventData.appname as AppName,
 EventData.contentname as ContentName,
 utf16(string=
 unhex(string=regex_replace(
 source=EventData.Content,re='^0x',replace=''))
 ) as Content,
 process_tracker_callchain(id=System.ProcessID).Data[-1] as ProcessInfo,
 process_tracker_callchain(id=System.ProcessID).Data as ProcessChain,
 EventData.hash as AmsiHash
 FROM hits
 WHERE
 Content =~ IocRegex
 AND if(condition= WhitelistRegex,
 then= NOT Content =~ WhitelistRegex,
 else= True)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.DetectProcessSpoofing</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.detectprocessspoofing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.detectprocessspoofing/</guid><description>&lt;p&gt;Detects Process parent spoofing such as SelectMyParent.exe or
Cobalt Strike select PPID.&lt;/p&gt;
&lt;p&gt;NOTE: for short lasting processes it is expected to report NULL
for CommandLine and Username fields as enrichment failed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ETW.DetectProcessSpoofing
description: |
 Detects Process parent spoofing such as SelectMyParent.exe or
 Cobalt Strike select PPID.

 NOTE: for short lasting processes it is expected to report NULL
 for CommandLine and Username fields as enrichment failed.

reference:
 - https://blog.f-secure.com/detecting-parent-pid-spoofing/
 - https://www.youtube.com/watch?v=DOe7WTuJ1Ac

type: CLIENT_EVENT

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

 query: |
 LET RecentProcesses = SELECT * FROM fifo(query={
 SELECT System.TimeStamp AS CreateTime,
 EventData.ImageName AS ImageName,
 int(int=EventData.ProcessID) AS Pid,
 EventData.MandatoryLabel AS MandatoryLabel,
 EventData.ProcessTokenElevationType AS ProcessTokenElevationType,
 EventData.ProcessTokenIsElevated AS TokenIsElevated
 FROM watch_etw(guid="{22fb2cd6-0e7b-422b-a0c7-2fad1fd0e716}", any=0x10)
 WHERE System.ID = 1
 }, max_rows=1000, max_age=60)

 -- Query it once to materialize the FIFO
 LET _ &amp;lt;= SELECT * FROM RecentProcesses

 LET GetProcessInfo(TargetPid) = SELECT * FROM switch(
 -- First try to get the pid directly
 a={
 SELECT
 Name, Pid, CreateTime,
 Exe as ImageName,
 CommandLine,
 Username,
 TokenIsElevated
 FROM pslist(pid=TargetPid)
 },
 -- Failing this look in the FIFO for a recently started process.
 b={
 SELECT
 basename(path=ImageName) as Name,
 Pid,
 CreateTime,
 ImageName,
 Null as CommandLine,
 Null as Username,
 if(condition= TokenIsElevated="0",
 then= false,
 else= true ) as TokenIsElevated
 FROM RecentProcesses
 WHERE Pid = TargetPid
 LIMIT 1
 })

 -- Resolve parent pid from the fifo - this allows us to catch fast terminating processes.
 SELECT System.TimeStamp AS EventTime,
 GetProcessInfo(TargetPid=int(int=EventData.ProcessID))[0] AS SuspiciousProcess,
 GetProcessInfo(TargetPid=System.ProcessID)[0] AS RealParent,
 GetProcessInfo(TargetPid=int(int=EventData.ParentProcessID))[0] AS ClaimedParent,
 System as _System, EventData as _EventData
 FROM watch_etw(guid="{22fb2cd6-0e7b-422b-a0c7-2fad1fd0e716}", any=0x10)
 WHERE System.ID = 1 AND str(str=System.ProcessID) != EventData.ParentProcessID

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.DNSOfflineCollector</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.dnsofflinecollector/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.dnsofflinecollector/</guid><description>&lt;p&gt;This artifact collects DNS queries for a specified duration. It can be used
with an Offline Collector (which is not the case with Windows.ETW.DNS).
It uses the artifact (Windows.ETW.DNS) that was built by Matt Green - @mgreen27&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ETW.DNSOfflineCollector
author: Jos Clephas - @DfirJos
description: |
 This artifact collects DNS queries for a specified duration. It can be used 
 with an Offline Collector (which is not the case with Windows.ETW.DNS).
 It uses the artifact (Windows.ETW.DNS) that was built by Matt Green - @mgreen27
parameters:
 - name: duration
 default: 60
 type: int
 - name: arg_ImageRegex
 description: "ImagePath regex filter for"
 default: .
 type: regex
 - name: arg_CommandLineRegex
 description: "Commandline to filter for."
 default: .
 type: regex
 - name: arg_QueryRegex
 description: "DNS query request (domain) to filter for."
 default: .
 type: regex
 - name: arg_AnswerRegex
 description: "DNS answer to filter for."
 default: .
 type: regex
 - name: arg_CommandLineExclusion
 description: "Commandline to filter out. Typically we do not want Dnscache events."
 default: svchost.exe -k NetworkService -p -s Dnscache$
 type: regex

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

 query: |
 SELECT * FROM collect(artifacts='Windows.ETW.DNS', timeout=duration, args=dict(`Windows.ETW.DNS`=dict(
 ImageRegex=arg_ImageRegex,
 CommandLineRegex=arg_CommandLineRegex,
 QueryRegex=arg_QueryRegex,
 AnswerRegex=arg_AnswerRegex,
 CommandLineExclusion=arg_CommandLineExclusion))) 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.Powershell</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/powershellmonitoring/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/powershellmonitoring/</guid><description>&lt;p&gt;This artifact enables Powershell scriptblock and commandlet load monitoring.&lt;br&gt;
It uses the ETW provider: Microsoft-Windows-PowerShell&lt;/p&gt;
&lt;p&gt;Detection logic is managed by several global ignore entries and an IOC csv.&lt;/p&gt;
&lt;h5 id="global-ignore"&gt;Global Ignore&lt;/h5&gt;
&lt;p&gt;IgnoreProcessExe - Process exe path to ignore&lt;br&gt;
IgnoreParentProcessExe - Parent exe path for child generated events to ignore&lt;br&gt;
IgnoreParentProcessName - Ignore events generated by a child process&lt;/p&gt;
&lt;h5 id="ioccsv"&gt;IocCsv&lt;/h5&gt;
&lt;p&gt;Name - detection name&lt;br&gt;
Type - type of detection: ScriptBlock,Commandlet or ScriptBlock|Commandlet&lt;br&gt;
Regex - regex to search for&lt;br&gt;
Ignore - regex to ignore&lt;br&gt;
DateModified - date detection last modified&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ETW.Powershell
author: Matt Green - @mgreen27
description: |
 This artifact enables Powershell scriptblock and commandlet load monitoring. 
 It uses the ETW provider: Microsoft-Windows-PowerShell 
 
 Detection logic is managed by several global ignore entries and an IOC csv. 

 ##### Global Ignore 
 IgnoreProcessExe - Process exe path to ignore 
 IgnoreParentProcessExe - Parent exe path for child generated events to ignore 
 IgnoreParentProcessName - Ignore events generated by a child process 
 
 ##### IocCsv 
 Name - detection name 
 Type - type of detection: ScriptBlock,Commandlet or ScriptBlock|Commandlet 
 Regex - regex to search for 
 Ignore - regex to ignore 
 DateModified - date detection last modified 
 

type: CLIENT_EVENT

parameters:
 - name: IgnoreProcessExe
 description: Regex of process exe path to ignore
 default: \\Program Files\\(Microsoft Monitoring Agent\\Agent|Microsoft System Center\\Operations Manager\\Server)\\MonitoringHost\.exe$
 - name: IgnoreParentProcessExe
 description: Regex of parent exe path for child generated events to ignore
 default: ^(C:\\Program Files\\Windows Defender Advanced Threat Protection\\SenseIR\.exe|C:\\Program Files\\Microsoft SQL Server\\MSSQL\d{1,2}\.MSSQLSERVER\\MSSQL\\Binn\\SQLAGENT\.EXE)$
 - name: IgnorePaths
 description: "List of path regex to ignore. This list will be joined and excluded."
 default: |
 \\SDIAG_.{8}-(.{4}-){3}.{12}\\
 \\Windows Defender Advanced Threat Protection\\
 \\Microsoft Azure Backup Server\\
 \\Program Files\\Microsoft Dependency Agent\\
 \\(Program Files|ProgramData)\\Amazon\\(WorkSpaces|EC2-Windows)
 \\Program Files(|\(x86\))\\Symantec\\Symantec Endpoint
 \\Program Files(|\(x86\))\\Automox\\execDir
 - name: IocCsv
 type: csv
 description: "Application name Regex to enable filtering on source."
 default: |
 Name,Type,Regex,Ignore,DateModified
 T1059.001-Mimikatz Execution via PowerShell,ScriptBlock,TOKEN_PRIVILE|SE_PRIVILEGE_ENABLED|mimikatz|lsass.dmp,,12/8/2022
 T1059.001-Cobalt Strike Powershell Loader,ScriptBlock,\$Doit|-bxor 35,,12/8/2022
 TT1562-Impair Defences,ScriptBlock,powershell -version 2|Set-PSReadlineOption|-HistorySaveStyle SaveNothing|remove-module +psreadline|[Amsi]::Bypass()|{2781761E-28E0-4109-99FE-B9D127C57AFE}|amsiInitFailed|System.Management.Automation.AmsiUtils|Remove-EtwTraceProvider|System.Management.Automation.Tracing.PSEtwLogProvider|HKLM.SYSTEM.CurrentControlSet.Control.WMI.Autologger.AUTOLOGGER_NAME,,23/8/2022
 T1562.001-Win Defender Disable using Powershell,ScriptBlock,Set-MpPreference -DisableRealtimeMonitoring|Set-MpPreference DisableBehaviorMonitoring|Set-MpPreference -DisableScriptScanning|Set-MpPreference -DisableBlockAtFirstSeen|MpPreference -ExclusionPath,,12/8/2022
 T1059.001-Malicious Powershell Commandlets,Commandlet,Add-ConstrainedDelegationBackdoor|Add-DomainObjectAcl|Add-Exfiltration|Add-ObjectAcl|Add-Persistance|Add-Persistence|Add-RegBackdoor|Add-RemoteConnection|Add-ScrnSaveBackdoor|Add-ServiceDacl|Add-SignedIntAsUnsigned|Bloodhound|Check-VM|Convert-ADName|Convert-DNSRecord|Convert-FileRight|Convert-LDAPProperty|Convert-NameToSid|Convert-SwitchtoBool|Convert-UIntToInt|ConvertFrom-LDAPLogonHours|ConvertFrom-SID|ConvertFrom-UACValue|ConvertTo-LittleEndian|ConvertTo-LogonHoursArray|ConvertTo-RC4ByteStream|ConvertTo-SID|Copy-ArrayOfMemAddresses|Copy-VSS|Create-MultipleSessions|Create-NamedPipe|Create-ProcessWithToken|Create-RemoteThread|Create-SuspendedWinLogon|Create-WinLogonProcess|DataToEncode|Decrypt-Bytes|DNS_TXT_Pwnage|Do-Exfiltration|Download_Execute|Download-Execute-PS|DumpCerts|DumpCreds|Emit-CallThreadStub|Enable-Duplication|Enable-Privilege|Enable-SeAssignPrimaryTokenPrivilege|Enable-SeDebugPrivilege|Enabled-DuplicateToken|Enum-AllTokens|Exclude-Hosts|Execute-Command-MSSQL|Execute-DNSTXT-Code|Execute-OnTime|ExetoText|exfill|ExfilOption|Expand-Archive|Exploit-Jboss|Export-PowerViewCSV|FakeDC|Find-4624Logon|Find-4648Logon|Find-AppLockerLog|Find-AVSignature|Find-DomainLocalGroupMember|Find-DomainObjectPropertyOutlier|Find-DomainProcess|Find-DomainShare|Find-DomainUserEvent|Find-DomainUserLocation|Find-ForeignGroup|Find-ForeignUser|Find-Fruit|Find-GPOComputerAdmin|Find-GPOLocation|Find-InterestingDomainAcl|Find-InterestingDomainShareFile|Find-InterestingFile|Find-LocalAdminAccess|Find-ManagedSecurityGroups|Find-PathDLLHijack|Find-ProcessDLLHijack|Find-PSScriptsInPSAppLog|Find-RDPClientConnection|Find-TrustedDocuments|FireBuster|FireListener|Free-AllTokens|Get-ADObject|Get-AllAttributesForClass|Get-ApplicationHost|Get-CachedGPPPassword|Get-CachedRDPConnection|Get-ChromeDump|Get-ClipboardContents|Get-ComputerDetail|Get-DecryptedCpassword|Get-DecryptedSitelistPassword|Get-DelegateType|Get-DFSshare|Get-DNSRecord|Get-DNSZone|Get-Domain|Get-DomainComputer|Get-DomainController|Get-DomainDFSShare|Get-DomainDFSShareV1|Get-DomainDFSShareV2|Get-DomainDNSRecord|Get-DomainDNSZone|Get-DomainFileServer|Get-DomainForeignGroupMember|Get-DomainForeignUser|Get-DomainGPO|Get-DomainGPOComputerLocalGroupMapping|Get-DomainGPOLocalGroup|Get-DomainGPOUserLocalGroupMapping|Get-DomainGroup|Get-DomainGroupMember|Get-DomainGroupMemberDeleted|Get-DomainGUIDMap|Get-DomainManagedSecurityGroup|Get-DomainObject|Get-DomainOU|Get-DomainPolicy|Get-DomainSearcher|Get-DomainSID|Get-DomainSite|Get-DomainSPNTicket|Get-DomainSubnet|Get-DomainTrust|Get-DomainTrustMapping|Get-DomainUser|Get-DomainUserEvent|Get-Forest|Get-ForestDomain|Get-ForestGlobalCatalog|Get-ForestSchemaClass|Get-ForestTrust|Get-FoxDump|Get-GPODelegation|Get-GPPInnerField|Get-GPPPassword|Get-GptTmpl|Get-GroupsXML|Get-Hex|Get-HttpStatus|Get-ImageNtHeaders|Get-IndexedItem|Get-Information|Get-IniContent|Get-IPAddress|Get-Keystrokes|Get-LastLoggedOn|Get-LoggedOnLocal|Get-LSASecret|Get-MemoryProcAddress|Get-MicrophoneAudio|Get-ModifiablePath|Get-ModifiableRegistryAutoRun|Get-ModifiableScheduledTaskFile|Get-ModifiableService|Get-ModifiableServiceFile|Get-NetComputer|Get-NetComputerSiteName|Get-NetDomain|Get-NetDomainController|Get-NetDomainTrust|Get-NetFileServer|Get-NetForest|Get-NetGPO|Get-NetGroup|Get-NetGroupMember|Get-NetLocalGroup|Get-NetLoggedon|Get-NetOU|Get-NetProcess|Get-NetRDPSession|Get-NetSession|Get-NetShare|Get-NetSite|Get-NetSubnet|Get-NetUser|Get-ObjectAcl|Get-PassHashes|Get-PassHints|Get-PathAcl|Get-PEArchitecture|Get-PEBasicInfo|Get-PEDetailedInfo|Get-PrimaryToken|Get-PrincipalContext|Get-ProcAddress|Get-ProcessTokenGroup|Get-ProcessTokenPrivilege|Get-ProcessTokenType|Get-Property|Get-Proxy|Get-RandomName|Get-RegAlwaysInstallElevated|Get-RegAutoLogon|Get-RegistryAlwaysInstallElevated|Get-RegistryAlwaysInstallElevated.|Get-RegistryAutoLogon|Get-RegistryMountedDrive|Get-RegLoggedOn|Get-RemoteProcAddress|Get-RemoteProcAddressFunction|Get-RickAstley|Get-Screenshot|Get-SecurityPackages|Get-ServiceDetail|Get-ServiceFilePermission|Get-ServicePermission|Get-ServiceUnquoted|Get-SitelistField|Get-SiteListPassword|Get-SiteName|Get-System|Get-SystemNamedPipe|Get-SystemToken|Get-ThreadToken|Get-TimedScreenshot|Get-TokenInformation|Get-TopPort|Get-UnattendedInstallFile|Get-Unconstrained|Get-UniqueTokens|Get-UnquotedService|Get-USBKeystrokes|Get-UserEvent|Get-VaultCredential|Get-VaultElementValue|Get-VirtualProtectValue|Get-VolumeShadowCopy|Get-VulnAutoRun|Get-VulnSchTask|Get-Web-Credentials|Get-WebConfig|Get-Win32Constants|Get-Win32Functions|Get-Win32Types|Get-WLAN-Keys|Get-WMIProcess|Get-WMIRegCachedRDPConnection|Get-WMIRegLastLoggedOn|Get-WMIRegMountedDrive|Get-WMIRegProxy|Gupt-Backdoor|HTTP-Backdoor|HTTP-Login|Import-DllImports|Import-DllInRemoteProcess|Inject-LocalShellcode|Inject-RemoteShellcode|Install-ServiceBinary|Install-SSP|InttoIP|Invoke-ACLScanner|Invoke-ADSBackdoor|Invoke-AllChecks|Invoke-AmsiBypass|Invoke-ARPScan|Invoke-AzureHound|Invoke-BackdoorLNK|Invoke-BadPotato|Invoke-BetterSafetyKatz|Invoke-BruteForce|Invoke-BypassUAC|Invoke-Carbuncle|Invoke-Certify|Invoke-CheckLocalAdminAccess|Invoke-CompareAttributesForClass|Invoke-CreateRemoteThread|Invoke-CredentialInjection|Invoke-CredentialsPhish|Invoke-DAFT|Invoke-DCSync|Invoke-Decode|Invoke-DinvokeKatz|Invoke-DllInjection|Invoke-DowngradeAccount|Invoke-EgressCheck|Invoke-Empire|Invoke-Encode|Invoke-EnumerateLocalAdmin|Invoke-EventHunter|Invoke-EventVwrBypass|Invoke-Eyewitness|Invoke-FakeLogonScreen|Invoke-Farmer|Invoke-FileFinder|Invoke-Get-RBCD-Threaded|Invoke-Gopher|Invoke-GPOLinks|Invoke-Grouper2|Invoke-HandleKatz|Invoke-ImpersonateUser|Invoke-Interceptor|Invoke-Internalmonologue|Invoke-Inveigh|Invoke-InveighRelay|Invoke-JSRatRegsvr|Invoke-JSRatRundll|Invoke-Kerberoast|Invoke-KrbRelayUp|Invoke-LdapSignCheck|Invoke-Lockless|Invoke-MapDomainTrust|Invoke-MemoryFreeLibrary|Invoke-MemoryLoadLibrary|Invoke-Method|Invoke-MITM6|Invoke-NanoDump|Invoke-NetRipper|Invoke-NetworkRelay|Invoke-NinjaCopy|Invoke-OxidResolver|Invoke-P0wnedshell|Invoke-Paranoia|Invoke-PatchDll|Invoke-PortScan|Invoke-PoshRatHttp|Invoke-PoshRatHttps|Invoke-PostExfil|Invoke-Potato|Invoke-PowerDump|Invoke-PPLDump|Invoke-Prasadhak|Invoke-PrintNightmare|Invoke-PrivescAudit|Invoke-ProcessHunter|Invoke-PsExec|Invoke-PSGcat|Invoke-PsGcatAgent|Invoke-PSInject|Invoke-PsUaCme|Invoke-ReflectivePEInjection|Invoke-ReverseDNSLookup|Invoke-ReverseDnsLookup|Invoke-RevertToSelf|Invoke-Rubeus|Invoke-RunAs|Invoke-SafetyKatz|Invoke-SauronEye|Invoke-SCShell|Invoke-Seatbelt|Invoke-ServiceAbuse|Invoke-SessionGopher|Invoke-ShareFinder|Invoke-SharpAllowedToAct|Invoke-SharpBlock|Invoke-SharpBypassUAC|Invoke-SharpChromium|Invoke-SharpClipboard|Invoke-SharpCloud|Invoke-SharpDPAPI|Invoke-SharpDump|Invoke-SharPersist|Invoke-SharpGPO-RemoteAccessPolicies|Invoke-SharpGPOAbuse|Invoke-SharpHandler|Invoke-SharpHide|Invoke-Sharphound|Invoke-SharpImpersonation|Invoke-SharpImpersonationNoSpace|Invoke-SharpKatz|Invoke-SharpLdapRelayScan|Invoke-Sharplocker|Invoke-SharpLoginPrompt|Invoke-SharpMove|Invoke-SharpPrinter|Invoke-SharpPrintNightmare|Invoke-SharpRDP|Invoke-SharpSecDump|Invoke-Sharpshares|Invoke-SharpSniper|Invoke-SharpSploit|Invoke-SharpSpray|Invoke-SharpSSDP|Invoke-SharpStay|Invoke-SharpUp|Invoke-Sharpview|Invoke-SharpWatson|Invoke-Sharpweb|Invoke-Shellcode|Invoke-ShellCommand|Invoke-SMBAutoBrute|Invoke-SMBScanner|Invoke-Snaffler|Invoke-Spoolsample|Invoke-SSHCommand|Invoke-SSIDExfil|Invoke-StandIn|Invoke-StickyNotesExtract|Invoke-Tater|Invoke-ThreadedFunction|Invoke-Thunderfox|Invoke-ThunderStruck|Invoke-TokenManipulation|Invoke-Tokenvator|Invoke-UrbanBishop|Invoke-UserHunter|Invoke-UserImpersonation|Invoke-VoiceTroll|Invoke-Whisker|Invoke-WinEnum|Invoke-winPEAS|Invoke-WireTap|Invoke-WmiCommand|Invoke-WScriptBypassUAC|Invoke-Zerologon|Jitter|Kerberoast|Kerbroast|Keylogger|LoggedKeys|MailRaider|Mimikat|Mimikittenz|Mount-VolumeShadowCopy|NetShareEnum|NetWkstaUserEnum|New-ADObjectAccessControlEntry|New-DomainGroup|New-DomainUser|New-DynamicParameter|New-HoneyHash|New-InMemoryModule|New-ScriptBlockCallback|New-ThreadedFunction|New-VolumeShadowCopy|Nishang|NotAllNameSpaces|Out-CHM|Out-CompressedDll|OUT-DNSTXT|Out-EncodedCommand|Out-EncryptedScript|Out-HTA|Out-Minidump|Out-RundllCommand|Out-SCF|Out-Shortcut|Out-WebQuery|Out-Word|Parse_Keys|Parse-Hosts|Parse-ILHosts|Parse-IPList|Parse-IpPorts|Parse-Pkt|Parse-Ports|ParseKeys|Password-List|Port-Scan|PortScan-Alive|Portscan-Port|PowerBreach|Powerpreter|PowerUp|PowerView|Remove-DomainGroupMember|Remove-DomainObjectAcl|Remove-Persistence|Remove-Ports|Remove-PoshRat|Remove-RemoteConnection|Remove-Update|Remove-VolumeShadowCopy|Request-SPNTicket|Resolve-IPAddress|Restore-ServiceBinary|Run-EXEonRemote|Set-ADObject|Set-DCShadowPermissions|Set-DesktopACLs|Set-DesktopACLToAllowEveryone|Set-DomainObject|Set-DomainObjectOwner|Set-DomainUserPassword|Set-FilelessBypassUac|Set-MacAttribute|Set-PowerStego|Set-Property|Set-RemotePSRemoting|Set-RemoteWMI|Set-ServiceBinaryPath|Set-Wallpaper|Sharphound|Shellcode|Shellcode32|Shellcode64|Show-TargetScreen|Split-Path|Start-CaptureServer|Start-Dnscat|Start-WebcamRecorder|StringtoBase64|Sub-SignedIntAsUnsigned|Test-AdminAccess|Test-IsAdmin|Test-MemoryRangeValid|Test-ServiceDaclPermission|TexttoExe|Update-ExeFunctions|Update-MemoryAddresses|Update-MemoryProtectionFlags|VolumeShadowCopyTools|Write-BytesToMemory|Write-HijackDll|Write-PortscanOut|Write-ServiceBinary|Write-UserAddMSI,,12/8/2022
 T1059.01-Powershell Malicious Keywords,ScriptBlock|Commandlet,AdjustTokenPrivileges|IMAGE_NT_OPTIONAL_HDR64_MAGIC|Microsoft.Win32.UnsafeNativeMethods|ReadProcessMemory.Invoke|SE_PRIVILEGE_ENABLED|LSA_UNICODE_STRING|MiniDumpWriteDump|PAGE_EXECUTE_READ|SECURITY_DELEGATION|TOKEN_ADJUST_PRIVILEGES|TOKEN_ALL_ACCESS|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE|TOKEN_ELEVATION|TOKEN_IMPERSONATE|TOKEN_INFORMATION_CLASS|TOKEN_PRIVILEGES|TOKEN_QUERY|System.Reflection.Assembly.Load|[System.Reflection.Assembly]::Load|[Reflection.Assembly]::Load|System.Reflection.AssemblyName|Reflection.Emit.AssemblyBuilderAccess|Runtime.InteropServices.DllImportAttribute|SuspendThread|Metasploit|Mimikatz|PS ATTACK,,12/8/2022
 T1059.001-Loading Powershell in Memory,ScriptBlock|Commandlet,System.Reflection.AssemblyName|System.Reflection.Emit.AssemblyBuilderAccess|System.Runtime.InteropServices.MarshalAsAttribute|memorystream,,12/8/2022
 
sources:
 - query: |
 -- materialize ignore path regex where exist and not \s
 LET ScriptIgnore = SELECT _value as PathRegex 
 FROM foreach(row=split(string=IgnorePaths,sep='\n')) 
 WHERE PathRegex AND NOT PathRegex =~ '^\\s+$'
 LET ScriptIgnorePath &amp;lt;= join(array=ScriptIgnore.PathRegex,sep='|')
 
 -- materialize scriptblock regex for initial pass
 LET ScriptBlock = SELECT Regex,Type FROM IocCsv WHERE Type =~ 'ScriptBlock'
 LET ScriptBlockRegex &amp;lt;= join(array=ScriptBlock.Regex,sep='|')
 
 -- materialize Commandlet regex for initial pass
 LET Commandlet = SELECT Regex,Type FROM IocCsv WHERE Type =~ 'Commandlet'
 LET CommandletRegex &amp;lt;= join(array=Commandlet.Regex,sep='|')
 
 -- watch ETW provider and first round data manipulation
 LET hits = SELECT 
 timestamp(epoch=timestamp(string=System.TimeStamp).unix) as EventTime,
 System.ID as EventID,
 System.ProcessID as ProcessID,
 get(member="EventData") AS EventData
 FROM watch_etw(guid="{a0c1853b-5c40-4b15-8766-3cf1c58f985a}") 
 WHERE ( EventData.ScriptBlockText OR EventData.Payload =~ '^Command .+ is Started\.\r\n$' )
 AND ( EventData.ScriptBlockText =~ ScriptBlockRegex
 OR EventData.Payload =~ CommandletRegex )
 
 -- print rows
 SELECT * FROM foreach(row=hits,query={
 SELECT
 EventTime,
 dict(
 Name=Name,
 Type=Type,
 Regex=Regex,
 Ignore=Ignore
 ) as Detection,
 EventID,
 if(condition= EventID=4104,
 then= EventData.ScriptBlockText,
 else= regex_replace(
 source=EventData.Payload,
 re='^Command | is Started\.\r\n$',
 replace=''
 )) as Payload,
 if(condition= EventID=4104,
 then= EventData,
 else= dict(Payload=EventData.Payload,
 ContextInfo=parse_string_with_regex(string=EventData.ContextInfo,
 regex=[
 'Severity = (?P&amp;lt;Severity&amp;gt;[^\\r]*)',
 'Host Name = (?P&amp;lt;HostName&amp;gt;[^\\r]*)',
 'Host Version = (?P&amp;lt;HostVersion&amp;gt;[^\\r]*)',
 'Host ID = (?P&amp;lt;HostID&amp;gt;[^\\r]*)',
 'Host Application = (?P&amp;lt;HostApplication&amp;gt;[^\\r]*)',
 'Engine Version = (?P&amp;lt;EngineVersion&amp;gt;[^\\r]*)',
 'Runspace ID = (?P&amp;lt;RunspaceID&amp;gt;[^\\r]*)',
 'Pipeline ID = (?P&amp;lt;PipelineID&amp;gt;[^\\r]*)',
 'Command Name= (?P&amp;lt;CommandName&amp;gt;[^\\r]*)',
 'CommandType = (?P&amp;lt;CommandType&amp;gt;[^\\r]*)',
 'Script Name = (?P&amp;lt;ScriptName&amp;gt;[^\\r]*)',
 'Command Path = (?P&amp;lt;CommandPath&amp;gt;[^\\r]*)',
 'Sequence Number = (?P&amp;lt;SequenceNumber&amp;gt;[^\\r]*)',
 'User = (?P&amp;lt;User&amp;gt;[^\\r]*)',
 'Connected User = (?P&amp;lt;ConnectedUser&amp;gt;[^\\r]*)',
 'Shell ID = (?P&amp;lt;ShellID&amp;gt;[^\\r]*)'
 ]),
 UserData=EventData.UserData)) as EventData,
 process_tracker_callchain(id=ProcessID).Data[-1] as ProcessInfo,
 process_tracker_callchain(id=ProcessID).Data as ProcessChain
 FROM IocCsv
 WHERE 
 if(condition= EventID=4104, then= Type=~'ScriptBlock',else= Type=~'Commandlet' )
 AND NOT if(condition=IgnoreProcessExe, 
 then= ProcessInfo.Exe =~ IgnoreProcessExe, else= False)
 AND NOT if(condition=IgnoreParentProcessExe, 
 then= ProcessChain.Exe[-2] =~ IgnoreParentProcessExe, else= False)
 AND Payload =~ Regex 
 AND NOT if(condition=Ignore, then= Payload=~Ignore, else= False)
 AND NOT if(condition=IgnorePaths,
 then= EventData.Path =~ ScriptIgnorePath 
 OR EventData.ContextInfo.CommandPath =~ ScriptIgnorePath
 OR EventData.ContextInfo.ScriptName =~ ScriptIgnorePath,
 else= False)
 LIMIT 1 -- limts to 1 row per IocCsv entry.
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.ScreenshotTaken</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.screenshottaken/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.etw.screenshottaken/</guid><description>&lt;p&gt;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.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
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") &amp;gt;= 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 &amp;gt;= 1
 
 SELECT timestamp(string=System.TimeStamp) AS Timestamp,
 ProcInfo,
 ScreenshotPid AS Pid,
 Count
 FROM Track
 WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.ETW.WMIEventing</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/wmieventing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/wmieventing/</guid><description>&lt;p&gt;This artifact collects events associated with creation and deletion of WMI
Event Consumers. All Event Consumers created under any namespace will
generate events which are filtered on event consumer classes.&lt;/p&gt;
&lt;p&gt;It uses the ETW provider:
Microsoft-Windows-WMI-Activity {1418ef04-b0b4-4623-bf7e-d74ab47bbdaa}&lt;br&gt;
Note: This provider events have support on Windows 10+&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.ETW.WMIEventing
author: Matt Green - @mgreen27
description: |
 This artifact collects events associated with creation and deletion of WMI 
 Event Consumers. All Event Consumers created under any namespace will 
 generate events which are filtered on event consumer classes. 
 
 It uses the ETW provider:
 Microsoft-Windows-WMI-Activity {1418ef04-b0b4-4623-bf7e-d74ab47bbdaa} 
 Note: This provider events have support on Windows 10+

type: CLIENT_EVENT

sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 
 query: |
 LET RecentProcesses = SELECT * FROM fifo(query={
 SELECT System.TimeStamp AS CreateTime, 
 EventData.ImageName AS ImageName,
 int(int=EventData.ProcessID) AS Pid,
 EventData.MandatoryLabel AS MandatoryLabel,
 EventData.ProcessTokenElevationType AS ProcessTokenElevationType,
 EventData.ProcessTokenIsElevated AS TokenIsElevated
 FROM watch_etw(guid="{22fb2cd6-0e7b-422b-a0c7-2fad1fd0e716}", any=0x10)
 WHERE System.ID = 1 
 }, max_rows=1000, max_age=60)
 
 -- Query it once to materialize the FIFO
 LET _ &amp;lt;= SELECT * FROM RecentProcesses
 
 LET GetProcessInfo(TargetPid) = SELECT * FROM switch(
 -- First try to get the pid directly
 a={
 SELECT 
 Name, Pid, CreateTime,
 Exe as ImageName,
 CommandLine,
 Username,
 TokenIsElevated
 FROM pslist(pid=TargetPid)
 },
 -- Failing this look in the FIFO for a recently started process.
 b={
 SELECT
 basename(path=ImageName) as Name,
 Pid,
 CreateTime,
 ImageName,
 Null as CommandLine,
 Null as Username,
 if(condition= TokenIsElevated="0", 
 then= false, 
 else= true ) as TokenIsElevated
 FROM RecentProcesses
 WHERE Pid = TargetPid
 LIMIT 1
 })
 
 -- watch ETW provider and first round data manipulation
 SELECT
 System.TimeStamp AS EventTime,
 System.ID as EventId,
 strip(prefix='\\\\\.\\',string=EventData.NamespaceName) as NamespaceName,
 EventData.Operation as Operation,
 GetProcessInfo(TargetPid=int(int=EventData.ClientProcessId))[0] as Process,
 EventData.IsLocal as IsLocal,
 EventData.ClientMachine as ClientMachine,
 EventData.ClientMachineFQDN as ClientMachineFQDN,
 EventData.User as User,
 EventData.CorrelationId as CorrelationId,
 EventData.OperationId as OperationId,
 EventData.GroupOperationId as GroupOperationId
 FROM watch_etw(guid="{1418ef04-b0b4-4623-bf7e-d74ab47bbdaa}")
 WHERE EventId = 11
 AND Operation =~ 'WbemServices::(PutInstance|DeleteInstance|PutClass|DeleteClass)'
 AND Operation =~ 'EventConsumer|EventFilter|FilterToConsumerBinding'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.Aurora</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.aurora/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.aurora/</guid><description>&lt;p&gt;This artifact is a wrapper around the Windows.EventLogs.EvtxHunter artifact. It searches the Windows Application event log for logs being written by Nextron System&amp;rsquo;s Aurora/Aurora Lite (&amp;lsquo;AuroraAgent&amp;rsquo; provider).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.Aurora
author: Wes Lambert - @therealwlambert
description: |
 This artifact is a wrapper around the Windows.EventLogs.EvtxHunter artifact. It searches the Windows Application event log for logs being written by Nextron System's Aurora/Aurora Lite ('AuroraAgent' provider).

reference:
 - https://www.nextron-systems.com/aurora/

parameters:
 - name: MessageRegex
 description: "Message regex to enable filtering on message"
 default: .
 - name: TargetGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 SELECT EventTime,
 Computer,
 Channel,
 Provider,
 EventID,
 EventRecordID,
 EventData,
 Message,
 FullPath
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=TargetGlob,
 ProviderRegex="AuroraAgent",
 VSSAnalysisAge=VSSAnalysisAge)
 WHERE Message =~ MessageRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.Bitsadmin</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/bitsadmin/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/bitsadmin/</guid><description>&lt;p&gt;This content will extract BITS Transfer events and enable filtering by URL
and TLD.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.Bitsadmin
author: "Matt Green - @mgreen27"
description: |
 This content will extract BITS Transfer events and enable filtering by URL 
 and TLD.

reference:
 - https://attack.mitre.org/techniques/T1197/
 - https://mgreen27.github.io/posts/2018/02/18/Sharing_my_BITS.html

parameters:
 - name: EventLog
 default: C:\Windows\System32\winevt\Logs\Microsoft-Windows-Bits-Client%4Operational.evtx
 - name: TldAllowListRegex
 description: TLD allow list regex - anchor TLD - e.g live.com
 default: '(office365|dell|live|mozilla|sun|adobe|onenote|microsoft|windowsupdate|google|oracle|hp)\.(net|com|(|\.au))|\.(office\.net|sentinelone\.net|connectwise.net)|(oneclient\.sfx|aka)\.ms|(edgedl.me|redirector)\.gvt1\.com|^(10|192\.168|172\.(1[6-9]|2[0-9]|3[0-1]))\.\d{1,3}\.\d{1,3}$'
 - name: UrlAllowListRegex
 description: Secondary whitelist regex. Used for Url

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

 query: |
 -- Find Files in scope
 LET files = SELECT * FROM glob(globs=EventLog)
 
 LET results = SELECT * FROM foreach(
 row=files,
 query={
 SELECT
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) AS EventTime,
 System.Computer as Computer,
 System.EventID.Value as EventId,
 System.Security.UserID as UserId,
 EventData.transferId as TransferId,
 EventData.name as Name,
 EventData.id as Id,
 EventData.url as Url,
 url(parse=EventData.url).Host AS TLD,
 EventData.peer as Peer,
 timestamp(epoch=EventData.fileTime) as FileTime,
 EventData.fileLength as fileLength,
 EventData.bytesTotal as bytesTotal,
 EventData.bytesTransferred as bytesTransferred,
 EventData.bytesTransferredFromPeer
 FROM parse_evtx(filename=OSPath)
 WHERE 
 EventId = 59
 AND NOT if( condition= TldAllowListRegex,
 then= TLD =~ TldAllowListRegex,
 else= FALSE)
 AND NOT if( condition= UrlAllowListRegex,
 then= Url =~ UrlAllowListRegex,
 else= FALSE)
 })

 SELECT * FROM results
 
 notebook:
 - type: vql_suggestion
 name: Stack rank by TLD
 template: |
 /*
 ## TLD stacking - find potential to add to Ignore regex and triage low counts
 */
 SELECT TLD,count() as TldTotal,
 Url as UrlExample
 FROM source(artifact="Windows.EventLogs.Bitsadmin")
 GROUP BY TLD
 ORDER BY TldTotal

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.Chainsaw</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.chainsaw/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.chainsaw/</guid><description>&lt;p&gt;This artifact leverages Chainsaw to enable usage of Sigma rules
(in addition to built-in rules) to faciliate detection within
Windows Event Logs.&lt;/p&gt;
&lt;p&gt;From the project&amp;rsquo;s description:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Chainsaw provides a powerful ‘first-response’ capability to
quickly identify threats within Windows event logs. It offers a
generic and fast method of searching through event logs for
keywords, and by identifying threats using built-in detection
logic and via support for Sigma detection rules.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/countercept/chainsaw" target="_blank" &gt;https://github.com/countercept/chainsaw&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.Chainsaw
description: |

 This artifact leverages Chainsaw to enable usage of Sigma rules
 (in addition to built-in rules) to faciliate detection within
 Windows Event Logs.

 From the project's description:

 "Chainsaw provides a powerful ‘first-response’ capability to
 quickly identify threats within Windows event logs. It offers a
 generic and fast method of searching through event logs for
 keywords, and by identifying threats using built-in detection
 logic and via support for Sigma detection rules."

 https://github.com/countercept/chainsaw

author: Wes Lambert - @therealwlambert, James Dorgan - @FranticTyping, Alex Korntizer - @AlexKornitzer
tools:
 - name: Chainsaw
 url: https://github.com/WithSecureLabs/chainsaw/releases/download/v2.9.0/chainsaw_all_platforms+rules+examples.zip
 version: 2.9.0
 expected_hash: 9f809ea14b71e7c53fde8ebef7f3a82881f4dcacec97566b29cc914324667eda
 
precondition: SELECT OS From info() where OS = 'windows'

parameters:
 - name: EVTXPath
 default: 'C:\Windows\System32\winevt\Logs'
 - name: ExecLength
 description: Size (in bytes) of output that will be returned for a single row for execve(). This value may need to be adjusted depending on the size of your event logs.
 type: int
 default: "100000000"
 - name: JSONLength
 description: Size (in bytes) of output that will be returned for a single row for parse_json_array(). This value may need to be adjusted depending on the size of your event logs.
 type: int
 default: "100000000"

sources:
 - query: |
 LET Toolzip &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Chainsaw", IsExecutable=FALSE)
 LET TmpDir &amp;lt;= tempdir()
 LET TmpResults &amp;lt;= tempfile()
 LET UnzipIt &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)
 LET SigmaRules &amp;lt;= TmpDir + '\\chainsaw\\sigma\\rules'
 LET ChainsawRules &amp;lt;= TmpDir + '\\chainsaw\\rules'
 LET SigmaMapping &amp;lt;= TmpDir + '\\chainsaw\\mappings\\sigma-event-logs-all.yml'
 LET ExecCS &amp;lt;= SELECT * FROM execve(argv=[
 TmpDir + '\\chainsaw\\chainsaw_x86_64-pc-windows-msvc.exe',
 'hunt', EVTXPath,
 "-s", SigmaRules,
 "-r", ChainsawRules,
 "--mapping", SigmaMapping,
 "--json",
 "--output", TmpResults], length=ExecLength)
 SELECT get(member="document.data.Event.System.TimeCreated_attributes.SystemTime") AS EventTime,
 get(member="name") AS Detection,
 get(member="level") AS Severity,
 get(member="status") AS Status,
 get(member="group") AS `Rule Group`,
 get(member="document.data.Event.System.Computer") AS Computer,
 get(member="document.data.Event.System.Channel") AS Channel,
 get(member="document.data.Event.System.EventID") AS EventID,
 get(member="document.data.Event.EventData.User") AS _User,
 get(member="document.data.Event.System") AS SystemData,
 get(member="document.data.Event.EventData") AS EventData,
 get(member="authors") AS Authors
 FROM parse_json_array(data=read_file(filename=TmpResults, length=JSONLength))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.CondensedAccountUsage</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/condensedaccountusage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/condensedaccountusage/</guid><description>&lt;p&gt;This artifact will extract condensed information on logon / logoff events.&lt;/p&gt;
&lt;p&gt;Security channel - EventIDs in 4624, 4625, 4634, 4647, 4648, 4672, 4778,
4779, 4800, 4801, 4802, and 4803.&lt;/p&gt;
&lt;p&gt;Exclude by default events related to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UserName egal to SYSTEM, ANONYMOUS LOGON, LOCAL SERVICE, NETWORK
SERVICE, or %ComputerName%$.&lt;/li&gt;
&lt;li&gt;Domain egal to NT AUTHORITY, Font Driver Host, or Window Manager.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inspired from work by Brian Maloney and @0x47617279.&lt;br&gt;
Thanks to Mike Cohen (scudette) for its help optimizing the query.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.CondensedAccountUsage
description: |
 This artifact will extract condensed information on logon / logoff events.
 
 Security channel - EventIDs in 4624, 4625, 4634, 4647, 4648, 4672, 4778,
 4779, 4800, 4801, 4802, and 4803.
 
 Exclude by default events related to: 
 - UserName egal to SYSTEM, ANONYMOUS LOGON, LOCAL SERVICE, NETWORK
 SERVICE, or %ComputerName%$. 
 - Domain egal to NT AUTHORITY, Font Driver Host, or Window Manager.
 
 Inspired from work by Brian Maloney and @0x47617279. 
 Thanks to Mike Cohen (scudette) for its help optimizing the query. 
 

author: Thomas DIOT (Qazeer)

type: CLIENT

parameters:
 - name: SecurityEvtx
 default: '%SystemRoot%\System32\Winevt\Logs\Security.evtx'

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

 query: |
 
 LET DomainNameLookup &amp;lt;= dict(
 `4624` = 'TargetDomainName',
 `4625` = 'TargetDomainName',
 `4634` = 'TargetDomainName',
 `4647` = 'TargetDomainName',
 `4648` = 'SubjectDomainName',
 `4672` = 'SubjectDomainName',
 `4778` = 'AccountDomain',
 `4779` = 'AccountDomain',
 `4800` = 'TargetDomainName',
 `4801` = 'TargetDomainName',
 `4802` = 'TargetDomainName',
 `4803` = 'TargetDomainName')
 
 LET UserNameLookup &amp;lt;= dict(
 `4624` = 'TargetUserName',
 `4625` = 'TargetUserName',
 `4634` = 'TargetUserName',
 `4647` = 'TargetUserName',
 `4648` = 'SubjectUserName',
 `4672` = 'SubjectUserName',
 `4778` = 'AccountName',
 `4779` = 'AccountName',
 `4800` = 'TargetUserName',
 `4801` = 'TargetUserName',
 `4802` = 'TargetUserName',
 `4803` = 'TargetUserName')
 
 LET LogonIdLookup &amp;lt;= dict(
 `4624` = 'TargetLogonId',
 `4625` = '-',
 `4634` = 'TargetLogonId',
 `4647` = 'TargetLogonId',
 `4648` = 'SubjectLogonId',
 `4672` = 'SubjectLogonId',
 `4778` = 'LogonID',
 `4779` = 'LogonID',
 `4800` = 'TargetLogonId',
 `4801` = 'TargetLogonId',
 `4802` = 'TargetLogonId',
 `4803` = 'TargetLogonId')
 
 LET LogonDescriptionLookup &amp;lt;= dict(
 `4624` = 'ACCOUNT_LOGGED_ON',
 `4625` = 'ACCOUNT_FAILED_TO_LOGON',
 `4634` = 'ACCOUNT_LOGGED_OFF',
 `4647` = 'ACCOUNT_INITITATED_LOGOFF',
 `4648` = 'LOGON_ATTEMPT_EXPLICIT_CREDENTIALS',
 `4672` = 'PRIVILEGED_LOGON',
 `4778` = 'SESSION_RECONNECTED',
 `4779` = 'SESSION_DISCONNECTED',
 `4800` = 'WORKSATION_LOCKED',
 `4801` = 'WORKSATION_UNLOCKED',
 `4802` = 'SCREENSAVER_INVOKED',
 `4803` = 'SCREENSAVER_DISMISSED')

 LET LogonTypeLookup &amp;lt;= dict(
 `0` = 'SYSTEM_LOGON',
 `2` = 'INTERACTIVE_LOGON',
 `3` = 'NETWORK_LOGON',
 `4` = 'BATCH_LOGON',
 `5` = 'SERVICE_LOGON',
 `7` = 'UNLOCK_LOGON',
 `8` = 'NETWORK_CLEARTEXT_LOGON',
 `9` = 'NEW_CREDENTIALS',
 `10` = 'REMOTE_INTERACTIVE_LOGON',
 `11` = 'CACHED_INTERACTIVE_LOGON',
 `12` = 'CACHED_REMOTE_INTERACTIVE_LOGON',
 `13` = 'CACHED_UNLOCK_LOGON')
 
 SELECT
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) AS EventTime,
 System.Computer as Computer,
 System.EventID.Value as EventID,
 get(item=LogonDescriptionLookup,
 member=str(str=System.EventID.Value)) as Description,
 get(item=EventData,
 member=get(item=DomainNameLookup,
 member=str(str=System.EventID.Value))) AS DomainName,
 get(item=EventData,
 member=get(item=UserNameLookup,
 member=str(str=System.EventID.Value))) AS UserName,
 get(item=EventData,
 member=get(item=LogonIdLookup,
 member=str(str=System.EventID.Value))) AS LogonId,
 if(condition= System.EventID.Value = 4648,
 then= join(array=[EventData.TargetDomainName,
 EventData.TargetUserName],
 sep='\\'),
 else= '-') as CredentialsUsedFor4648,
 if(condition= EventData.LogonType,
 then= EventData.LogonType,
 else= '-') as LogonType,
 if(condition= EventData.LogonType,
 then= get(item=LogonTypeLookup,
 member=str(str=EventData.LogonType)),
 else= '-') as LogonTypeDescription,
 if(condition= EventData.AuthenticationPackageName,
 then= EventData.AuthenticationPackageName,
 else= '-' ) as AuthenticationPackageName,
 if(condition= EventData.IpAddress,
 then= EventData.IpAddress,
 else= if(condition= EventData.ClientAddress,
 then= EventData.ClientAddress,
 else= '-')) as IpAddress,
 if(condition= EventData.WorkstationName,
 then= EventData.WorkstationName,
 else= if(condition= EventData.ClientName,
 then= EventData.ClientName,
 else= '-')) as ClientName
 FROM parse_evtx(filename=expand(path=SecurityEvtx))
 WHERE System.Provider.Name =~ "Security-Auditing"
 AND System.EventID.Value in (4624, 4625, 4634, 4647, 4648, 4672, 4778, 4779, 4800, 4801, 4802, 4803)
 AND NOT UserName =~ '^(SYSTEM|ANONYMOUS LOGON|LOCAL SERVICE|NETWORK SERVICE)$'
 AND NOT UserName = expand(path='%ComputerName%$')
 AND NOT DomainName =~ '^(NT AUTHORITY|FONT DRIVER HOST|WINDOW MANAGER)$'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.DeepBlueCLI</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.deepbluecli/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.deepbluecli/</guid><description>&lt;p&gt;DeepBlueCLI - a PowerShell Module for Threat Hunting via Windows Event Logs&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.DeepBlueCLI
description: DeepBlueCLI - a PowerShell Module for Threat Hunting via Windows Event Logs

author: Anthony Hannouille - @AnthoLaMalice
tools:
 - name: DeepBlueCLI
 url: https://github.com/sans-blue-team/DeepBlueCLI/archive/refs/heads/master.zip
type: CLIENT

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

sources:
 - query: |
 LET Toolzip &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="DeepBlueCLI", IsExecutable=FALSE)
 
 LET TmpDir &amp;lt;= tempdir()
 
 LET _ &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)
 
 LET DeepBlueCLILocation &amp;lt;= TmpDir + '\\DeepBlueCLI-master'
 
 LET cmdline = 'powershell -executionpolicy bypass -command "cd '+ "'" + DeepBlueCLILocation + "'" + '; .\\DeepBlue.ps1 | ConvertTo-JSON"'
 
 SELECT * FROM foreach(
 row={
 SELECT Stdout FROM execve(argv=["Powershell", cmdline], length=104857600)
 }, query={
 SELECT * FROM parse_json_array(data=Stdout) where log(message=Stdout) AND log(message=Stderr)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.EvtxHussar</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.evtxhussar/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.evtxhussar/</guid><description>&lt;p&gt;Grab important events from Windows logs (.evtx) using &lt;a href="https://github.com/yarox24/EvtxHussar" target="_blank" &gt;EvtxHussar&lt;/a&gt;
.
Also upload PowerShell ScriptBlocks (reconstructed as files).&lt;/p&gt;
&lt;p&gt;Following categories are supported:&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Antivirus (Symantec, Windows Defender)&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Accounts (Users related operations)&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Audit (Log cleared, Policy changed)&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Windows Firewall &lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Logons&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Powershell events&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Processes&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;RDP&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;ScheduledTasks (creation/modification/execution)&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Services&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;WinRM&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Boot up/Restart/Shutdown&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;SMB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: If no logs from specific category will be found, source will remain empty.&lt;br /&gt;
Based on version 1.7 of EvtxHussar.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.EvtxHussar
description: |
 Grab important events from Windows logs (.evtx) using [EvtxHussar](https://github.com/yarox24/EvtxHussar).
 Also upload PowerShell ScriptBlocks (reconstructed as files).

 Following categories are supported:&amp;lt;br /&amp;gt;
 - Antivirus (Symantec, Windows Defender)&amp;lt;br /&amp;gt;
 - Accounts (Users related operations)&amp;lt;br /&amp;gt;
 - Audit (Log cleared, Policy changed)&amp;lt;br /&amp;gt;
 - Windows Firewall &amp;lt;br /&amp;gt;
 - Logons&amp;lt;br /&amp;gt;
 - Powershell events&amp;lt;br /&amp;gt;
 - Processes&amp;lt;br /&amp;gt;
 - RDP&amp;lt;br /&amp;gt;
 - ScheduledTasks (creation/modification/execution)&amp;lt;br /&amp;gt;
 - Services&amp;lt;br /&amp;gt;
 - WinRM&amp;lt;br /&amp;gt;
 - Boot up/Restart/Shutdown&amp;lt;br /&amp;gt;
 - SMB

 Note: If no logs from specific category will be found, source will remain empty.&amp;lt;br /&amp;gt;
 Based on version 1.7 of EvtxHussar.

author: Jarosław Oparka - @yarox24

type: CLIENT

resources:
 timeout: 3600 # 1 hour
 max_rows: 10000000 # 10 million
 max_upload_bytes: 5368709120 # 5 Gigabytes

tools:
 - name: EvtxHussar17
 url: https://github.com/yarox24/EvtxHussar/releases/download/1.7/EvtxHussar1.7_windows_amd64.zip
 serve_locally: true

precondition:
 SELECT OS From info() where OS = 'windows' AND Architecture = "amd64"

parameters:
 - name: LogsPath
 description: |
 Windows Event logs path
 default: "C:\\Windows\\System32\\winevt\\Logs"
 type: hidden
 - name: AntivirusSymantec
 description: |
 Include Symantec Network Protection (Application.evtx) events
 default: Y
 type: bool
 - name: AntivirusWindowsDefender
 description: |
 Include Windows Defender (Microsoft-Windows-Windows Defender%4Operational.evtx) events
 default: Y
 type: bool
 - name: AccountsUserRelatedOperations
 description: |
 Include events related to account manipulation (Security.evtx)
 default: Y
 type: bool
 - name: AuditLogCleared
 description: |
 Include events related to Windows Event log clearing (Security.evtx, System.evtx)
 default: Y
 type: bool
 - name: AuditPolicyChanges
 description: |
 Include events related to changes in audit policy (Security.evtx)
 default: Y
 type: bool
 - name: BootupRestartShutdown
 description: |
 Include events related to boot up/restart/shutdown of OS (System.evtx, Security.evtx)
 default: Y
 type: bool
 - name: Logons
 description: |
 Include events related to logon/logoff/sessions of Windows users (Security.evtx)
 default: Y
 type: bool
 - name: PowerShellScriptBlocksReconstructAndUpload
 description: |
 Include EID 4104 - Creating Scriptblock text (Microsoft-Windows-PowerShell%4Operational.evtx), reconstruct and upload them as .ps1 files
 default: Y
 type: bool
 - name: Option_PowerShellScriptBlocksXorApply
 description: |
 Should we apply XOR operation (Key: Y) on reconstructed PS ScriptBlocks when saving them temporarily on target system. May prevent them from deletion by AV.
 default: Y
 type: bool
 - name: PowerShellEvents
 description: |
 Include events related to PowerShell activity on the system (Microsoft-Windows-PowerShell%4Operational.evtx, Windows PowerShell.evtx)
 default: Y
 type: bool
 - name: Processes
 description: |
 Include events related to creation/termination of processess (Security.evtx, Microsoft-Windows-Sysmon%4Operational.evtxx)
 default: Y
 type: bool
 - name: RDP
 description: |
 Include events related to RDP activity on the system (Microsoft-Windows-RemoteDesktopServices-RdpCoreTS%4Operational.evtx, Security.evtx, Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx, Microsoft-Windows-TerminalServices-RDPClient%254Operational.evtx, Microsoft-Windows-TerminalServices-RemoteConnectionManager%4Operational.evtx)
 default: Y
 type: bool
 - name: ScheduledTasksCreationModification
 description: |
 Include events related to creation and modification of Scheduled Tasks (Microsoft-Windows-TaskScheduler%4Operational.evtx, Security.evtx)
 default: Y
 type: bool
 - name: ScheduledTasksExecution
 description: |
 Include events related to execution of Scheduled Tasks(Microsoft-Windows-TaskScheduler%4Operational.evtx)
 default: Y
 type: bool
 - name: Services
 description: |
 Include events related to Windows services (System.evtx, Security.evtx)
 default: Y
 type: bool
 - name: SMBClientDestinations
 description: |
 Include events related to usage of SMB Client (outgoing SMB connections)
 default: Y
 type: bool
 - name: SMBServerAccessAudit
 description: |
 Include events related to access to SMB Server (incoming SMB connections)
 default: Y
 type: bool
 - name: SMBServerModifications
 description: |
 Include events related to SMB Server configuration
 default: Y
 type: bool
 - name: WindowsFirewall
 description: |
 Include Windows Firewall (Microsoft-Windows-Windows Firewall With Advanced Security%4Firewall.evtx, Security.evtx) events
 default: Y
 type: bool
 - name: WinRM
 description: |
 Include events related to Windows Remote Management (Microsoft-Windows-WinRM%4Operational.evtx)
 default: Y
 type: bool


sources:
 - name: Antivirus_Symantec
 query: |
 // Execute EvtxHussar
 LET ZipInfo &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName= "EvtxHussar17", IsExecutable= False)

 LET tmpdir &amp;lt;= tempdir()

 LET Unpack &amp;lt;= SELECT * FROM unzip(filename=ZipInfo[0].FullPath, output_directory=tmpdir)

 LET Binpath &amp;lt;= tmpdir + "\\EvtxHussar\\EvtxHussar.exe"
 LET CWDpath &amp;lt;= tmpdir + "\\EvtxHussar\\"

 LET outdir &amp;lt;= tempdir()

 LET cnt &amp;lt;= int(int=0)
 LET IncreaseCounter(c, cat_flag) = if(condition= cat_flag = "Y", then=c + 1, else=c)

 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=AntivirusSymantec)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=AntivirusWindowsDefender)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=AccountsUserRelatedOperations)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=AuditLogCleared)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=AuditPolicyChanges)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=BootupRestartShutdown)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=Logons)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=PowerShellScriptBlocksReconstructAndUpload)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=PowerShellEvents)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=Processes)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=RDP)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=ScheduledTasksCreationModification)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=ScheduledTasksExecution)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=Services)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=SMBClientDestinations)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=SMBServerAccessAudit)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=SMBServerModifications)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=WinRM)
 LET cnt &amp;lt;= IncreaseCounter(c=cnt, cat_flag=WindowsFirewall)
 LET cnt_max &amp;lt;= int(int=19)


 LET AppendIfEnabled(arr, cat_flag, l2propername) = if(condition= cat_flag = "Y", then= arr + l2propername, else= arr )

 LET EnabledL2Maps &amp;lt;= array(a="TO_DELETE")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=AntivirusSymantec, l2propername="AV_SymantecNetwork")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=AntivirusWindowsDefender, l2propername="AV_WindowsDefender")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=AccountsUserRelatedOperations, l2propername="AccountsUserRelatedOperations")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=AuditLogCleared, l2propername="AuditLogCleared")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=AuditPolicyChanges, l2propername="AuditPolicyChanged")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=BootupRestartShutdown, l2propername="General_BootupRestartShutdown")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=Logons, l2propername="LogonsUniversal")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=PowerShellScriptBlocksReconstructAndUpload, l2propername="PowerShellScriptBlock")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=PowerShellEvents, l2propername="PowerShellUniversal")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=Processes, l2propername="ProcessCreation")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=RDP, l2propername="RDPUniversal")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=ScheduledTasksCreationModification, l2propername="ScheduledTasks_CreationModification")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=ScheduledTasksExecution, l2propername="ScheduledTasks_Execution")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=Services, l2propername="ServicesUniversal")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=SMBClientDestinations, l2propername="SMB_ClientDestinations")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=SMBServerAccessAudit, l2propername="SMB_ServerAccessAudit")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=SMBServerModifications, l2propername="SMB_ServerModifications")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=WinRM, l2propername="WinRMUniversal")
 LET EnabledL2Maps &amp;lt;= AppendIfEnabled(arr=EnabledL2Maps, cat_flag=WindowsFirewall, l2propername="FirewallUniversal")


 LET HussArgs &amp;lt;= array(bin=Binpath,
 outdir_flag="-o",
 outdir_path=outdir,
 format_flag="-f",
 format_val="jsonl"
 )
 LET HussArgs &amp;lt;= if(condition= cnt &amp;lt; cnt_max, then= HussArgs + "--includeonly" + join(array=EnabledL2Maps[1:], sep=","), else= HussArgs)
 LET HussArgs &amp;lt;= if(condition= Option_PowerShellScriptBlocksXorApply = "Y", then= HussArgs + "--scriptblockxor", else= HussArgs)
 LET HussArgs &amp;lt;= HussArgs + LogsPath

 LET _ &amp;lt;= log(message="EvtxHussar cmdline arguments: %v", args=HussArgs)

 LET ExecuteHussar = SELECT log(message="EvtxHussar stdout: %s",
 args=Stdout)
 FROM execve(cwd=CWDpath, argv=HussArgs, sep="\n")

 LET _ &amp;lt;= if(condition= cnt &amp;gt; 0, then= ExecuteHussar,
 else= log(message="As no plugins were selected, nothing to do."))


 // Helper functions for sources
 LET GetOutputFiles(category, jsonl_filename) = SELECT OSPath, Size FROM glob(globs=outdir + format(format="\\*\\%s\\%s", args=[category, jsonl_filename]))

 LET PluginOutput(search_result) = SELECT * FROM foreach(
 row= { SELECT * FROM search_result },
 query= { SELECT * FROM parse_jsonl(filename=OSPath) ORDER BY EventTime DESC}
 )

 // Antivirus_Symantec
 SELECT *, "EvtxHussar.Antivirus_Symantec" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="av", jsonl_filename="symantec_networkprotection.jsonl"))

 - name: Antivirus_WindowsDefender
 query: |
 SELECT *, "EvtxHussar.Antivirus_WindowsDefender" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="av", jsonl_filename="windows_defender.jsonl"))

 - name: Accounts_UsersRelatedOperations
 query: |
 SELECT *, "EvtxHussar.Accounts_UsersRelatedOperations" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="accounts", jsonl_filename="users_related_operations.jsonl"))

 - name: Audit_LogCleared
 query: |
 SELECT *, "EvtxHussar.Audit_LogCleared" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="audit", jsonl_filename="log_cleared.jsonl"))

 - name: Audit_PolicyChanges
 query: |
 SELECT *, "EvtxHussar.Audit_PolicyChanges" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="audit", jsonl_filename="policy_change.jsonl"))

 - name: BootupRestartShutdown
 query: |
 SELECT *, "EvtxHussar.BootupRestartShutdown" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="general", jsonl_filename="bootup_restart_shutdown.jsonl"))

 - name: Logons
 query: |
 SELECT *, "EvtxHussar.Logons" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="logons", jsonl_filename="logons.jsonl"))

 - name: Powershell_Events
 query: |
 SELECT *, "EvtxHussar.Powershell_Events" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="powershell", jsonl_filename="powershell_events.jsonl"))

 - name: Powershell_ScriptblocksSummary
 query: |
 SELECT *, "EvtxHussar.Powershell_ScriptblocksSummary" AS __Source FROM foreach(
 row= { SELECT *, if(condition= Option_PowerShellScriptBlocksXorApply = "Y", then= Name[:-4], else=Name) AS FinalName, if(condition= Option_PowerShellScriptBlocksXorApply = "Y", then = xor(string=read_file(filename=OSPath), key='Y'), else = read_file(filename=OSPath)) AS Content FROM glob(globs=outdir + "\\*\\powershell\\scriptblocks\\*") },
 query= { SELECT FinalName, upload(file=Content, accessor="data", name="C:\\evtxhussar_virtual_scriptblocks_directory\\" + FinalName).sha256 AS UploadSHA256, Size, humanize(bytes=Size) AS `Human Size`, Content[:100] AS `First 100 characters of script` FROM scope() }
 )

 - name: Processes
 query: |
 SELECT *, "EvtxHussar.Processes" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="processes", jsonl_filename="processes.jsonl"))

 - name: RDP
 query: |
 SELECT *, "EvtxHussar.RDP" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="rdp", jsonl_filename="rdp.jsonl"))

 - name: ScheduledTasks_CreationModification
 query: |
 SELECT *, "EvtxHussar.ScheduledTasks_CreationModification" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="scheduled_tasks", jsonl_filename="creation_modification.jsonl"))

 - name: ScheduledTasks_Execution
 query: |
 SELECT *, "EvtxHussar.ScheduledTasks_Execution" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="scheduled_tasks", jsonl_filename="execution.jsonl"))

 - name: Services
 query: |
 SELECT *, "EvtxHussar.Services" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="services", jsonl_filename="services.jsonl"))

 - name: SMB_ClientDestinations
 query: |
 SELECT *, "EvtxHussar.SMB_ClientDestinations" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="smb", jsonl_filename="smb_client_destinations.jsonl"))

 - name: SMB_ServerAccessAudit
 query: |
 SELECT *, "EvtxHussar.SMB_ServerAccessAudit" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="smb", jsonl_filename="smb_server_access_audit.jsonl"))

 - name: SMB_ServerModifications
 query: |
 SELECT *, "EvtxHussar.SMB_ServerModifications" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="smb", jsonl_filename="smb_server_modifications.jsonl"))

 - name: WinRM
 query: |
 SELECT *, "EvtxHussar.WinRM" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="winrm", jsonl_filename="winrm.jsonl"))

 - name: WindowsFirewall
 query: |
 SELECT *, "EvtxHussar.WindowsFirewall" AS __Source FROM PluginOutput(search_result=GetOutputFiles(category="firewall", jsonl_filename="windows_firewall.jsonl"))

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.Hayabusa</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.hayabusa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.hayabusa/</guid><description>&lt;p&gt;&lt;a href="https://github.com/Yamato-Security/hayabusa" target="_blank" &gt;Hayabusa&lt;/a&gt;
 is a
Windows event log fast forensics timeline generator and threat
hunting tool.&lt;/p&gt;
&lt;p&gt;This artifact runs Hayabusa on the endpoint against the specified
Windows event log directory, and generates and uploads a single CSV/JSONL
file for further analysis with excel, timeline explorer, elastic
stack, jq, etc.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.Hayabusa
description: |
 [Hayabusa](https://github.com/Yamato-Security/hayabusa) is a
 Windows event log fast forensics timeline generator and threat
 hunting tool.

 This artifact runs Hayabusa on the endpoint against the specified
 Windows event log directory, and generates and uploads a single CSV/JSONL
 file for further analysis with excel, timeline explorer, elastic
 stack, jq, etc.

author: Eric Capuano - @eric_capuano, Whitney Champion - @shortxstack, Zach Mathis - @yamatosecurity, Fukusuke Takahashi - @fukusuket, Julian Hill - @julianghill

tools:
 - name: Hayabusa-3.8.1
 url: https://github.com/Yamato-Security/hayabusa/releases/download/v3.8.1/hayabusa-3.8.1-win-x64-live-response.zip
 expected_hash: 51ef2aff99bb3ed4e5ebe5b07053c62719263ca7a49223bb0e0bb8785eb479a0
 version: 3.8.1

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

parameters:
 - name: EvtxDirectory
 description: "Directory of .evtx files"
 default: C:/Windows/System32/winevt/Logs
 - name: MinimalLevel
 description: "Minimum level for rules"
 default: medium
 type: choices
 choices:
 - informational
 - low
 - medium
 - high
 - critical
 - name: OutputFormat
 description: "Choose the format of the result file"
 default: csv
 type: choices
 choices:
 - csv
 - jsonl
 - name: OutputProfile
 description: "Decide how much data you want back"
 default: standard
 type: choices
 choices:
 - minimal
 - standard
 - verbose
 - all-field-info
 - all-field-info-verbose
 - super-verbose
 - timesketch-minimal
 - timesketch-verbose
 - name: OutputTimeFormat
 description: "Choose the format of timestamp"
 default: ISO-8601
 type: choices
 choices:
 - European-time
 - ISO-8601
 - RFC-2822
 - RFC-3339
 - US-military-time
 - US-time
 - UTC
 - name: Threads
 description: "Number of threads"
 type: int
 default: 4
 - name: UpdateRules
 description: "Update rules before scanning"
 type: bool
 default: Y
 - name: Sort
 description: "Sort events before saving the file"
 type: bool
 default: N
 - name: NoisyRules
 description: "Enable rules marked as noisy"
 type: bool
 default: N
 - name: EIDFilter
 description: "Scan only common Event IDs for quicker scans"
 type: bool
 default: N
 - name: OutputFilenameTemplate
 description: "Upload filename template. Supports env vars via expand() and {ext} for csv/jsonl (ex: %COMPUTERNAME%_hayabusa_results.{ext})."
 default: hayabusa_results.{ext}
 - name: TimeOffset
 description: "Scan recent events based on an offset (ex: 1y, 3M, 30d, 24h, 30m)"
 - name: TimelineStart
 description: "Start time of the event logs to load (ex: '2020-02-22 00:00:00 +09:00')"
 - name: TimelineEnd
 description: "End time of the event logs to load (ex: '2022-02-22 23:59:59 +09:00')"
 - name: ExcludeCategory
 description: "Do not load rules with specified logsource categories (ex: process_creation,pipe_created)"
 - name: ExcludeEID
 description: "Do not scan specific EIDs for faster speed (ex: 1) (ex: 1,4688)"
 - name: ExcludeStatus
 description: "Do not load rules according to status (ex: experimental) (ex: stable,test)"
 - name: ExcludeTag
 description: "Do not load rules with specific tags (ex: sysmon)"
 - name: IncludeCategory
 description: "Only load rules with specified logsource categories (ex: process_creation,pipe_created)"
 - name: IncludeEID
 description: "Scan only specified EIDs for faster speed (ex: 1) (ex: 1,4688)"
 - name: IncludeTag
 description: "Only load rules with specific tags (ex: attack.execution,attack.discovery)"

required_permissions:
 - EXECVE
 - FILESYSTEM_WRITE

sources:
 - name: Upload
 query: |
 -- Fetch the binary
 LET Toolzip &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="Hayabusa-3.8.1", IsExecutable=FALSE)

 LET TmpDir &amp;lt;= tempdir()

 -- Unzip the binary
 LET _ &amp;lt;= SELECT *
 FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)

 LET HayabusaExe &amp;lt;= TmpDir + '\\hayabusa-3.8.1-win-x64.exe'

 -- Optionally update the rules
 LET _ &amp;lt;= if(condition=UpdateRules, then={
 SELECT * FROM execve(argv=[HayabusaExe, 'update-rules'], cwd=TmpDir) })

 LET HayabusaCmd &amp;lt;= if(condition=OutputFormat = "csv", then="csv-timeline", else="json-timeline")
 LET ResultFile &amp;lt;= TmpDir + '\\hayabusa_results.' + OutputFormat

 -- Build the command line considering all options
 -- If it does not match if(condition...), it returns Null, so remove Null with filter(....regex=".+")
 LET cmdline &amp;lt;= filter(list=(
 HayabusaExe, HayabusaCmd,
 "--no-wizard", 
 "--quiet", "--no-summary",
 "--directory", EvtxDirectory, 
 "--output", ResultFile,
 "--min-level", MinimalLevel,
 "--profile", OutputProfile,
 "--" + OutputTimeFormat,
 "--threads", str(str=Threads),
 if(condition=OutputFormat = "jsonl", then="-L"),
 if(condition=Sort, then="--sort"),
 if(condition=NoisyRules, then="--enable-noisy-rules"),
 if(condition=EIDFilter, then="--eid-filter"),
 if(condition=TimeOffset, then="--time-offset"), if(condition=TimeOffset, then=TimeOffset),
 if(condition=TimelineStart, then="--timeline-start"), if(condition=TimelineStart, then=TimelineStart),
 if(condition=TimelineEnd, then="--timeline-end"), if(condition=TimelineEnd, then=TimelineEnd),
 if(condition=ExcludeCategory, then="--exclude-category"), if(condition=ExcludeCategory, then=ExcludeCategory),
 if(condition=ExcludeEID, then="--exclude-eid"), if(condition=ExcludeEID, then=ExcludeEID),
 if(condition=ExcludeStatus, then="--exclude-status"), if(condition=ExcludeStatus, then=ExcludeStatus),
 if(condition=ExcludeTag, then="--exclude-tag"), if(condition=ExcludeTag, then=ExcludeTag),
 if(condition=IncludeCategory, then="--include-category"), if(condition=IncludeCategory, then=IncludeCategory),
 if(condition=IncludeEID, then="--include-eid"), if(condition=IncludeEID, then=IncludeEID),
 if(condition=IncludeTag, then="--include-tag"), if(condition=IncludeTag, then=IncludeTag),
 ), regex=".+")

 -- Run the tool and divert messages to logs.
 LET ExecHB &amp;lt;= SELECT *
 FROM execve(argv=cmdline, cwd=TmpDir, sep="\n", length=9999999)
 WHERE log(message=Stdout)

 -- Determine the Upload Filename
 LET FinalName &amp;lt;= SELECT regex_replace(
 source=expand(path=OutputFilenameTemplate),
 re="\\{ext\\}",
 replace=OutputFormat) AS Name
 FROM scope()

 -- Upload the raw file.
 SELECT upload(file=ResultFile, name=FinalName[0].Name) AS Uploads FROM scope()

 - name: Results
 query: |
 LET CSV_RESULT = SELECT * FROM parse_csv(filename=ResultFile)
 LET JSONL_RESULT = SELECT * FROM parse_jsonl(filename=ResultFile)
 LET s = scope()
 
 SELECT *, timestamp(string=s.Timestamp || s.datetime) AS EventTime
 FROM if(condition= OutputFormat = "csv", then=CSV_RESULT, else=JSONL_RESULT)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.LogonSessions</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.logonsessions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.logonsessions/</guid><description>&lt;p&gt;This artifact searches for logon and logoff events within Security event logs identified
by Event ID 4624 and 4634. These logon/logoff events are grouped by &amp;ldquo;TargetLogonId&amp;rdquo; field
into &amp;ldquo;logon sessions&amp;rdquo;. For each of these logon sessions, start, end and duration
are derived&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.LogonSessions
description: |
 This artifact searches for logon and logoff events within Security event logs identified
 by Event ID 4624 and 4634. These logon/logoff events are grouped by "TargetLogonId" field
 into "logon sessions". For each of these logon sessions, start, end and duration
 are derived


author: "Marinus Boekelo - Northwave"

type: CLIENT

parameters:
 - name: EvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Security.evtx'
 - name: UsernameRegex
 description: "Target username Regex"
 default: .
 type: regex
 - name: UsernameWhitelist
 description: "Target username witelist Regex"
 default: '\\$$'
 type: regex
 - name: ServerRegex
 description: "Target server regex"
 default: .
 type: regex
 - name: ProcessNameRegex
 description: "Target process Regex"
 default: .
 - name: ProcessNameWhitelist
 description: "Target process whitelist Regex"
 type: regex
 - name: SearchVSS
 description: "Add VSS into query."
 type: bool
 - 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"

sources:
 - query: |

 -- firstly set timebounds for performance
 LET DateAfterTime &amp;lt;= if(condition=DateAfter,
 then=timestamp(epoch=DateAfter),
 else=timestamp(epoch="1600-01-01")
 )
 LET DateBeforeTime &amp;lt;= if(condition=DateBefore,
 then=timestamp(epoch=DateBefore),
 else=timestamp(epoch="2200-01-01")
 )

 -- expand provided glob into a list of paths on the file system (fs)
 LET fspaths &amp;lt;= SELECT FullPath
 FROM glob(globs=expand(path=EvtxGlob))

 -- function returning list of VSS paths corresponding to path
 LET vsspaths(path) = SELECT FullPath
 FROM Artifact.Windows.Search.VSS(SearchFilesGlob=path)

 -- function to search evtx files
 LET logonSearchAndGroup(PathList) =
 SELECT
 TargetLogonId,
 min(item=EventTime) as Start,
 max(item=EventTime) as End,
 max(item=System.TimeCreated.SystemTime)-min(item=System.TimeCreated.SystemTime) as Duration,
 System.Computer as SourceHost,
 enumerate(items=EventData) as EventDataList
 FROM foreach(
 row=PathList,
 query={
 SELECT
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) AS EventTime,
 EventData.TargetLogonId as TargetLogonId, EventData, System
 FROM
 parse_evtx(filename=FullPath)
 WHERE System.EventID.Value IN (4624,4634)
 AND EventData.TargetLogonId != 999
 AND EventTime &amp;lt; DateBeforeTime
 AND EventTime &amp;gt; DateAfterTime
 }
 ) GROUP BY TargetLogonId


 LET evtxsearch(PathList) =
 SELECT
 Start, End, Duration, SourceHost,
 EventDataList.SubjectUserSid AS SubjectUserSid,
 EventDataList.SubjectUserName AS SubjectUserName,
 EventDataList.SubjectDomainName AS SubjectDomainName,
 EventDataList.TargetLogonId AS TargetLogonId,
 EventDataList.TargetUserName AS TargetUserName,
 EventDataList.TargetDomainName AS TargetDomainName,
 EventDataList.TargetLogonId AS TargetLogonId,
 EventDataList.LogonType AS LogonType,
 EventDataList.LogonProcessName AS LogonProcessName,
 EventDataList.ProcessName AS ProcessName,
 EventDataList.IpAddress AS IpAddress
 FROM logonSearchAndGroup(PathList=PathList)
 WHERE TargetUserName =~ UsernameRegex
 AND NOT if(condition=UsernameWhitelist,
 then= TargetUserName =~ UsernameWhitelist,
 else= FALSE)
 AND ProcessName =~ ProcessNameRegex
 AND NOT if(condition=ProcessNameWhitelist,
 then= ProcessName =~ ProcessNameWhitelist,
 else= FALSE)
 ORDER BY Start


 -- include VSS in calculation and deduplicate with GROUP BY by file
 LET include_vss =
 SELECT * FROM foreach(
 row=fspaths,
 query={ SELECT * FROM evtxsearch(PathList={ SELECT FullPath FROM vsspaths(path=FullPath) }) }
 )

 -- exclude VSS in EvtxHunt`
 LET exclude_vss = SELECT *
 FROM evtxsearch(PathList={SELECT FullPath FROM fspaths})

 -- return rows
 SELECT * FROM if(condition=SearchVSS,
 then={ SELECT * FROM include_vss },
 else={ SELECT * FROM exclude_vss })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.MoveIt</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/moveitevtx/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/moveitevtx/</guid><description>&lt;p&gt;This Artifact enables scoping EventLogs from Progress Software&amp;rsquo;s MoveIT File
Transfer. It is designed to assist in identifying exfiltration resulting from
the exploitation of CVE-2023-34362&lt;/p&gt;
&lt;p&gt;This artifact parses EvtxHunter output and returns a set of fields in results.
An unparsed data field is availible in the hidden _RawData field.&lt;/p&gt;
&lt;p&gt;There are several parameter&amp;rsquo;s available for search leveraging regex.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EvtxGlob glob of EventLogs to target. Default to MoveIt.evtx but can be targeted.&lt;/li&gt;
&lt;li&gt;dateAfter enables search for events after this date.&lt;/li&gt;
&lt;li&gt;dateBefore enables search for events before this date.&lt;/li&gt;
&lt;li&gt;IocRegex enables regex search over the message field.&lt;/li&gt;
&lt;li&gt;IgnoreRegex enables a regex whitelist for the Message field.&lt;/li&gt;
&lt;li&gt;IdRegex enables a regex query to select specific event Ids.&lt;/li&gt;
&lt;li&gt;VSSAnalysisAge enables searching over VSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: MoveIT event logging may not be turned on by default.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.MoveIt
author: Rapid7 team - Ted Samuels, @mgreen27 &amp;amp; @scudette
description: |
 This Artifact enables scoping EventLogs from Progress Software's MoveIT File
 Transfer. It is designed to assist in identifying exfiltration resulting from
 the exploitation of CVE-2023-34362

 This artifact parses EvtxHunter output and returns a set of fields in results.
 An unparsed data field is availible in the hidden _RawData field.

 There are several parameter's available for search leveraging regex.

 - EvtxGlob glob of EventLogs to target. Default to MoveIt.evtx but can be targeted.
 - dateAfter enables search for events after this date.
 - dateBefore enables search for events before this date.
 - IocRegex enables regex search over the message field.
 - IgnoreRegex enables a regex whitelist for the Message field.
 - IdRegex enables a regex query to select specific event Ids.
 - VSSAnalysisAge enables searching over VSS.

 NOTE: MoveIT event logging may not be turned on by default.

reference:
 - https://www.rapid7.com/blog/post/2023/06/01/rapid7-observed-exploitation-of-critical-moveit-transfer-vulnerability/
 - https://www.huntress.com/blog/moveit-transfer-critical-vulnerability-rapid-respons
 - https://www.mandiant.com/resources/blog/zero-day-moveit-data-theft
 - https://nvd.nist.gov/vuln/detail/CVE-2023-34362

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

parameters:
 - name: EvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\MOVEit.evtx'
 - name: IocRegex
 type: regex
 description: "IOC Regex"
 default:
 - name: IgnoreRegex
 description: "Regex of string to witelist"
 type: regex
 - name: IdRegex
 default: .
 type: regex
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.
 - 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"

sources:
 - query: |
 LET Parse(X) = to_dict(
 item={
 SELECT split(sep=":", string=Column0)[0] AS _key,
 regex_replace(re="^\\s+|\\s+$", replace="", source=split(sep=":", string=Column0)[1]) AS _value
 FROM split_records(accessor="data", filenames=X, regex="\r\n")
 WHERE Column0 =~ "^[a-zA-Z0-9]+:"
 }) + parse_string_with_regex(regex="User '(?P&amp;lt;User&amp;gt;[^']+)'", string=X)

 SELECT EventTime,Computer,Channel,Provider,EventID,EventRecordID,
 Parse(X=split(string=EventData.Data[0],sep="\r\n\r\n")[1]) as EventData,
 split(string=EventData.Data[0],sep="\r\n\r\n")[0] as Message,
 FullPath,
 EventData.Data[0] as _RawData
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=EvtxGlob,
 IocRegex=IocRegex,
 IdRegex=IdRegex,
 WhitelistRegex=IgnoreRegex,
 DateAfter=DateAfter,
 DateBefore=DateBefore,
 VSSAnalysisAge=VSSAnalysisAge )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.RDPClientActivity</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.rdpclientactivity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.rdpclientactivity/</guid><description>&lt;p&gt;This artifact retrieves outgoing RDP session activity from the
Microsoft-Windows-TerminalServices-RDPClient event logs. It aggregates
sessions based on ActivityID and outputs hostname, timeframe and disconnect reasons.
The latter is filled using a dict that was taken from MS Docs (see references)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.RDPClientActivity
author: "Marinus Boekelo - Northwave"
description: |
 This artifact retrieves outgoing RDP session activity from the
 Microsoft-Windows-TerminalServices-RDPClient event logs. It aggregates
 sessions based on ActivityID and outputs hostname, timeframe and disconnect reasons.
 The latter is filled using a dict that was taken from MS Docs (see references)

type: CLIENT

reference:
 - https://social.technet.microsoft.com/wiki/contents/articles/37870.remote-desktop-client-troubleshooting-disconnect-codes-and-reasons.aspx

parameters:
 - name: EvtxGlob
 default: '%SystemRoot%\System32\winevt\Logs\Microsoft-Windows-TerminalServices-RDPClient%4Operational.evtx'
 - name: SearchVSS
 description: "Add VSS into query."
 type: bool
 - 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"

sources:
 - query: |

 -- Definitions of disconnect reasons (see references)
 LET DisconnectReasonLookup &amp;lt;= dict(
 `0` = "No error",
 `1` = "User-initiated client disconnect.",
 `2` = "User-initiated client logoff.",
 `3` = "Your Remote Desktop Services session has ended, possibly for one of the following reasons: The administrator has ended the session. An error occurred while the connection was being established. A network problem occurred. For help solving the problem, see Remote Desktop in Help and Support.",
 `4` = "Extended Reason: The remote session ended because the total login time limit was reached. This limit is set by the server administrator or by network policies.",
 `5` = "Extended Reason: Your Remote Desktop Services session has ended. Another user connected to the remote computer, so your connection was lost. Try connecting again, or contact your network administrator or technical support group.",
 `6` = "Extended Reason: The connection was disconnected because the remote computer is low on memory.",
 `7` = "Extended Reason: This computer can't connect to the remote computer. Try connecting again. If the problem continues, contact the owner of the remote computer or your network administrator.",
 `8` = "Extended Reason: The client could not establish a connection to the remote computer. The most likely causes for this error are: 1) Remote connections might not be enabled at the remote computer. 2) The maximum number of connections was exceeded at the remote computer. 3) A network error occurred while establishing a connection. 4) The remote computer might not support the required FIPS security level. Please lower the client side required security level Policy, or contact your network administrator for assistance.",
 `9` = "Extended Reason: The connection was denied because the user account is not authorized for remote login.",
 `256` = "Extended Reason: The remote session was disconnected because there was an internal error in the remote computer's licensing protocol.",
 `257` = "Extended Reason: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license. Please contact the server administrator.",
 `258` = "Extended Reason: The remote session was disconnected because there are no Remote Desktop client access licenses available for this computer. Please contact the server administrator.",
 `259` = "Extended Reason: The remote session was disconnected because the remote computer received an invalid licensing message from this computer.",
 `260` = "Remote Desktop can't find the computer. This might mean that it does not belong to the specified network. Verify the computer name and domain that you are trying to connect to.",
 `261` = "Extended Reason: The remote session was disconnected because the Remote Desktop client access license stored on this computer is in an invalid format.",
 `262` = "This computer can't connect to the remote computer. Your computer does not have enough virtual memory available. Close your other programs, and then try connecting again. If the problem continues, contact your network administrator or technical support.",
 `263` = "Extended Reason: The remote session was disconnected because the client prematurely ended the licensing protocol.",
 `264` = "This computer can't connect to the remote computer. The two computers couldn't connect in the amount of time allotted. Try connecting again. If the problem continues, contact your network administrator or technical support.",
 `265` = "Extended Reason: The remote session was disconnected because the local computer's client access license could not be upgraded or renewed. Please contact the server administrator.",
 `266` = "The smart card service is not running. Please start the smart card service and try again.",
 `267` = "Extended Reason: The remote session was disconnected because license store creation failed with access denied. Please run the remote desktop client with elevated privileges.",
 `516` = "Remote Desktop can't connect to the remote computer for one of these reasons: 1) Remote access to the server is not enabled 2) The remote computer is turned off 3) The remote computer is not available on the network Make sure the remote computer is turned on and connected to the network, and that remote access is enabled.",
 `522` = "A smart card reader was not detected. Please attach a smart card reader and try again.",
 `772` = "This computer can't connect to the remote computer. The connection was lost due to a network error. Try connecting again. If the problem continues, contact your network administrator or technical support.",
 `778` = "There is no card inserted in the smart card reader. Please insert your smart card and try again.",
 `1024` = "Extended Reason: Remote Desktop Connection could not find the destination computer. This can happen if the computer name is incorrect or the computer is not yet registered with RD Connection Broker. Try connecting again, or contact your network administrator.",
 `1026` = "Extended Reason: An error occurred while Remote Desktop Connection was loading the destination computer. Try connecting again, or contact your network administrator.",
 `1028` = "Extended Reason: An error occurred while Remote Desktop Connection was redirecting to the destination computer. Try connecting again, or contact your network administrator.",
 `1029` = "Extended Reason: Couldn't connect to the remote computer (there was a problem setting up the virtual machine). Try connecting again, or contact your network administrator for help.",
 `1030` = "Because of a security error, the client could not connect to the remote computer. Verify that you are logged on to the network, and then try connecting again.",
 `1031` = "Extended Reason: Windows can't find the IP address of the destination virtual machine. This can happen if the virtual machine doesn't have Hyper-V enlightenments and the name of the virtual machine doesn't match the computer name in Windows. Contact your network administrator for assistance.",
 `1032` = "The specified computer name contains invalid characters. Please verify the name and try again.",
 `1033` = "Extended Reason: Connection processing has been canceled. Try connecting again, or contact your network administrator.",
 `1034` = "An error has occurred in the smart card subsystem. Please contact your helpdesk about this error.",
 `1040` = "Extended Reason: Your computer can't connect to the remote computer because the Connection Broker couldn't validate the settings specified in your RDP file. Contact your network administrator for assistance.",
 `1041` = "Extended Reason: A timeout error occurred while Remote Desktop Connection was starting the virtual machine. Try connecting again, or contact your network administrator.",
 `1042` = "Extended Reason: A session monitoring error occurred while Remote Desktop Connection was starting the virtual machine. Try connecting again, or contact your network administrator.",
 `1796` = "This computer can't connect to the remote computer. Try connecting again. If the problem continues, contact the owner of the remote computer or your network administrator.",
 `1800` = "Your computer could not connect to another console session on the remote computer because you already have a console session in progress.",
 `2056` = "The remote computer disconnected the session because of an error in the licensing protocol. Please try connecting to the remote computer again or contact your server administrator.",
 `2308` = "Your Remote Desktop Services session has ended. The connection to the remote computer was lost, possibly due to network connectivity problems. Try connecting to the remote computer again. If the problem continues, contact your network administrator or technical support.",
 `2311` = "The connection has been terminated because an unexpected server authentication certificate was received from the remote computer. Try connecting again. If the problem continues, contact the owner of the remote computer or your network administrator.",
 `2312` = "A licensing error occurred while the client was attempting to connect (Licensing timed out). Please try connecting to the remote computer again.",
 `2567` = "The specified username does not exist. Verify the username and try logging in again. If the problem continues, contact your system administrator or technical support.",
 `2820` = "This computer can't connect to the remote computer. An error occurred that prevented the connection. Try connecting again. If the problem continues, contact the owner of the remote computer or your network administrator.",
 `2822` = "Because of an error in data encryption, this session will end. Please try connecting to the remote computer again.",
 `2823` = "The user account is currently disabled and cannot be used. For assistance, contact your system administrator or technical support.",
 `2825` = "The remote computer requires Network Level Authentication, which your computer does not support. For assistance, contact your system administrator or technical support.",
 `3079` = "A user account restriction (for example, a time-of-day restriction) is preventing you from logging on. For assistance, contact your system administrator or technical support.",
 `3080` = "The remote session was disconnected because of a decompression failure at the client side. Please try connecting to the remote computer again.",
 `3335` = "As a security precaution, the user account has been locked because there were too many logon attempts or password change attempts. Wait a while before trying again, or contact your system administrator or technical support.",
 `3337` = "The security policy of your computer requires you to type a password on the Windows Security dialog box. However, the remote computer you want to connect to cannot recognize credentials supplied using the Windows Security dialog box. For assistance, contact your system administrator or technical support.",
 `3590` = "The client can't connect because it doesn't support FIPS encryption level. Please lower the server side required security level Policy, or contact your network administrator for assistance",
 `3591` = "This user account has expired. For assistance, contact your system administrator or technical support.",
 `3592` = "Failed to reconnect to your remote session. Please try to connect again.",
 `3593` = "The remote PC doesn't support Restricted Administration mode.",
 `3847` = "This user account's password has expired. The password must change in order to logon. Please update the password or contact your system administrator or technical support.",
 `3848` = "A connection will not be made because credentials may not be sent to the remote computer. For assistance, contact your system administrator.",
 `4103` = "The system administrator has restricted the times during which you may log in. Try logging in later. If the problem continues, contact your system administrator or technical support.",
 `4104` = "The remote session was disconnected because your computer is running low on video resources. Close your other programs, and then try connecting again. If the problem continues, contact your network administrator or technical support.",
 `4339` = "Extended Reason: The remote computer does not support RemoteApp. For assistance, contact your system administrator.",
 `4359` = "The system administrator has limited the computers you can log on with. Try logging on at a different computer. If the problem continues, contact your system administrator or technical support.",
 `4498` = "Extended Reason: The remote session was disconnected because of a decryption error at the server. Please try connecting to the remote computer again.",
 `4615` = "You must change your password before logging on the first time. Please update your password or contact your system administrator or technical support.",
 `4871` = "The system administrator has restricted the types of logon (network or interactive) that you may use. For assistance, contact your system administrator or technical support.",
 `5127` = "The Kerberos sub-protocol User2User is required. For assistance, contact your system administrator or technical support.",
 `6919` = "Remote Desktop cannot connect to the remote computer because the authentication certificate received from the remote computer is expired or invalid. In some cases, this error might also be caused by a large time discrepancy between the client and server computers.",
 `7431` = "Remote Desktop cannot verify the identity of the remote computer because there is a time or date difference between your computer and the remote computer. Make sure your computer's clock is set to the correct time, and then try connecting again. If the problem occurs again, contact your network administrator or the owner of the remote computer.",
 `8711` = "Your computer can't connect to the remote computer because your smart card is locked out. Contact your network administrator about unlocking your smart card or resetting your PIN.",
 `9479` = "Could not auto-reconnect to your applications,please re-launch your applications",
 `9732` = "Client and server versions do not match. Please upgrade your client software and then try connecting again.",
 `33554433` = "Failed to reconnect to the remote program. Please restart the remote program.",
 `33554434` = "The remote computer does not support RemoteApp. For assistance, contact your system administrator.",
 `50331649` = "Your computer can't connect to the remote computer because the username or password is not valid. Type a valid user name and password.",
 `50331650` = "Your computer can't connect to the remote computer because it can't verify the certificate revocation list. Contact your network administrator for assistance.",
 `50331651` = "Your computer can't connect to the remote computer due to one of the following reasons: 1) The requested Remote Desktop Gateway server address and the server SSL certificate subject name do not match. 2) The certificate is expired or revoked. 3) The certificate root authority does not trust the certificate. Contact your network administrator for assistance.",
 `50331652` = "Your computer can't connect to the remote computer because the SSL certificate was revoked by the certification authority. Contact your network administrator for assistance.",
 `50331653` = "This computer can't verify the identity of the RD Gateway. It's not safe to connect to servers that can't be identified. Contact your network administrator for assistance.",
 `50331654` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server address requested and the certificate subject name do not match. Contact your network administrator for assistance.",
 `50331655` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server's certificate has expired or has been revoked. Contact your network administrator for assistance.",
 `50331656` = "Your computer can't connect to the remote computer because an error occurred on the remote computer that you want to connect to. Contact your network administrator for assistance.",
 `50331657` = "An error occurred while sending data to the Remote Desktop Gateway server. The server is temporarily unavailable or a network connection is down. Try again later, or contact your network administrator for assistance.",
 `50331658` = "An error occurred while receiving data from the Remote Desktop Gateway server. Either the server is temporarily unavailable or a network connection is down. Try again later, or contact your network administrator for assistance.",
 `50331659` = "Your computer can't connect to the remote computer because an alternate logon method is required. Contact your network administrator for assistance.",
 `50331660` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server address is unreachable or incorrect. Type a valid Remote Desktop Gateway server address.",
 `50331661` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server is temporarily unavailable. Try reconnecting later or contact your network administrator for assistance.",
 `50331662` = "Your computer can't connect to the remote computer because the Remote Desktop Services client component is missing or is an incorrect version. Verify that setup was completed successfully, and then try reconnecting later.",
 `50331663` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server is running low on server resources and is temporarily unavailable. Try reconnecting later or contact your network administrator for assistance.",
 `50331664` = "Your computer can't connect to the remote computer because an incorrect version of rpcrt4.dll has been detected. Verify that all components for Remote Desktop Gateway client were installed correctly.",
 `50331665` = "Your computer can't connect to the remote computer because no smart card service is installed. Install a smart card service and then try again, or contact your network administrator for assistance.",
 `50331666` = "Your computer can't stay connected to the remote computer because the smart card has been removed. Try again using a valid smart card, or contact your network administrator for assistance.",
 `50331667` = "Your computer can't connect to the remote computer because no smart card is available. Try again using a smart card.",
 `50331668` = "Your computer can't stay connected to the remote computer because the smart card has been removed. Reinsert the smart card and then try again.",
 `50331669` = "Your computer can't connect to the remote computer because the user name or password is not valid. Please type a valid user name and password.",
 `50331671` = "Your computer can't connect to the remote computer because a security package error occurred in the transport layer. Retry the connection or contact your network administrator for assistance.",
 `50331672` = "The Remote Desktop Gateway server has ended the connection. Try reconnecting later or contact your network administrator for assistance.",
 `50331673` = "The Remote Desktop Gateway server administrator has ended the connection. Try reconnecting later or contact your network administrator for assistance.",
 `50331674` = "Your computer can't connect to the remote computer due to one of the following reasons: 1) Your credentials (the combination of user name, domain, and password) were incorrect. 2) Your smart card was not recognized.",
 `50331675` = "Remote Desktop can't connect to the remote computer for one of these reasons: 1) Your user account is not listed in the RD Gateway's permission list 2) You might have specified the remote computer in NetBIOS format (for example, computer1), but the RD Gateway is expecting an FQDN or IP address format (for example, computer1.fabrikam.com or 157.60.0.1). Contact your network administrator for assistance.",
 `50331676` = "Remote Desktop can't connect to the remote computer for one of these reasons: 1) Your user account is not authorized to access the RD Gateway 2) Your computer is not authorized to access the RD Gateway 3) You are using an incompatible authentication method (for example, the RD Gateway might be expecting a smart card but you provided a password) Contact your network administrator for assistance.",
 `50331679` = "Your computer can't connect to the remote computer because your network administrator has restricted access to this RD Gateway server. Contact your network administrator for assistance.",
 `50331680` = "Your computer can't connect to the remote computer because the web proxy server requires authentication. To allow unauthenticated traffic to an RD Gateway server through your web proxy server, contact your network administrator.",
 `50331681` = "Your computer can't connect to the remote computer because your password has expired or you must change the password. Please change the password or contact your network administrator or technical support for assistance.",
 `50331682` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server reached its maximum allowed connections. Try reconnecting later or contact your network administrator for assistance.",
 `50331683` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server does not support the request. Contact your network administrator for assistance.",
 `50331684` = "Your computer can't connect to the remote computer because the client does not support one of the Remote Desktop Gateway's capabilities. Contact your network administrator for assistance.",
 `50331685` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server and this computer are incompatible. Contact your network administrator for assistance.",
 `50331686` = "Your computer can't connect to the remote computer because the credentials used are not valid. Insert a valid smart card and type a PIN or password, and then try connecting again.",
 `50331687` = "Your computer can't connect to the remote computer because your computer or device did not pass the Network Access Protection requirements set by your network administrator. Contact your network administrator for assistance.",
 `50331688` = "Your computer can't connect to the remote computer because no certificate was configured to use at the Remote Desktop Gateway server. Contact your network administrator for assistance.",
 `50331689` = "Your computer can't connect to the remote computer because the RD Gateway server that you are trying to connect to is not allowed by your computer administrator. If you are the administrator, add this Remote Desktop Gateway server name to the trusted Remote Desktop Gateway server list on your computer and then try connecting again.",
 `50331690` = "Your computer can't connect to the remote computer because your computer or device did not meet the Network Access Protection requirements set by your network administrator, for one of the following reasons: 1) The Remote Desktop Gateway server name and the server's public key certificate subject name do not match. 2) The certificate has expired or has been revoked. 3) The certificate root authority does not trust the certificate. 4) The certificate key extension does not support encryption. 5) Your computer cannot verify the certificate revocation list. Contact your network administrator for assistance.",
 `50331691` = "Your computer can't connect to the remote computer because a user name and password are required to authenticate to the Remote Desktop Gateway server instead of smart card credentials.",
 `50331692` = "Your computer can't connect to the remote computer because smart card credentials are required to authenticate to the Remote Desktop Gateway server instead of a user name and password.",
 `50331693` = "Your computer can't connect to the remote computer because no smart card reader is detected. Connect a smart card reader and then try again, or contact your network administrator for assistance.",
 `50331695` = "Your computer can't connect to the remote computer because authentication to the firewall failed due to missing firewall credentials. To resolve the issue, go to the firewall website that your network administrator recommends, and then try the connection again, or contact your network administrator for assistance.",
 `50331696` = "Your computer can't connect to the remote computer because authentication to the firewall failed due to invalid firewall credentials. To resolve the issue, go to the firewall website that your network administrator recommends, and then try the connection again, or contact your network administrator for assistance.",
 `50331698` = "Your Remote Desktop Services session ended because the remote computer didn't receive any input from you.",
 `50331699` = "The connection has been disconnected because the session timeout limit was reached.",
 `50331700` = "Your computer can't connect to the remote computer because an invalid cookie was sent to the Remote Desktop Gateway server. Contact your network administrator for assistance.",
 `50331701` = "Your computer can't connect to the remote computer because the cookie was rejected by the Remote Desktop Gateway server. Contact your network administrator for assistance.",
 `50331703` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway server is expecting an authentication method different from the one attempted. Contact your network administrator for assistance.",
 `50331704` = "The RD Gateway connection ended because periodic user authentication failed. Try reconnecting with a correct user name and password. If the reconnection fails, contact your network administrator for further assistance.",
 `50331705` = "The RD Gateway connection ended because periodic user authorization failed. Try reconnecting with a correct user name and password. If the reconnection fails, contact your network administrator for further assistance.",
 `50331707` = "Your computer can't connect to the remote computer because the Remote Desktop Gateway and the remote computer are unable to exchange policies. This could happen due to one of the following reasons: 1. The remote computer is not capable of exchanging policies with the Remote Desktop Gateway. 2. The remote computer's configuration does not permit a new connection. 3. The connection between the Remote Desktop Gateway and the remote computer ended. Contact your network administrator for assistance.",
 `50331708` = "Your computer can't connect to the remote computer, possibly because the smart card is not valid, the smart card certificate was not found in the certificate store, or the Certificate Propagation service is not running. Contact your network administrator for assistance.",
 `50331709` = "To use this program or computer, first log on to the following website",
 `50331710` = "To use this program or computer, you must first log on to an authentication website. Contact your network administrator for assistance.",
 `50331711` = "Your session has ended. To continue using the program or computer, first log on to the following website:.",
 `50331712` = "Your session has ended. To continue using the program or computer, you must first log on to an authentication website. Contact your network administrator for assistance.",
 `50331713` = "The RD Gateway connection ended because periodic user authorization failed. Your computer or device didn't pass the Network Access Protection (NAP) requirements set by your network administrator. Contact your network administrator for assistance.",
 `50331714` = "Your computer can't connect to the remote computer because the size of the cookie exceeded the supported size. Contact your network administrator for assistance.",
 `50331716` = "Your computer can't connect to the remote computer using the specified forward proxy configuration. Contact your network administrator for assistance.",
 `50331717` = "This computer cannot connect to the remote resource because you do not have permission to this resource. Contact your network administrator for assistance.",
 `50331718` = "There are currently no resources available to connect to. Retry the connection or contact your network administrator.",
 `50331719` = "An error occurred while Remote Desktop Connection was accessing this resource. Retry the connection or contact your system administrator.",
 `50331721` = "Your Remote Desktop Client needs to be updated to the newest version. Contact your system administrator for help installing the update, and then try again.",
 `50331722` = "Your network configuration doesn't allow the necessary HTTPS ports. Contact your network administrator for help allowing those ports or disabling the web proxy, and then try connecting again.",
 `50331723` = "We're setting up more resources, and it might take a few minutes. Please try again later.",
 `50331724` = "The user name you entered does not match the user name used to subscribe to your applications. If you wish to sign in as a different user please choose Sign Out from the Home menu.",
 `50331725` = "Looks like there are too many users trying out the Azure RemoteApp service at the moment. Please wait a few minutes and then try again.",
 `50331726` = "Maximum user limit has been reached. Please contact your administrator for further assistance.",
 `50331727` = "Your trial period for Azure RemoteApp has expired. Ask your admin or tech support for help.",
 `50331728` = "You no longer have access to Azure RemoteApp. Ask your admin or tech support for help."
 )

 -- firstly set timebounds for performance
 LET DateAfterTime &amp;lt;= if(condition=DateAfter,
 then=timestamp(epoch=DateAfter),
 else=timestamp(epoch="1600-01-01")
 )
 LET DateBeforeTime &amp;lt;= if(condition=DateBefore,
 then=timestamp(epoch=DateBefore),
 else=timestamp(epoch="2200-01-01")
 )
 
 -- expand provided glob into a list of paths on the file system (fs)
 LET fspaths &amp;lt;= SELECT FullPath
 FROM glob(globs=expand(path=EvtxGlob))
 
 -- function returning list of VSS paths corresponding to path
 LET vsspaths(path) = SELECT FullPath
 FROM Artifact.Windows.Search.VSS(SearchFilesGlob=path)
 
 LET retrieveRecords(PathList) =
 SELECT * 
 FROM
 foreach(
 row=PathList,
 query={
 SELECT
 System.EventRecordID as EventRecordID,
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) as EventTime,
 System.TimeCreated.SystemTime as EventTimeFloat,
 System.EventID.Value as EventID,
 System.Correlation.ActivityID as ActivityID,
 System.Computer as SourceHost,
 System.Security.UserID as SourceUserSID,
 if(condition=System.EventID.Value=1026, then=EventData.Value, else=null) as DisconnectReasonID,
 if(condition=System.EventID.Value=1026, then=get(item=DisconnectReasonLookup,member=str(str=EventData.Value),default='Unknown'), else=null) as DisconnectReason,
 if(condition=System.EventID.Value=1024, then=EventData.Value, else=null) as DestinationHost,
 if(condition=System.EventID.Value=1027, then=EventData.DomainName, else=null) as ConnectedDomain,
 if(condition=System.EventID.Value=1029, then=EventData.Data.Value, else=null) as DestinationUsernameHash
 FROM parse_evtx(filename=FullPath)
 WHERE EventID IN (1024,1026,1027,1029)
 AND EventTime &amp;lt; DateBeforeTime
 AND EventTime &amp;gt; DateAfterTime
 }
 )
 GROUP BY EventRecordID
 
 LET evtxsearch(PathList) = 
 SELECT 
 min(item=EventTime) as Start,
 max(item=EventTime) as End,
 max(item=EventTimeFloat)-min(item=EventTimeFloat) as Duration,
 SourceUserSID,
 lookupSID(sid=SourceUserSID) as SourceUser,
 SourceHost,
 { SELECT _value FROM foreach(row=enumerate(items=DestinationHost)) WHERE _value != NULL LIMIT 1 } as DestinationHost,
 { SELECT _value FROM foreach(row=enumerate(items=ConnectedDomain)) WHERE _value != NULL LIMIT 1 } as ConnectedDomain,
 { SELECT _value FROM foreach(row=enumerate(items=DestinationUsernameHash)) WHERE _value!= NULL LIMIT 1 } as DestinationUsernameHash,
 join(array=array(a1={ SELECT _value FROM foreach(row=enumerate(items=DisconnectReasonID)) WHERE _value!= NULL }), sep=' | ') as DisconnectReasonID,
 join(array=array(a1={ SELECT _value FROM foreach(row=enumerate(items=DisconnectReason)) WHERE _value!= NULL }), sep=' | ') as DisconnectReason
 FROM retrieveRecords(PathList=PathList)
 GROUP BY ActivityID

 -- include VSS in calculation and deduplicate with GROUP BY by file
 LET include_vss =
 SELECT * FROM foreach(
 row=fspaths,
 query={ SELECT * FROM evtxsearch(PathList={ SELECT FullPath FROM vsspaths(path=FullPath) }) }
 )

 -- exclude VSS in EvtxHunt`
 LET exclude_vss = SELECT *
 FROM evtxsearch(PathList={SELECT FullPath FROM fspaths})

 -- return rows
 SELECT * FROM if(condition=SearchVSS,
 then={ SELECT * FROM include_vss },
 else={ SELECT * FROM exclude_vss })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.RecordIDCheck</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/recordidcheck/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/recordidcheck/</guid><description>&lt;p&gt;This artifact will compare EventLog records and report on
abnormalities in RecordID sequence and optional time gap. The
artifact can be used for both hunting, remote or local analysis.&lt;/p&gt;
&lt;p&gt;There are several parameter&amp;rsquo;s available.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EvtxGlob glob of EventLogs to target. Default to all but can be targeted.&lt;/li&gt;
&lt;li&gt;PathRegex enables filtering on evtx path for specific log targetting.&lt;/li&gt;
&lt;li&gt;DateAfter enables search for events after this date.&lt;/li&gt;
&lt;li&gt;DateBefore enables search for events before this date.&lt;/li&gt;
&lt;li&gt;MaxTimeDifference enables flaging temporal gaps between Events. Note also potential false positives on machines turned off.&lt;/li&gt;
&lt;li&gt;SearchVSS enables searching over VSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: Please use with caution this artifact can potentially be heavy
on the endpoint. Temporal analysis is turned off by default due to
potential for false positives during machine shutdown. Sequential
false positives may also occur very occasionally.&lt;/p&gt;
&lt;p&gt;version: 0.6.1&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.RecordIDCheck
author: Matt Green - @mgreen27
description: |
 This artifact will compare EventLog records and report on
 abnormalities in RecordID sequence and optional time gap. The
 artifact can be used for both hunting, remote or local analysis.

 There are several parameter's available.
 - EvtxGlob glob of EventLogs to target. Default to all but can be targeted.
 - PathRegex enables filtering on evtx path for specific log targetting.
 - DateAfter enables search for events after this date.
 - DateBefore enables search for events before this date.
 - MaxTimeDifference enables flaging temporal gaps between Events. Note also potential false positives on machines turned off.
 - SearchVSS enables searching over VSS

 Note: Please use with caution this artifact can potentially be heavy
 on the endpoint. Temporal analysis is turned off by default due to
 potential for false positives during machine shutdown. Sequential
 false positives may also occur very occasionally.

 version: 0.6.1

parameters:
 - name: EvtxGlob
 description: Target glob to process for abnormalities.
 default: '%SystemRoot%\System32\Winevt\Logs\*.evtx'
 - name: PathRegex
 description: Event log Regex to enable filtering on path
 default: .
 - 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: MaxTimeDifference
 description: Alert on events with a gap between previous event greater than this number in seconds.
 - name: SearchVSS
 description: "Add VSS into query."
 type: bool

sources:
 - query: |
 -- time testing
 LET time_test(stamp) =
 if(condition= DateBefore AND DateAfter,
 then= stamp &amp;lt; DateBefore AND stamp &amp;gt; DateAfter,
 else=
 if(condition=DateBefore,
 then= stamp &amp;lt; DateBefore,
 else=
 if(condition= DateAfter,
 then= stamp &amp;gt; DateAfter,
 else= True
 )))

 -- create dict for previous results.
 LET EvtxPath&amp;lt;=dict(FullPath='',RecordID='',EventTime='')

 -- expand provided glob into a list of paths on the file system (fs)
 LET fspaths &amp;lt;= SELECT FullPath
 FROM glob(globs=expand(path=EvtxGlob))
 WHERE FullPath =~ PathRegex

 -- function returning list of VSS paths corresponding to path
 LET vsspaths(path) = SELECT FullPath
 FROM Artifact.Windows.Search.VSS(SearchFilesGlob=path)
 WHERE FullPath =~ PathRegex

 -- function returning IOC hits
 LET evtxsearch(PathList) = SELECT * FROM foreach(
 row=PathList,
 query={
 SELECT
 FullPath,
 System.Computer as Computer,
 System.Channel as Channel,
 EvtxPath.OLDEventTime as FirstEventTime,
 set(item=EvtxPath,field='OLDFullPath',value=EvtxPath.FullPath) as _SetOLDFullPath,
 set(item=EvtxPath,field='FullPath',value=FullPath) as _SetFullPath,
 set(item=EvtxPath,field='OLDRecordID',value=EvtxPath.RecordID) as _SetOLDRecordID,
 set(item=EvtxPath,field='RecordID',value=System.EventRecordID) as _SetRecordID,
 set(item=EvtxPath,field='OLDEventTime',value=EvtxPath.EventTime) as _SetOLDEventTime,
 set(item=EvtxPath,field='EventTime',value=timestamp(epoch=int(int=System.TimeCreated.SystemTime))) as _SetEventTime,
 EvtxPath.OLDRecordID as FirstRecordID,
 timestamp(epoch=int(int=System.TimeCreated.SystemTime)) AS SecondEventTime,
 System.EventRecordID as SecondRecordID,
 System.EventRecordID - EvtxPath.OLDRecordID as _RecordIDSequence,
 EvtxPath.OLDFullPath as _OLDFullPath
 FROM parse_evtx(filename=FullPath)
 WHERE
 time_test(stamp=SecondEventTime)
 }
 )

 -- include VSS
 LET include_vss = SELECT * FROM foreach(row=fspaths,
 query={
 SELECT *
 FROM evtxsearch(PathList={
 SELECT FullPath FROM vsspaths(path=FullPath)
 })
 --GROUP BY EventRecordID,Channel
 })

 -- exclude VSS`
 LET exclude_vss = SELECT *
 FROM evtxsearch(PathList={SELECT FullPath FROM fspaths})
 -- return rows
 SELECT *,
 SecondEventTime.Unix - FirstEventTime.Unix as SecondsGap,
 if(condition= NOT _RecordIDSequence=1,
 then= "EventRecordID not sequential",
 else= "Gap between EventRecordIDs exceeds maximum seconds.") as Description
 FROM if(condition=SearchVSS,
 then=include_vss,
 else=exclude_vss)
 WHERE _RecordIDSequence
 AND FullPath = _OLDFullPath
 AND
 ( if(condition=MaxTimeDifference,
 then= SecondsGap &amp;gt; int(int=MaxTimeDifference),
 else= False)
 OR NOT _RecordIDSequence=1 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.RemoteAccessVPN</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.remoteaccessvpn/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.remoteaccessvpn/</guid><description>&lt;p&gt;This Artifact enables scoping EventLogs from Microsoft VPN, served by
Remote Access Service server role.
It is designed to assist in identifying VPN connections on organizations that
are using Microsoft VPN service. It targets both server and client side logs.&lt;/p&gt;
&lt;p&gt;This artifact parses EvtxHunter output and returns a set of fields in results.
An unparsed data field is availible in the hidden _RawData field.&lt;/p&gt;
&lt;p&gt;There are several parameter&amp;rsquo;s available for search leveraging regex.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ClientEvtxGlob glob of VPN Client EventLogs to target. Default to Application.evtx.&lt;/li&gt;
&lt;li&gt;ServerEvtxGlob glob of VPN Server EventLogs to target. Default to System.evtx.&lt;/li&gt;
&lt;li&gt;NPSLogsGlob glob of NPS Server Text Logs to target.&lt;/li&gt;
&lt;li&gt;dateAfter enables search for events after this date.&lt;/li&gt;
&lt;li&gt;dateBefore enables search for events before this date.&lt;/li&gt;
&lt;li&gt;IocRegex enables regex search over the message field.&lt;/li&gt;
&lt;li&gt;IgnoreRegex enables a regex whitelist for the Message field.&lt;/li&gt;
&lt;li&gt;VSSAnalysisAge enables searching over VSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.RemoteAccessVPN
author: Théo Letailleur, Synacktiv
description: |
 This Artifact enables scoping EventLogs from Microsoft VPN, served by
 Remote Access Service server role.
 It is designed to assist in identifying VPN connections on organizations that
 are using Microsoft VPN service. It targets both server and client side logs.

 This artifact parses EvtxHunter output and returns a set of fields in results.
 An unparsed data field is availible in the hidden _RawData field.

 There are several parameter's available for search leveraging regex.

 - ClientEvtxGlob glob of VPN Client EventLogs to target. Default to Application.evtx.
 - ServerEvtxGlob glob of VPN Server EventLogs to target. Default to System.evtx.
 - NPSLogsGlob glob of NPS Server Text Logs to target.
 - dateAfter enables search for events after this date.
 - dateBefore enables search for events before this date.
 - IocRegex enables regex search over the message field.
 - IgnoreRegex enables a regex whitelist for the Message field.
 - VSSAnalysisAge enables searching over VSS.


reference:
 - https://www.synacktiv.com/publications/forensic-aspects-of-microsoft-remote-access-vpn.html
 - https://learn.microsoft.com/en-us/windows-server/remote/remote-access/remote-access

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

parameters:
 - name: ClientEvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
 description: "EVTX file path glob where RAS Client logs are stored"
 - name: ServerEvtxGlob
 default: '%SystemRoot%\System32\Winevt\Logs\System.evtx'
 description: "EVTX file path glob where RAS Server logs are stored"
 - name: NPSLogsGlob
 default: '%SystemRoot%\System32\LogFiles\IN*'
 - name: IocRegex
 default: .
 type: regex
 - name: IgnoreRegex
 description: "Regex of string to whitelist"
 type: regex
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.
 - 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"

sources:
 - name: VPN Server
 description: VPN Server event logs
 query: |
 LET VPNServerIdRegex = '^(20250|20253|20255|20271|20272|20274|20275)$'

 -- User
 LET extract_user(eventid, eventdata) =
 if(condition=eventid=20271,then=format(format='''%v''', args=[eventdata[1]]), else=
 if(condition=(eventid=20250 OR eventid=20253 OR eventid=20255 OR eventid=20272 OR eventid=20274),then=format(format='''%v''', args=[eventdata[2]]), else=
 if(condition=eventid=20275,then="N/A")
 ))

 -- TunnelIP
 LET extract_tunnelip(eventid, eventdata) =
 if(condition=eventid=20274,then=format(format='''%v''', args=[eventdata[4]]), else=
 if(condition=eventid=20275,then=format(format='''%v''', args=[eventdata[2]])
 ))

 -- ExternalIP
 LET extract_externalip(eventid, eventdata) =
 if(condition=eventid=20271,then=format(format='''%v''', args=[eventdata[2]]))

 SELECT EventTime,Computer,Channel,Provider,EventID,extract_user(eventid=EventID,eventdata=EventData.Data) as User, extract_tunnelip(eventid=EventID, eventdata=EventData.Data) as TunnelIP, extract_externalip(eventid=EventID, eventdata=EventData.Data) as ExternalIP, EventData.Data[1:] as ExtraInfo,Message,EventData.Data as _RawData
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=ServerEvtxGlob,
 IocRegex=IocRegex,
 IdRegex=VPNServerIdRegex,
 WhitelistRegex=IgnoreRegex,
 DateAfter=DateAfter,
 DateBefore=DateBefore,
 VSSAnalysisAge=VSSAnalysisAge )

 - name: VPN Clients
 description: VPN Client event logs
 query: |
 LET VPNClientIdRegex = '^(20220|20221|20222|20223|20224|20225|20226|20227)$'

 SELECT EventTime,Computer,Channel,Provider,EventID,EventData.Data[1] as User, EventData.Data[2:] as ExtraInfo,Message,EventData.Data as _RawData
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=ClientEvtxGlob,
 IocRegex=IocRegex,
 IdRegex=VPNClientIdRegex,
 WhitelistRegex=IgnoreRegex,
 DateAfter=DateAfter,
 DateBefore=DateBefore,
 VSSAnalysisAge=VSSAnalysisAge )

 - name: NPS Server
 description: Retrieve NPS Server logs (also available in the Microsoft VPN server)
 query: |
 SELECT * FROM foreach(
 row={
 SELECT FullPath FROM glob(globs=expand(path=NPSLogsGlob))
 },
 query={
 SELECT * from parse_csv(filename=FullPath, columns=["ComputerName","ServiceName","Record-Date","Record-Time","Packet-Type","User-Name","Fully-Qualified-Distinguished-Name","Called-Station-ID","Calling-Station-ID","Callback-Number","Framed-IP-Address","NAS-Identifier","NAS-IP-Address","NAS-Port","Client-Vendor","Client-IP-Address","Client-Friendly-Name","Event-Timestamp","Port-Limit","NAS-Port-Type","Connect-Info","Framed-Protocol","Service-Type","Authentication-Type","Policy-Name","Reason-Code","Class","Session-Timeout","Idle-Timeout","Termination-Action","EAP-Friendly-Name","Acct-Status-Type","Acct-Delay-Time","Acct-Input-Octets","Acct-Output-Octets","Acct-Session-Id","Acct-Authentic","Acct-Session-Time","Acct-Input-Packets","Acct-Output-Packets","Acct-Terminate-Cause","Acct-Multi-Ssn-ID","Acct-Link-Count","Acct-Interim-Interval","Tunnel-Type","Tunnel-Medium-Type","Tunnel-Client-Endpt","Tunnel-Server-Endpt","Acct-Tunnel-Conn","Tunnel-Pvt-Group-ID","Tunnel-Assignment-ID","Tunnel-Preference","MS-Acct-Auth-Type","MS-Acct-EAP-Type","MS-RAS-Version","MS-RAS-Vendor","MS-CHAP-Error","MS-CHAP-Domain","MS-MPPE-Encryption-Types","MS-MPPE-Encryption-Policy","Proxy-Policy-Name","Provider-Type","Provider-Name","Remote-Server-Address","MS-RAS-Client-Name","MS-RAS-Client-Version"])
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.RPCFirewall</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.rpcfirewall/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.rpcfirewall/</guid><description>&lt;p&gt;Collect RPC Firewall logs from Windows hosts&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.RPCFirewall
description: |
 Collect RPC Firewall logs from Windows hosts

reference:
 - https://github.com/zeronetworks/rpcfirewall

author: Wes Lambert - @therealwlambert
parameters:
 - name: TargetGlob
 default: '%SystemRoot%\System32\Winevt\Logs\RPCFW.evtx'
 - name: IdRegex
 default: .
 type: regex
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.

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

 query: |
 LET EventDescriptionTable &amp;lt;= SELECT * FROM parse_csv(accessor="data", filename='''
 ID,Description
 1,RPC Firewall Protection Added
 2,RPC Firewall Protection Removed
 3,RPC Server Function Called
 ''')
 SELECT EventTime,
 Computer,
 Channel,
 EventID,
 EventRecordID,
 { SELECT Description FROM EventDescriptionTable WHERE ID = EventID} AS Description,
 EventData,
 if(condition=EventID=3,
 then=dict(
 Function=EventData.Data[0],
 ProcessID=EventData.Data[1],
 ImagePath=EventData.Data[2],
 Protocol=EventData.Data[3],
 Endpoint=EventData.Data[4],
 ClientNetworkAddress=EventData.Data[5],
 InterfaceUUID=EventData.Data[6],
 OpNum=EventData.Data[7],
 SID=EventData.Data[8],
 AuthenticationLevel=EventData.Data[9],
 AuthenticationService=EventData.Data[10],
 ClientPort=EventData.Data[11],
 ServerNetworkAddress=EventData.Data[12],
 ServerPort=EventData.Data[13]),
 else=dict(
 ImagePath=EventData.Data[0],
 ProcessID=EventData.Data[1]
 )
 ) AS EventDataDetails,
 Message
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=TargetGlob,
 VSSAnalysisAge=VSSAnalysisAge,
 IdRegex=IdRegex)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.SysmonProcessEnriched.yaml</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.sysmonprocessenriched/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.sysmonprocessenriched/</guid><description>&lt;p&gt;Collects sysmon process creation events and enriches with authenticode signature, tlsh hash, and call chain. Requires Sysmon and the process tracker.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.SysmonProcessEnriched.yaml
author: Zane Gittins
description: |
 Collects sysmon process creation events and enriches with authenticode signature, tlsh hash, and call chain. Requires Sysmon and the process tracker.
reference:
 - https://signalsleuth.io/2025/08/31/sysmon_enrichment.html

type: CLIENT_EVENT

parameters:
 - name: CachePeriod
 default: 3600
 description: Cache the authenticode signature and tlsh hash of a image for this duration of seconds.
 type: int64
 - name: TLSHImageRegex
 default: "AppData|Downloads|Desktop|Public|Temp"
 description: If an image matches this regex, calculate the TLSH hash.
 type: regex

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

 query: |
 LET get_auth_cache(Image) = authenticode(filename=Image)
 
 LET get_tlsh_cache(Image) = tlsh_hash(path=Image)
 
 SELECT *, cache(period=CachePeriod,
 func=get_auth_cache(Image=EventData.Image),
 key=str(str=EventData.Hashes),
 name="auth") AS Authenticode,
 if(condition=(EventData.Image =~ TLSHImageRegex),
 then=cache(period=CachePeriod,
 func=get_tlsh_cache(Image=EventData.Image),
 key=str(str=EventData.Hashes),
 name="tlsh")) AS TLSH,
 join(array=process_tracker_callchain(id=EventData.ProcessId).Data.Name,
 sep="-&amp;gt;") AS CallChain
 FROM delay(
 query={
 SELECT *
 FROM watch_evtx(
 filename="C:\\Windows\\system32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx")
 WHERE System.EventID.Value = 1
 },
 delay=1)
resources:
 max_rows: 1000

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.WonkaVision</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.wonkavision/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.wonkavision/</guid><description>&lt;p&gt;Collect WonkaVision logs from Windows hosts.&lt;/p&gt;
&lt;p&gt;WonkaVision is a utility developed by @4ndr3w6S and @exploitph that is used to detect forged Kerberos tickets.&lt;/p&gt;
&lt;p&gt;This artifact allows users to run the utility (if desired) and collect the relevant logs from the Windows Application log.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.WonkaVision
description: |
 Collect WonkaVision logs from Windows hosts.

 WonkaVision is a utility developed by @4ndr3w6S and @exploitph that is used to detect forged Kerberos tickets.

 This artifact allows users to run the utility (if desired) and collect the relevant logs from the Windows Application log.

reference:
 - https://github.com/0xe7/WonkaVision

author: Wes Lambert - @therealwlambert
parameters:
 - name: TargetGlob
 default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
 - name: VSSAnalysisAge
 type: int
 default: 0
 description: |
 If larger than zero we analyze VSS within this many days
 ago. (e.g 7 will analyze all VSS within the last week). Note
 that when using VSS analysis we have to use the ntfs accessor
 for everything which will be much slower.
 - name: IdRegex
 default: .
 type: regex
 - name: RunWonkaVision
 type: bool
 default: F
 description: Run WonkaVision.exe

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

 query: |
 LET RunWV &amp;lt;= if(condition=RunWonkaVision, then={
 SELECT * FROM chain(a={
 SELECT * FROM Artifact.Windows.Detection.WonkaVision()
 }, b=sleep(time=10))
 })
 LET EventDescriptionTable &amp;lt;= SELECT * FROM parse_csv(accessor="data", filename='''
 ID,Description
 9988,Possible compromised session
 9989,Possible forged ticket
 ''')
 SELECT EventTime,
 Computer,
 Channel,
 Provider,
 EventID,
 EventRecordID,
 { SELECT Description FROM EventDescriptionTable WHERE ID = EventID} AS Description,
 if(condition = EventID =~ "9988",
 then=grok(data=EventData, grok='''Possible compromised session\\nTotal Score: %{DATA:total_score}\\nSession: %{DATA:session}\\nMachine Name: %{DATA:machine_name}\\nUsername: %{DATA:user}\\n\\nIOAs:\\n\\n\\tUsernameMismatch: %{DATA:username_mismatch}\\n\\n\\nIOA Reasons: %{DATA:ioa_reasons}. '''),
 else=grok(data=EventData, grok='''Possible forged ticket\\nTotal Score: %{DATA:total_score}\\nSession: %{DATA:session}\\nMachine Name: %{DATA:machine_name}\\nUser: %{DATA:user}\\nService Principal Name: %{DATA:service_principal_name}\\n\\nIOAs:%{DATA:ioa}\\n\\n\\tPasswordMustChange: %{DATA:password_must_change}\\n\\n\\nTool Scores:\\n\\tMimikatz Score: %{NUMBER:mimikatz_score}\\n\\tImpacket Score: %{NUMBER:impacket_score}\\n\\tRubeus Score: %{NUMBER:rubeus_score}\\n\\tCobalt Strike Score: %{NUMBER:cobalt_strike_score}\\n\\n\\nIOA Reasons: %{DATA:ioa_reasons}. ''',patterns=["Possible forged ticket\\nTotal Score: %{DATA:total_score}\\nSession: %{DATA:session}\\nMachine Name: %{DATA:machine_name}\\nUser: %{DATA:user}\\nService Principal Name: %{DATA:service_principal_name}\\n\\nIOAs:%{DATA:ioa}\\n\\n\\nTool Scores:\\n\\tMimikatz Score: %{NUMBER:mimikatz_score}\\n\\tImpacket Score: %{NUMBER:impacket_score}\\n\\tRubeus Score: %{NUMBER:rubeus_score}\\n\\tCobalt Strike Score: %{NUMBER:cobalt_strike_score}\\n\\n\\nIOA Reasons: %{GREEDYDATA:ioa_reasons}"])) AS EventDetails,
 EventData.Data[0] AS EventDataOriginal
 FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob=TargetGlob,
 VSSAnalysisAge=VSSAnalysisAge,
 IdRegex=IdRegex)
 WHERE Provider =~ "Wonka"

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.EventLogs.Zircolite</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.zircolite/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.eventlogs.zircolite/</guid><description>&lt;p&gt;Zircolite is a standalone tool that can be used to apply Sigma rules to EVTX files on endpoints in an effort to quickly parse large datasets and surface detections.&lt;/p&gt;
&lt;p&gt;You can read more about Zircolite below:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagga40/Zircolite" target="_blank" &gt;https://github.com/wagga40/Zircolite&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;NOTE: This artifact may take several minutes to run, depending on the size of EVTX files being analyzed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.EventLogs.Zircolite
description: |
 Zircolite is a standalone tool that can be used to apply Sigma rules to EVTX files on endpoints in an effort to quickly parse large datasets and surface detections.
 
 You can read more about Zircolite below:
 
 https://github.com/wagga40/Zircolite
 
 NOTE: This artifact may take several minutes to run, depending on the size of EVTX files being analyzed.
 
author: Wes Lambert -- @therealwlambert
tools:
 - name: Zircolite
 url: https://github.com/wagga40/Zircolite/releases/download/2.8.1/zircolite_win10.exe
parameters:
 - name: EVTXPath
 default: 'C:\Windows\System32\winevt\Logs'
 - name: Rules
 type: upload
 description: Ruleset to be used (defaults to Zircolite generic ruleset)
 default: https://raw.githubusercontent.com/wagga40/Zircolite/master/rules/rules_windows_generic.json
 - name: Mappings
 type: upload
 default: https://raw.githubusercontent.com/wagga40/Zircolite/master/config/fieldMappings.json
 description: Mappings for ruleset (defaults to Zircolite field mappings)
 
sources:
 - query: |
 LET TmpResults &amp;lt;= tempfile(remove_last=True)
 LET Results = SELECT * FROM read_file(filenames=TmpResults)
 LET Zlite &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Zircolite", IsExecutable=FALSE)
 LET RulesFile &amp;lt;= tempfile(data=Rules, remove_last=True, extension=".json")
 Let MappingsFile &amp;lt;= tempfile(data=Mappings, remove_last=True, extension=".json")
 LET ExecZlite &amp;lt;= SELECT * FROM execve(argv=[
 Zlite.FullPath[0], 
 "--evtx", EVTXPath, 
 "--ruleset", RulesFile,
 "--config", MappingsFile,
 "--noexternal",
 "--outfile", TmpResults])
 LET Data = SELECT * FROM foreach(row=Results, query={SELECT parse_json_array(data=Data) AS Content FROM scope()})
 SELECT * FROM foreach(row=Data, query={
 SELECT
 get(member="title") AS Detection,
 get(member="description") AS Description, 
 get(member="rule_level") AS Severity,
 get(member="count") AS Count,
 get(member="tags") AS Tags,
 get(member="matches") AS Matches,
 get(member="sigma") AS _Sigma
 FROM Content 
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Events.SysmonArchiveMonitor</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonarchivemonitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonarchivemonitor/</guid><description>&lt;p&gt;This artifact enables automatic management of the Sysmon archive folder.&lt;/p&gt;
&lt;p&gt;FileDelete is a super usefuil capability offered by Sysmon enabling archive
of deleted files. It is typically used to archive interesting files or to target
collection during an active engagement.&lt;/p&gt;
&lt;p&gt;Requrements: Windows.Sysinternals.SysmonArchive&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Events.SysmonArchiveMonitor
author: Matt Green - @mgreen27
description: |
 This artifact enables automatic management of the Sysmon archive folder.

 FileDelete is a super usefuil capability offered by Sysmon enabling archive
 of deleted files. It is typically used to archive interesting files or to target
 collection during an active engagement.

 Requrements: Windows.Sysinternals.SysmonArchive

reference:
 - https://github.com/trustedsec/SysmonCommunityGuide/blob/master/chapters/file-delete.md
 - https://isc.sans.edu/diary/Sysmon+and+File+Deletion/26084
 - https://blog.nviso.eu/2022/06/30/enforcing-a-sysmon-archive-quota/


type: CLIENT_EVENT

parameters:
 - name: SysmonArchiveGlob
 description: Glob to target configured Sysmon archive folder contents.
 default: C:\Sysmon\*
 - name: ArchiveSize
 description: Desired size of archive in bytes. Default is ~1GB.
 default: 1000000000
 type: int64
 - name: CheckDelay
 description: Desired time to wait between checks. Default is 10 mins (600s).
 default: 600
 type: int64


sources:
 - query: |
 LET schedule = SELECT UTC.String AS Now
 FROM clock(period=CheckDelay)

 -- on each schedule run Windows.Sysinternals.SysmonArchive
 SELECT * FROM foreach(row=schedule,
 query={
 SELECT *
 FROM Artifact.Windows.Sysinternals.SysmonArchive(
 ArchiveSize=ArchiveSize,
 SysmonArchiveGlob=SysmonArchiveGlob,
 DeleteFiles=True,
 ShowAll=False)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Events.SysmonRegistry</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonregistry/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonregistry/</guid><description>&lt;p&gt;This artifact enables monitoring for registry events of interest via the Sysmon
ETW proiver.&lt;/p&gt;
&lt;p&gt;The artifact requires Sysmon installed collecting registry events 12,13 and 14.&lt;br&gt;
It is also reccomended to run Windows.Events.TrackProcesses as this also
includes a base level Sysmon install.&lt;/p&gt;
&lt;p&gt;Monitoring is configured by a csv KeyRegex which has the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regex - a regex to select registry key events of interest.&lt;/li&gt;
&lt;li&gt;FilterRegex - a regex to filter out keys.&lt;/li&gt;
&lt;li&gt;FilterProcess - a regex to filter out Image field -
e.g &lt;code&gt;C:\\Windows\\regedit\.exe$&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Details - a description of the Detection.&lt;/li&gt;
&lt;li&gt;ATT&amp;amp;CK - a MITRE ATT&amp;amp;CK reference.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: This artifact may be impacted by your Sysmon configuration.
Generally it is more efficient to filter at the kernel level via Sysmon
configurtion.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Events.SysmonRegistry
author: Matt Green - @mgreen27
description: |
 This artifact enables monitoring for registry events of interest via the Sysmon 
 ETW proiver.
 
 The artifact requires Sysmon installed collecting registry events 12,13 and 14. 
 It is also reccomended to run Windows.Events.TrackProcesses as this also 
 includes a base level Sysmon install.
 
 Monitoring is configured by a csv KeyRegex which has the following fields: 
 * Regex - a regex to select registry key events of interest. 
 * FilterRegex - a regex to filter out keys. 
 * FilterProcess - a regex to filter out Image field - 
 e.g ```C:\\Windows\\regedit\.exe$```. 
 * Details - a description of the Detection. 
 * ATT&amp;amp;CK - a MITRE ATT&amp;amp;CK reference. 
 
 Note: This artifact may be impacted by your Sysmon configuration. 
 Generally it is more efficient to filter at the kernel level via Sysmon 
 configurtion.
 
type: CLIENT_EVENT

parameters:
 - name: KeyRegex
 type: csv
 default: |
 Regex,FilterRegex,FilterProcess,Details,ATT&amp;amp;CK
 CurrentVersion\\Run,,,"Windows: Wildcard for Run keys, including RunOnce, RunOnceEx, RunServices, RunServicesOnce [Also covers terminal server] ",T1060
 Policies\\Explorer\\Run,,,Windows: Alternate runs keys | Credit @ion-storm,T1060
 Group Policy\\Scripts,,,Windows: Group policy scripts,T1484
 Windows\\System\\Scripts,,,"Windows: Wildcard for Logon, Loggoff, Shutdown",T1484
 CurrentVersion\\Windows\\Load,,,Windows: [ https://msdn.microsoft.com/en-us/library/jj874148.aspx ],T1060
 CurrentVersion\\Windows\\Run,,,Windows: [ https://msdn.microsoft.com/en-us/library/jj874148.aspx ],T1060
 CurrentVersion\\Winlogon\\Shell,,,Windows: [ https://msdn.microsoft.com/en-us/library/ms838576(v=winembedded.5).aspx ],T1060
 CurrentVersion\\Winlogon\\System,,,Windows [ https://www.exterminate-it.com/malpedia/regvals/zlob-dns-changer/118 ],T1060
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify,,,Windows: Autorun location [ https://attack.mitre.org/wiki/Technique/T1004 ] [ https://www.cylance.com/windows-registry-persistence-part-2-the-run-keys-and-search-order ],
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell,,,Windows: [ https://technet.microsoft.com/en-us/library/ee851671.aspx ],
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit,,,Windows: Autorun location [ https://www.cylance.com/windows-registry-persistence-part-2-the-run-keys-and-search-order ],
 ^HKLM\\Software\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32,,,Windows: Legacy driver loading | Credit @ion-storm ,
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\BootExecute,,,Windows: Autorun | Credit @ion-storm | [ https://www.cylance.com/windows-registry-persistence-part-2-the-run-keys-and-search-order ],
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug,,,Windows: Automatic program crash debug program [ https://www.symantec.com/security_response/writeup.jsp?docid=2007-050712-5453-99&amp;amp;tabid=2 ],
 UserInitMprLogonScript,,,Windows: Legacy logon script environment variable [ http://www.hexacorn.com/blog/2014/11/14/beyond-good-ol-run-key-part-18/ ],
 user shell folders\\startup$,,,Monitor changes to Startup folder location for monitoring evasion | Credit @SBousseaden,T1112
 \\ServiceDll$,,,Windows: Points to a service's DLL [ https://blog.cylance.com/windows-registry-persistence-part-1-introduction-attack-phases-and-windows-services ],T1031|T1050
 \\ServiceManifest$,,,Windows: Manifest pointing to service's DLL [ https://www.geoffchappell.com/studies/windows/win32/services/svchost/index.htm ],T1031|T1050
 \\ImagePath$,,,Windows: Points to a service's EXE [ https://attack.mitre.org/wiki/Technique/T1050 ],T1031|T1050
 \\Start$,,,"Windows: Services start mode changes (Disabled, Automatically, Manual)",T1031|T1050
 Control\\Terminal Server\\WinStations\\RDP-Tcp\\PortNumber$,,,Windows: RDP port change under Control [ https://blog.menasec.net/2019/02/of-rdp-hijacking-part1-remote-desktop.html ],
 Control\\Terminal Server\\fSingleSessionPerUser$,,,"Windows: Allow same user to have mutliple RDP sessions, to hide from admin being impersonated",
 fDenyTSConnections$,,,Windows: Attacker turning on RDP,
 LastLoggedOnUser$,,,Windows: Changing last-logged in user,
 RDP-tcp\\PortNumber$,,,Windows: Changing RDP port to evade IDS,
 Services\\PortProxy\\v4tov4$,,,Windows: Changing RDP port to evade IDS,
 \\command\\,,,Windows: Sensitive sub-key under file associations and CLSID that map to launch command,T1042
 \\ddeexec\\,,,Windows: Sensitive sub-key under file associations and CLSID that map to launch command,T1122
 {86C86720-42A0-1069-A2E8-08002B30309D},,,Windows: Tooltip handler,T1122
 exefile,,,"Windows Executable handler, to log any changes not already monitored",T1042
 \\InprocServer32\\(Default)$,,,Windows:COM Object Hijacking [ https://blog.gdatasoftware.com/2014/10/23941-com-object-hijacking-the-discreet-way-of-persistence ] | Credit @ion-storm,T1122
 \\Hidden$,,,"Windows:Explorer: Some types of malware try to hide their hidden system files from the user, good signal event ",T1158
 \\ShowSuperHidden$,,,"Windows:Explorer: Some types of malware try to hide their hidden system files from the user, good signal event [ Example: https://www.symantec.com/security_response/writeup.jsp?docid=2007-061811-4341-99&amp;amp;tabid=2 ]",T1158
 \\HideFileExt$,,,Windows:Explorer: Some malware hides file extensions to make diagnosis/disinfection more daunting to novice users ,T1158
 Classes\\*\\,,,Windows:Explorer: [ http://www.silentrunners.org/launchpoints.html ] ,
 Classes\\AllFilesystemObjects\\,,,Windows:Explorer: [ http://www.silentrunners.org/launchpoints.html ] ,
 Classes\\Directory\\,,,Windows:Explorer: [ https://stackoverflow.com/questions/1323663/windows-shell-context-menu-option ],
 Classes\\Drive\\,,,Windows:Explorer: [ https://stackoverflow.com/questions/1323663/windows-shell-context-menu-option ],
 Classes\\Folder\\,,,"Windows:Explorer: ContextMenuHandlers, DragDropHandlers, CopyHookHandlers, [ https://stackoverflow.com/questions/1323663/windows-shell-context-menu-option ]",
 Classes\\PROTOCOLS\\,,,Windows:Explorer: Protocol handlers,
 ContextMenuHandlers\\,,,Windows: [ http://oalabs.openanalysis.net/2015/06/04/malware-persistence-hkey_current_user-shell-extension-handlers/ ],
 CurrentVersion\\Shell,,,"Windows: Shell Folders, ShellExecuteHooks, ShellIconOverloadIdentifers, ShellServiceObjects, ShellServiceObjectDelayLoad [ http://oalabs.openanalysis.net/2015/06/04/malware-persistence-hkey_current_user-shell-extension-handlers/ ]",
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\ShellExecuteHooks,,,Windows: ShellExecuteHooks,
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\ShellServiceObjectDelayLoad,,,Windows: ShellExecuteHooks,
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\ShellIconOverlayIdentifiers,,,Windows: ShellExecuteHooks,
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\,,,Windows: Credit to @Hexacorn [ http://www.hexacorn.com/blog/2013/01/19/beyond-good-ol-run-key-part-3/ ],
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\InitialProgram,,,Windows:RDP: Note other Terminal Server run keys are handled by another wildcard already,
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\,,,Windows: Group Policy internally uses a plug-in architecture that nothing should be modifying,T1484
 ^HKLM\\SYSTEM\\CurrentControlSet\\Services\\WinSock,,,"Windows: Wildcard, includes Winsock and Winsock2",
 \\ProxyServer$,,,Windows: System and user proxy server,
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider,,,"Wildcard, includes Credential Providers and Credential Provider Filters",
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\,,,[ https://attack.mitre.org/wiki/Technique/T1131 ] [ https://attack.mitre.org/wiki/Technique/T1101 ],T1101
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\SecurityProviders,,,Windows: Changes to WDigest-UseLogonCredential for password scraping [ https://www.trustedsec.com/april-2015/dumping-wdigest-creds-with-meterpreter-mimikatzkiwi-in-windows-8-1/ ],
 ^HKLM\\Software\\Microsoft\\Netsh,,,Windows: Netsh helper DLL [ https://attack.mitre.org/wiki/Technique/T1128 ],
 Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ProxyEnable,,,Windows: Malware often disables a web proxy for 2nd stage downloads,
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order\\,,,Windows: Order of network providers that are checked to connect to destination [ https://www.malwarearchaeology.com/cheat-sheets ] ,
 \\EnableFirewall$,,,"Windows: Monitor for firewall disablement, all firewall profiles [ https://attack.mitre.org/wiki/Technique/T1089 ]",T1089
 \\DoNotAllowExceptions$,,,"Windows: Monitor for firewall disablement, all firewall profiles [ https://attack.mitre.org/wiki/Technique/T1089 ]",T1089
 ^HKLM\\SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\StandardProfile\\AuthorizedApplications\\List,,,Windows Firewall authorized applications for all networks| Credit @ion-storm ,
 ^HKLM\\SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\DomainProfile\\AuthorizedApplications\\List,,,Windows Firewall authorized applications for domain networks ,
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Appinit_Dlls\\,,,Windows: Feature disabled by default [ https://attack.mitre.org/wiki/Technique/T1103 ],T1103
 ^HKLM\\Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Appinit_Dlls\\,,,Windows: Feature disabled by default [ https://attack.mitre.org/wiki/Technique/T1103 ],T1103
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls\\,,,Windows: Credit to @Hexacorn [ http://www.hexacorn.com/blog/2013/01/19/beyond-good-ol-run-key-part-3/ ] [ https://blog.comodo.com/malware/trojware-win32-trojanspy-volisk-a/ ],
 Microsoft\\Office\\Outlook\\Addins\\,,,"Microsoft:Office: Outlook add-ins, access to sensitive data and often cause issues",T1137
 Office Test\\,,,Microsoft:Office: Persistence method [ http://www.hexacorn.com/blog/2014/04/16/beyond-good-ol-run-key-part-10/ ] | Credit @Hexacorn,T1137
 Security\\Trusted Documents\\TrustRecords,,,"Microsoft:Office: Monitor when ""Enable editing"" or ""Enable macros"" is used | Credit @OutflankNL | [ https://outflank.nl/blog/2018/01/16/hunting-for-evil-detect-macros-being-executed/ ]",
 Internet Explorer\\Toolbar\\,,,Microsoft:InternetExplorer: Machine and user [ Example: https://www.exterminate-it.com/malpedia/remove-mywebsearch ] ,T1176
 Internet Explorer\\Extensions\\,,,Microsoft:InternetExplorer: Machine and user [ Example: https://www.exterminate-it.com/malpedia/remove-mywebsearch ] ,T1176
 Browser Helper Objects\\,,,Microsoft:InternetExplorer: Machine and user [ https://msdn.microsoft.com/en-us/library/bb250436(v=vs.85).aspx ],T1176
 ^HKLM\\Software\\Classes\\CLSID\\{AB8902B4-09CA-4BB6-B78D-A8F59079A8D5}\\,,,Windows: Thumbnail cache autostart [ http://blog.trendmicro.com/trendlabs-security-intelligence/poweliks-levels-up-with-new-autostart-mechanism/ ] ,
 ^HKLM\\Software\\Classes\\WOW6432Node\\CLSID\\{AB8902B4-09CA-4BB6-B78D-A8F59079A8D5}\\,,,Windows: Thumbnail cache autostart [ http://blog.trendmicro.com/trendlabs-security-intelligence/poweliks-levels-up-with-new-autostart-mechanism/ ] ,
 ^HKLM\\Software\\Classes\\CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\,,,Windows: DirectX instances,
 ^HKLM\\Software\\Classes\\WOW6432Node\\CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\,,,Windows: DirectX instances,
 \\UrlUpdateInfo$,,,Microsoft:ClickOnce: Source URL is stored in this value [ https://subt0x10.blogspot.com/2016/12/mimikatz-delivery-via-clickonce-with.html ],
 \\InstallSource$,,,Windows: Source folder for certain program and component installations,
 \\EulaAccepted$,,,Sysinternals tool launched. Lots of useful abilities for attackers ,
 \\DisableAntiSpyware$,,,Windows:Defender: State modified via registry,T1089|Tamper-Defender
 \\DisableAntiVirus$,,,Windows:Defender: State modified via registry,T1089|Tamper-Defender
 \\SpynetReporting$,,,Windows:Defender: State modified via registry,T1089|Tamper-Defender
 DisableRealtimeMonitoring$,,,Windows:Defender: State modified via registry,T1089|Tamper-Defender
 \\SubmitSamplesConsent$,,,Windows:Defender: State modified via registry,T1089|Tamper-Defender
 HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA$,,,Detect: UAC Tampering | Credit @ion-storm ,T1088
 HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\LocalAccountTokenFilterPolicy$,,,Detect: UAC Tampering | Credit @ion-storm ,T1088
 HKLM\\Software\\Microsoft\\Security Center\\$,,,[ https://attack.mitre.org/wiki/Technique/T1089 ],T1089|Tamper-SecCenter
 SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\HideSCAHealth$,,,Windows:Security Center: Malware sometimes disables [ https://blog.avast.com/2013/08/12/your-documents-are-corrupted-from-image-to-an-information-stealing-trojan/ ],T1089|Tamper-SecCenter
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom,,,Windows: AppCompat [ https://www.fireeye.com/blog/threat-research/2017/05/fin7-shim-databases-persistence.html ],T1138
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\InstalledSDB,,,Windows: AppCompat [ https://attack.mitre.org/wiki/Technique/T1138 ],T1138
 VirtualStore,,,"Windows: Registry virtualization, something's wrong if it's in use [ https://msdn.microsoft.com/en-us/library/windows/desktop/aa965884(v=vs.85).aspx ]",
 ^HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\,,,"Windows: Malware likes changing IFEO, like adding Debugger to disable antivirus EXE",T1183
 ^HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\,,,Windows: Event log system integrity and ACLs,
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Safeboot\\,,,Windows: Services approved to load in safe mode. Almost nothing should ever modify this.,Tamper-Safemode
 ^HKLM\\SYSTEM\\CurrentControlSet\\Control\\Winlogon\\,,,Windows: Providers notified by WinLogon,Tamper-Winlogon
 ^HKLM\\Software\\Microsoft\\Tracing\\RASAPI32,,,Windows: Malware sometimes disables tracing to obfuscate tracks,Tamper-Tracing
 \\{CAFEEFAC-,,,Java Registry,
 

sources:
 - query: |
 -- firstly generate initial regex to apply to events
 LET target_entries = join(array=KeyRegex.Regex,sep='|')
 
 -- Monitor ETW provider and extract target key event by regex
 LET hits = SELECT 
 EventData.UtcTime as EventTime,
 System.ID as EventId,
 EventData.EventType as EventType,
 EventData.TargetObject as TargetObject,
 EventData.Details as Value,
 dict(Image=EventData.Image,User=EventData.User,ProcessId=EventData.ProcessId,ProcessGuid=EventData.ProcessGuid) as ProcessInfo,
 EventData.Image as _Image
 FROM watch_etw(guid="{5770385f-c22a-43e0-bf4c-06f5698ffbd9}")
 WHERE System.ID in ( 12, 13, 14 )
 AND TargetObject =~ target_entries

 -- apply additional filters and add context.
 SELECT *, process_tracker_callchain(id=ProcessInfo.ProcessId).Data as ProcessChain
 FROM foreach(row=hits, query={
 SELECT EventTime,EventId,EventType,TargetObject,Value,ProcessInfo,
 dict(Regex=Regex,FilterRegex=FilterRegex,FilterProcess=FilterProcess,Details=Details,`ATT&amp;amp;CK`=`ATT&amp;amp;CK`) as Detection
 FROM KeyRegex
 WHERE TargetObject =~ Regex
 AND NOT if(condition= FilterProcess,
 then= _Image =~ FilterProcess,
 else= False)
 AND NOT if(condition= FilterRegex,
 then= TargetObject =~ FilterRegex,
 else= False)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Events.TrackProcesses.UseExistingSysmonOnly</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.events.trackprocesses.useexistingsysmononly/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.events.trackprocesses.useexistingsysmononly/</guid><description>&lt;p&gt;&lt;strong&gt;This is a modified version of Windows.Events.TrackProcesses for servers
that do not use the Inventory service. It assumes that Sysmon
is already installed and running. The option to forward updates to the server
is also removed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This artifact uses sysmon and pslist to keep track of running
processes using the Velociraptor process tracker.&lt;/p&gt;
&lt;p&gt;The Process Tracker keeps track of exited processes, and resolves
process callchains from it in memory cache.&lt;/p&gt;
&lt;p&gt;This event artifact enables the global process tracker and makes it
possible to run many other artifacts that depend on the process
tracker.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Events.TrackProcesses.UseExistingSysmonOnly
description: |
 **This is a modified version of Windows.Events.TrackProcesses for servers
 that do not use the Inventory service. It assumes that Sysmon
 is already installed and running. The option to forward updates to the server
 is also removed.**
 
 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

parameters:
 - name: MaxSize
 type: int64
 description: Maximum size of the in memory process cache (default 10k)

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

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

 query: |
 LET UpdateQuery =
 SELECT * FROM foreach(row={
 SELECT *,
 get(member='EventData') AS EventData
 FROM watch_etw(guid='{5770385f-c22a-43e0-bf4c-06f5698ffbd9}')
 }, 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&amp;lt;SHA256&amp;gt;[^,]+)",
 "MD5=(?P&amp;lt;MD5&amp;gt;[^,]+)",
 "IMPHASH=(?P&amp;lt;IMPHASH&amp;gt;[^,]+)"],
 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 &amp;lt;= process_tracker(
 enrichments=if(condition=AddEnrichments, then=[
 '''x=&amp;gt;if(
 condition=NOT x.Data.VersionInformation AND x.Data.Image,
 then=dict(VersionInformation=parse_pe(file=x.Data.Image).VersionInformation))
 ''',
 '''x=&amp;gt;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"

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.AdvancedPortScanner</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.advancedportscanner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.advancedportscanner/</guid><description>&lt;p&gt;This Velociraptor artifact is tailored for forensics analysis of Angry IP Scanner usage on Windows platforms. This facilitates the identification of how Angry IP Scanner was configured and used, aiding in DFIR investigations. It examines registry keys HKEY_USERS\&lt;em&gt;\SOFTWARE\Famatech\advanced_port_scanner and HKEY_USERS\&lt;/em&gt;\SOFTWARE\Famatech\advanced_port_scanner\State for retrieve some informations about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run: Displays the version of Advanced Port Scanner&lt;/li&gt;
&lt;li&gt;locale_timestamp: Indicates the time in EPOCH (UTC +0) at which the application was first launched&lt;/li&gt;
&lt;li&gt;locale: Displays the language chosen for the graphical interface, may prove useful to have an idea of the native language of a threat actor (it is necessary to correlate with a modus operandi in order not to fall into the trap of a false flag)&lt;/li&gt;
&lt;li&gt;LastPortsUsed: Displays the last ports used in the last scan&lt;/li&gt;
&lt;li&gt;LastRangeUsed: Displays the last IP range used in the last scan&lt;/li&gt;
&lt;li&gt;IpRangesMruList: Displays all the IP ranges scanned by the tool, the first digit of each prefix in this list indicates the frequency of scans for each range&lt;/li&gt;
&lt;li&gt;PortsMruList: Displays all the ports that have been scanned by the tool, the first digit of each prefix in this list indicates the frequency of scans for each port&lt;/li&gt;
&lt;li&gt;SearchMruList: Displays all the IP addresses or hostnames that have been searched using the GUI&amp;rsquo;s &amp;ldquo;search&amp;rdquo; feature&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.AdvancedPortScanner

description: |
 This Velociraptor artifact is tailored for forensics analysis of Angry IP Scanner usage on Windows platforms. This facilitates the identification of how Angry IP Scanner was configured and used, aiding in DFIR investigations. It examines registry keys HKEY_USERS\\*\\SOFTWARE\\Famatech\\advanced_port_scanner and HKEY_USERS\\*\\SOFTWARE\\Famatech\\advanced_port_scanner\\State for retrieve some informations about:
 
 - run: Displays the version of Advanced Port Scanner
 - locale_timestamp: Indicates the time in EPOCH (UTC +0) at which the application was first launched
 - locale: Displays the language chosen for the graphical interface, may prove useful to have an idea of the native language of a threat actor (it is necessary to correlate with a modus operandi in order not to fall into the trap of a false flag)
 - LastPortsUsed: Displays the last ports used in the last scan
 - LastRangeUsed: Displays the last IP range used in the last scan
 - IpRangesMruList: Displays all the IP ranges scanned by the tool, the first digit of each prefix in this list indicates the frequency of scans for each range
 - PortsMruList: Displays all the ports that have been scanned by the tool, the first digit of each prefix in this list indicates the frequency of scans for each port
 - SearchMruList: Displays all the IP addresses or hostnames that have been searched using the GUI's "search" feature

author: Julien Houry - @y0sh1mitsu (CSIRT Airbus Protect)

reference:
 
 - https://www.protect.airbus.com/blog/uncovering-cyber-intruders-a-forensic-deep-dive-into-netscan-angry-ip-scanner-and-advanced-port-scanner/
 - https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-136a
 - https://thedfirreport.com/2021/01/18/all-that-for-a-coinminer/

type: CLIENT

parameters:
 - name: RegistryPath_APS
 default: HKEY_USERS\\*\\SOFTWARE\\Famatech\\advanced_port_scanner
 type: hidden
 - name: RegistryPath_State
 default: HKEY_USERS\\*\\SOFTWARE\\Famatech\\advanced_port_scanner\\State
 type: hidden
 - name: RegistryData
 type: regex
 default: .

sources:

- name: AdvancedPortScanner
 query: | 
 SELECT Key.FileInfo.FullPath AS FullPath, Key.FileInfo.ModTime AS ModificationTime, run, locale, locale_timestamp
 FROM read_reg_key(globs=RegistryPath_APS, accessor="registry") WHERE Key.FileInfo.FullPath =~ RegistryData
 
- name: State
 query: |
 SELECT Key.FileInfo.FullPath AS FullPath, Key.FileInfo.ModTime AS ModificationTime, LastPortsUsed, LastRangeUsed, IpRangesMruList, PortsMruList, SearchMruList
 FROM read_reg_key(globs=RegistryPath_State, accessor="registry") WHERE Key.FileInfo.FullPath =~ RegistryData

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.AngryIPScanner</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.angryipscanner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.angryipscanner/</guid><description>&lt;p&gt;This Velociraptor artifact is tailored for forensic analysis of Angry IP Scanner usage on Windows platforms. This facilitates the identification of how Angry IP Scanner was configured and used, aiding in DFIR investigations. It examines HKEY_USERS\*\SOFTWARE\JavaSoft\Prefs\ipscan from the registry for retrieve some informations about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;language: Displays the language used in the GUI, may prove useful to have an idea of the language used by a threat actor (it is necessary to correlate with a modus operandi in order not to fall into the trap of a false flag)&lt;/li&gt;
&lt;li&gt;Version: Displays the version of Angry IP Scanner&lt;/li&gt;
&lt;li&gt;LastVersionCheck: Captures the last time (EPOCH format in UTC +0) when the application checked for an update&lt;/li&gt;
&lt;li&gt;PortScanConfiguration: Displays the selected ports for scanning&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.AngryIPScanner

description: |
 This Velociraptor artifact is tailored for forensic analysis of Angry IP Scanner usage on Windows platforms. This facilitates the identification of how Angry IP Scanner was configured and used, aiding in DFIR investigations. It examines HKEY_USERS\\*\\SOFTWARE\\JavaSoft\\Prefs\\ipscan from the registry for retrieve some informations about:
 
 - language: Displays the language used in the GUI, may prove useful to have an idea of the language used by a threat actor (it is necessary to correlate with a modus operandi in order not to fall into the trap of a false flag)
 - Version: Displays the version of Angry IP Scanner
 - LastVersionCheck: Captures the last time (EPOCH format in UTC +0) when the application checked for an update
 - PortScanConfiguration: Displays the selected ports for scanning


author: Julien Houry - @y0sh1mitsu (CSIRT Airbus Protect)

reference:

 - https://www.protect.airbus.com/blog/uncovering-cyber-intruders-a-forensic-deep-dive-into-netscan-angry-ip-scanner-and-advanced-port-scanner/
 - https://www.cisa.gov/news-events/cybersecurity-advisories/aa20-259a
 - https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-060a

type: CLIENT

precondition: SELECT OS FROM info() where OS = 'windows'

parameters:
 - name: RegistryPath
 type: hidden
 default: HKEY_USERS\\*\\SOFTWARE\\JavaSoft\\Prefs\\ipscan
 - name: RegistryData
 type: regex
 default: .

sources:
 - query: |
 SELECT Key.FileInfo.FullPath AS FullPath, Key.FileInfo.ModTime AS ModificationTime, language, get(field="last/Run/Version", default="Unknown") AS Version, get(field="port/String", default="Unknown") AS PortScanConfiguration, get(field="last/Version/Check", default="Unknown") AS LastVersionCheck FROM read_reg_key(globs=RegistryPath, accessor="registry") WHERE Key.FileInfo.FullPath =~ RegistryData

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.Clipboard</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.clipboard/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.clipboard/</guid><description>&lt;p&gt;This artifact will show the Clipboard activity.&lt;/p&gt;
&lt;p&gt;The artefact ActivitiesCache.db has started to log clipboard activity since Windows 10 version 1803.&lt;/p&gt;
&lt;p&gt;The prerequisite for clipboard data to be logged by this artefact relies on the system having two settings checked:
Clipboard history enabled
Clipboard sync across devices&lt;/p&gt;
&lt;p&gt;StartTime (epoch time) – When the data was first copied to the clipboard&lt;/p&gt;
&lt;p&gt;ExpirationTime (epoch time) – When the data will be deleted from the ActivitiesCache.db (roughly 12 hours)&lt;/p&gt;
&lt;p&gt;ClipboardPayload – Base64 encoded string of the clipboard contents, but here it is decoded, and the clipboard content is shown&lt;/p&gt;
&lt;p&gt;Payload – This field tells you where the clipboard data was copied from!&lt;/p&gt;
&lt;p&gt;ActivityType – Type 10 means data resides in clipboard, Type 16 shows if data was copied or pasted&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.Clipboard
author: Hisham Adwan with the help of Velo Community
description: |
 This artifact will show the Clipboard activity.
 
 The artefact ActivitiesCache.db has started to log clipboard activity since Windows 10 version 1803.
 
 The prerequisite for clipboard data to be logged by this artefact relies on the system having two settings checked:
 Clipboard history enabled 
 Clipboard sync across devices 

 StartTime (epoch time) – When the data was first copied to the clipboard 

 ExpirationTime (epoch time) – When the data will be deleted from the ActivitiesCache.db (roughly 12 hours) 

 ClipboardPayload – Base64 encoded string of the clipboard contents, but here it is decoded, and the clipboard content is shown 

 Payload – This field tells you where the clipboard data was copied from! 

 ActivityType – Type 10 means data resides in clipboard, Type 16 shows if data was copied or pasted

reference:
 - https://www.youtube.com/watch?v=6Q3vEO69AkQ&amp;amp;ab_channel=JohnHammond
 - https://www.inversecos.com/2022/05/how-to-perform-clipboard-forensics.html
 
parameters:
 - name: FileGlob
 default: C:\Users\*\AppData\Local\ConnectedDevicesPlatform\*\ActivitiesCache.db

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

 query: |
 SELECT
 CreatedTime,
 LastModifiedTime,
 LastModifiedOnClient,
 StartTime,
 EndTime,
 Payload,
 split(sep='''\\''', string=dirname(path=OSPath))[2] AS User,
 base64decode(string=parse_json_array(data=ClipboardPayload)[0].content) AS ClipboardPayload,
 OSPath AS Path,
 Mtime
 FROM foreach(row={
 SELECT Mtime, OSPath from glob(globs=FileGlob)}, query={
 SELECT *, Mtime, OSPath FROM sqlite(file=OSPath, query="SELECT * FROM ActivityOperation")})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.FileZilla</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/filezilla/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/filezilla/</guid><description>&lt;p&gt;This artifact enumerate&amp;rsquo;s all user directories on a system and will
parse three files within a users AppData\Roaming\FileZilla
directory: filezilla.xml, recentservers.xml, and queue.sqlite3&lt;/p&gt;
&lt;p&gt;The three files provide valuable data to incident responders if data was
exfiltrated using FileZilla.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;filezilla.xml - contains saved user settings&lt;/li&gt;
&lt;li&gt;recentservers.xml - contains recently accessed servers&lt;/li&gt;
&lt;li&gt;queue.sqlite3 - contains multiple tables that can be used to identify what
files were exfiltrated and to where (remote hostname and file path).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the sqlite() plugin, VR will parse user&amp;rsquo;s queue.sqlite3 file and
join data from various tables.&lt;/p&gt;
&lt;p&gt;You can read more about filezilla.xml and recentservers.xml forensic
artifacts here:
&lt;a href="https://www.hecfblog.com/2013/09/daily-blog-93-filezilla-artifacts.html" target="_blank" &gt;https://www.hecfblog.com/2013/09/daily-blog-93-filezilla-artifacts.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The queue.sqlite3 does not have much documentation out there that I could
find. However, it is a sqlite database that contains 5 tables: files,
local_paths, remote_paths, servers, and sqlite_sequence that provide
valuable information to incident responders and shed light on what data
was exfiltrated by a threat actor.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.FileZilla
description: |
 This artifact enumerate's all user directories on a system and will
 parse three files within a users AppData\Roaming\FileZilla
 directory: filezilla.xml, recentservers.xml, and queue.sqlite3
 
 The three files provide valuable data to incident responders if data was
 exfiltrated using FileZilla.
 
 - filezilla.xml - contains saved user settings
 - recentservers.xml - contains recently accessed servers
 - queue.sqlite3 - contains multiple tables that can be used to identify what
 files were exfiltrated and to where (remote hostname and file path).
 
 Using the sqlite() plugin, VR will parse user's queue.sqlite3 file and
 join data from various tables.
 
 You can read more about filezilla.xml and recentservers.xml forensic
 artifacts here: 
 https://www.hecfblog.com/2013/09/daily-blog-93-filezilla-artifacts.html
 
 The queue.sqlite3 does not have much documentation out there that I could
 find. However, it is a sqlite database that contains 5 tables: files,
 local_paths, remote_paths, servers, and sqlite_sequence that provide 
 valuable information to incident responders and shed light on what data
 was exfiltrated by a threat actor.
 
author: "Dan Kelly - @dan_kelly17"

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: FileZillaGlob
 default: \AppData\Roaming\FileZilla\
 
 - name: queueSQLQuery
 default: |
 SELECT local_paths.path AS PATH, files.source_file AS File, servers.host FROM files JOIN local_paths ON local_paths.id = files.local_path JOIN servers ON servers.id = files.server
 
 - name: userRegex
 default: .
 type: regex

precondition: 
 SELECT OS FROM info() WHERE OS = 'windows'

sources:
 - name: FileZilla
 query: |
 -- get the filezilla.xml file
 LET filezilla_xml = SELECT * from foreach(
 row={
 SELECT Uid, Name AS User,
 expand(path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name =~ userRegex
 },
 query={
 SELECT 
 User, 
 OSPath, 
 parse_xml(file=OSPath).FileZilla3.Settings.Setting.Tabs.Tab as Tab,
 Mtime
 FROM glob(globs=FileZillaGlob + 'filezilla.xml', root=HomeDirectory)
 })
 
 SELECT * FROM foreach(row=filezilla_xml,
 query={
 SELECT 
 *, 
 OSPath AS SourceFilePath
 FROM foreach(row=Tab, query={
 SELECT * FROM _value
 })
 })

 - name: RecentServers
 query: |
 LET recentservers_xml = SELECT * from foreach(
 row={
 SELECT Uid, Name AS User,
 expand(path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name =~ userRegex
 },
 query={
 SELECT 
 User, 
 OSPath, 
 parse_xml(file=OSPath).FileZilla3.RecentServers.Server as Server,
 Mtime
 FROM glob(globs=FileZillaGlob + 'recentservers.xml', root=HomeDirectory)
 })
 
 SELECT * FROM foreach(row=recentservers_xml,
 query={
 SELECT 
 *,
 OSPath AS SourceFilePath
 FROM foreach(row=Server, query={
 SELECT * FROM _value
 })
 })
 
 - name: Queue_SQLITE3
 query: |
 LET queue_sqlite = SELECT * from foreach(
 row={
 SELECT Uid, Name AS User,
 expand(path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name =~ userRegex
 },
 query={
 SELECT 
 User, 
 OSPath, 
 Mtime
 FROM glob(globs=FileZillaGlob + 'queue.sqlite3', root=HomeDirectory)
 })
 
 SELECT * FROM foreach(row=queue_sqlite,
 query={
 SELECT 
 *,
 OSPath as SourceFilePath
 FROM sqlite(file=OSPath, query=queueSQLQuery)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.Jumplists_JLECmd</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.jumplists_jlecmd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.jumplists_jlecmd/</guid><description>&lt;ul&gt;
&lt;li&gt;Execute Eric Zimmerman&amp;rsquo;s JLECmd to parse AUTOMATICDESTINATIONS-MS and CUSTOMDESTINATIONS-MS files in C:\ drive recursively and return output for analysis. (jlecmd.exe -d C:/ &amp;ndash;csvf -csv tmpdir results.csv).&lt;/li&gt;
&lt;li&gt;JLECmd.zip is downloaded from the URL to &amp;lsquo;C:\Program Files\Velociraptor\Tools&amp;rsquo; folder.&lt;/li&gt;
&lt;li&gt;JLECmd.zip can be uploaded to Velociraptor Server in order to copy it to the clients in case there is no internet connection.&lt;/li&gt;
&lt;li&gt;Created using @carlos_cajigas LECmd VQL as a quide.&lt;/li&gt;
&lt;li&gt;JLECmd is a CLI tool for analyzing Custom Destinations jump list data. Learn more - &lt;a href="https://github.com/EricZimmerman/JLECmd" target="_blank" &gt;https://github.com/EricZimmerman/JLECmd&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.Jumplists_JLECmd
description: |
 * Execute Eric Zimmerman's JLECmd to parse AUTOMATICDESTINATIONS-MS and CUSTOMDESTINATIONS-MS files in C:\ drive recursively and return output for analysis. (jlecmd.exe -d C:/ --csvf -csv tmpdir results.csv).
 * JLECmd.zip is downloaded from the URL to 'C:\Program Files\Velociraptor\Tools' folder.
 * JLECmd.zip can be uploaded to Velociraptor Server in order to copy it to the clients in case there is no internet connection.
 * Created using @carlos_cajigas LECmd VQL as a quide.
 * JLECmd is a CLI tool for analyzing Custom Destinations jump list data. Learn more - https://github.com/EricZimmerman/JLECmd

author: Orhan Emre @orhan_emre. Modified by Zach K. https://www.linkedin.com/in/zach-kal on 2026-02-11 to address 404-url and update JLE ver to 1.5.1.

type: CLIENT

tools:
 - name: JLECmd
 url: https://download.ericzimmermanstools.com/JLECmd.zip
 version: 1.5.1


parameters:
 - name: sourceFile
 default: .
 type: regex
 description: "RegEx pattern for the name or path of the Automatic and Custom Destinations jump list files. Example 'recent' folder"
 - name: localPath
 default: .
 type: regex
 description: "RegEx pattern for the name or path of the target of the Automatic and Custom Destinations jump list files. Example 'powershell_ise.exe'"
 - name: arguments
 default: .
 type: regex
 description: "Arguments of the Automatic and Custom Destinations jump list files. Example '/c powershell Invoke-Command'"
 - name: dateAfter
 description: "search for Automatic and Custom Destinations jump list files with a SourceCreated after this date. YYYY-MM-DD"
 - name: dateBefore
 description: "search for Automatic and Custom Destinations jump list files with a SourceCreated before this date. YYYY-MM-DD"

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

sources:
 - query: |
 -- get context on target binary
 LET jlecmdpackage &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="JLECmd", IsExecutable=FALSE)

 -- build tempfolder for output
 LET tmpdir &amp;lt;= tempdir()

 -- decompress utility
 LET payload = SELECT *
 FROM unzip(filename=jlecmdpackage[0].FullPath,
 output_directory=tmpdir) WHERE OriginalPath =~ "JLECmd.exe"

 -- execute payload
 LET deploy &amp;lt;= SELECT *
 FROM execve(argv=[payload.NewPath[0],
 "-d",
 "c:/",
 "--csv",
 tmpdir,
 "--csvf",
 "results.csv"])

 LET x = scope()

 SELECT * FROM foreach(row={
 SELECT OSPath, upload(file=OSPath)
 FROM glob(globs="results_*.csv", root=tmpdir)
 }, query={
 SELECT x.SourceFile AS SourceFile,
 x.SourceCreated AS SourceCreated,
 x.SourceModified AS SourceModified,
 x.LocalPath AS LocalPath,
 x.Arguments AS Arguments,
 x.TargetCreated AS TargetCreated,
 x.TargetModified AS TargetModified,
 x.VolumeLabel AS VolumeLabel,
 x.DriveType AS DriveType,
 x.AppIdDescription AS AppIdDescription,
 x.CommonPath AS CommonPath,
 x.VolumeSerialNumber AS VolumeSerialNumber,
 x.MachineID AS MachineID,
 x.MachineMACAddress AS MachineMACAddress,
 x.TargetMFTEntryNumber AS TargetMFTEntryNumber,
 x.TargetSequenceNumber AS TargetSequenceNumber,
 x.TargetIDAbsolutePath AS TargetIDAbsolutePath,
 x.TrackerCreatedOn AS TrackerCreatedOn,
 x.ExtraBlocksPresent AS ExtraBlocksPresent,
 x.HeaderFlags AS HeaderFlags,
 x.FileAttributes AS FileAttributes,
 x.FileSize AS FileSize
 FROM parse_csv(filename=OSPath)
 WHERE
 (if(condition=dateAfter, then=SourceCreated &amp;gt; dateAfter,
 else=TRUE) AND
 if(condition=dateBefore, then=SourceCreated &amp;lt; dateBefore,
 else=TRUE))
 AND SourceFile =~ sourceFile
 AND LocalPath =~ localPath
 AND Arguments =~ arguments
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.NotificationsDatabase</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.notificationsdatabase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.notificationsdatabase/</guid><description>&lt;p&gt;Parses the Win10/11 notifications database, which contains events for badges, tiles, and toasts shown to each user.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.NotificationsDatabase
author: Zane Gittins
description: |
 Parses the Win10/11 notifications database, which contains events for badges, tiles, and toasts shown to each user.

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT or NOTEBOOK
type: CLIENT

parameters:
 - name: UserRegex
 default: .
 - name: SearchGlob
 default: "C:/Users/*/AppData/Local/Microsoft/Windows/Notifications/wpndatabase.db"

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

 query: |
 LET Files &amp;lt;= SELECT *
 FROM glob(globs=SearchGlob)
 WHERE OSPath =~ UserRegex
 LET Notifications &amp;lt;= SELECT *
 FROM foreach(
 row=Files,
 query={
 SELECT *
 FROM sqlite(file=OSPath,
 accessor="auto",
 query="SELECT * FROM Notification")
 })
 LET Handlers &amp;lt;= SELECT *
 FROM foreach(
 row=Files,
 query={
 SELECT *
 FROM sqlite(file=OSPath,
 accessor="auto",
 query="SELECT * FROM NotificationHandler")
 })
 LET Results = SELECT *, {
 SELECT *
 FROM Handlers
 WHERE RecordId = HandlerId
 } AS HandlerInfo
 FROM Notifications
 SELECT Id,
 HandlerInfo.PrimaryId AS Application,
 HandlerId,
 Type,
 timestamp(winfiletime=ExpiryTime) AS ExpiryTime,
 timestamp(winfiletime=ArrivalTime) AS ArrivalTime,
 Payload AS PayloadRaw,
 Tag,
 Group,
 DataVersion,
 PayloadType,
 HandlerInfo
 FROM Results

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.PersistenceSniper</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.persistencesniper/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.persistencesniper/</guid><description>&lt;p&gt;PersistenceSniper is a Powershell module that can be used by Blue Teams, Incident
Responders and System Administrators to hunt persistences implanted in Windows machines.
It is also available on Powershell Gallery and it is digitally signed with a valid code
signing certificate. The tool is under active development with new releases coming out
regularly, so make sure to use the up-to-date version.
&lt;a href="https://github.com/last-byte/PersistenceSniper" target="_blank" &gt;https://github.com/last-byte/PersistenceSniper&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;NOTE: the Rapid7 team has observed this artifact fail with some EDR/EPP tools deployed
with Powershell prevention capabilities. Please ensure the Velociraptor binary (and
child powershell) are excluded in these tools.
Now DiffCSVUrl is downloaded during generation of the
collector, not during execution.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.PersistenceSniper
description: |
 PersistenceSniper is a Powershell module that can be used by Blue Teams, Incident
 Responders and System Administrators to hunt persistences implanted in Windows machines.
 It is also available on Powershell Gallery and it is digitally signed with a valid code
 signing certificate. The tool is under active development with new releases coming out
 regularly, so make sure to use the up-to-date version.
 https://github.com/last-byte/PersistenceSniper

 NOTE: the Rapid7 team has observed this artifact fail with some EDR/EPP tools deployed
 with Powershell prevention capabilities. Please ensure the Velociraptor binary (and
 child powershell) are excluded in these tools.
 Now DiffCSVUrl is downloaded during generation of the 
 collector, not during execution.

author: Chris Jones - CPIRT | FabFaeb | Antonio Blescia (TheThMando) | 0xdeadcell

parameters:
 - name: IncludeHighFalsePositivesChecks
 default: true
 type: bool
 - name: UploadHits
 type: bool
 default: false

tools:
 - name: PSniper
 url: https://github.com/last-byte/PersistenceSniper/releases/download/v1.16.1/PersistenceSniper.zip
 - name: DiffCSVUrl
 url: https://raw.githubusercontent.com/ablescia/Windows.PersistenceSniper/main/false_positives.csv


type: Client

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

sources:
 - query: |
 LET TmpDir &amp;lt;= tempdir(remove_last='Y')

 LET Toolzip &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="PSniper",
 IsExecutable=FALSE)
 
 LET CSVPath &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="DiffCSVUrl",
 IsExecutable=FALSE)

 LET _ &amp;lt;= SELECT *
 FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)

 LET PSniperLocation = path_join(
 components=[TmpDir, 'PersistenceSniper', 'PersistenceSniper.psm1'],
 path_type='windows')

 LET FalsePositivesFile &amp;lt;= path_join(
 components=[TmpDir, '\\false_positives.csv'],
 path_type='windows')

 LET CSVFile &amp;lt;= path_join(
 components=[TmpDir + '\\psniper_results.csv'],
 path_type='windows')
 LET csvpath = '"' + CSVFile.Path + '"'

 LET arg_diffcsv &amp;lt;= if(
 condition=CSVFile != "",
 then="-DiffCSV " + '"' + FalsePositivesFile.Path + '"',
 else="")

 LET arg_includehighfalsepositiveschecks &amp;lt;= if(
 condition=IncludeHighFalsePositivesChecks,
 then="-IncludeHighFalsePositivesChecks",
 else="")

 LET cmdline &amp;lt;= join(
 array=['import-module', '"' + PSniperLocation.Path + '";', 'Find-AllPersistence', arg_includehighfalsepositiveschecks, arg_diffcsv, '| ConvertTo-CSV -NoTypeInformation | Out-File -encoding ASCII',csvpath],
 sep=' ')

 LET _ &amp;lt;= SELECT *
 FROM execve(
 argv=["powershell", "-ExecutionPolicy", "bypass", "-command", cmdline])

 LET hits = SELECT *
 FROM parse_csv(filename=CSVFile)

 -- upload files if selected
 LET upload_hits = SELECT *, upload(file=CSVFile) AS Upload
 FROM hits

 -- return rows
 SELECT *
 FROM if(
 condition=UploadHits,
 then=upload_hits,
 else=hits)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.RecentFileCache</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.recentfilecache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.recentfilecache/</guid><description>&lt;p&gt;Parses the RecentFileCache as evidence of execution artifact existing on older Windows systems (&amp;lt;= Win 7).&lt;/p&gt;
&lt;p&gt;Full path, Drive letter and the binary name will be parsed. The order represents the timeline of the execution flow. However, there are no timestamps included in this artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.RecentFileCache
author: Stephan Mikiss @stephmikiss (SEC Defence @SEC Consult)
description: |
 Parses the RecentFileCache as evidence of execution artifact existing on older Windows systems (&amp;lt;= Win 7).
 
 Full path, Drive letter and the binary name will be parsed. The order represents the timeline of the execution flow. However, there are no timestamps included in this artifact.

type: CLIENT
parameters:
 - name: FileGlob
 description: Glob to RecentFileCache.
 default: C:/Windows/appcompat/Programs/RecentFileCache.bcf
 - name: FullPathRegex
 description: Regex to filter in the full path of the entry.
 default: .
 - name: BinaryRegex
 description: Regex to filter for binary names.
 default: .

sources:
 - query: |

 LET entries = SELECT utf16(string=Entry) as FullPath
 FROM parse_records_with_regex(
 file="C:/Windows/appcompat/Programs/RecentFileCache.bcf",
 regex='''[\x00]{3}(?P&amp;lt;Entry&amp;gt;[a-z]\x00:.+?\x00)[\x00]{2}''')
 
 SELECT parse_string_with_regex(string=FullPath,regex='''(?P&amp;lt;Drive&amp;gt;^[a-z]:)''').Drive as Drive,
 FullPath,
 parse_string_with_regex(string=FullPath,regex='''\\(?P&amp;lt;Binary&amp;gt;[^\\]+$)''').Binary as Binary
 FROM entries
 WHERE FullPath =~ FullPathRegex
 AND Binary =~ BinaryRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.SoftPerfectNetworkScanner</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.softperfectnetworkscanner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.softperfectnetworkscanner/</guid><description>&lt;p&gt;This Velociraptor artifact is tailored for forensic analysis of SoftPerfect Network Scanner (NetScan) usage on Windows platforms. This facilitates the identification of how SoftPerfect Network Scanner was configured and used, aiding in DFIR investigations. It parse the MFT to search and retrieve the content of two files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;netscan.lic: display information related to the program&amp;rsquo;s graphical user interface language configuration and license details, including the license name for example&lt;/li&gt;
&lt;li&gt;netscan.xml: display information regarding the tool&amp;rsquo;s configuration (selected scan ports, history of scanned IP ranges&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.SoftPerfectNetworkScanner
description: |
 This Velociraptor artifact is tailored for forensic analysis of SoftPerfect Network Scanner (NetScan) usage on Windows platforms. This facilitates the identification of how SoftPerfect Network Scanner was configured and used, aiding in DFIR investigations. It parse the MFT to search and retrieve the content of two files:
 
 - netscan.lic: display information related to the program's graphical user interface language configuration and license details, including the license name for example
 - netscan.xml: display information regarding the tool's configuration (selected scan ports, history of scanned IP ranges...)
author: Julien Houry - @y0sh1mitsu (CSIRT Airbus Protect), Matt Green - @mgreen27 (ntfs performance update)

parameters:
 - name: AllDrives
 type: bool
 description: "Select MFT search on all attached ntfs drives."
 
reference:
 - https://www.protect.airbus.com/blog/uncovering-cyber-intruders-a-forensic-deep-dive-into-netscan-angry-ip-scanner-and-advanced-port-scanner/
 - https://www.cisa.gov/news-events/cybersecurity-advisories/aa20-259a
 - https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-060a

type: CLIENT

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

sources:
 - query: |
 SELECT 
 FileName,
 OSPath,
 Created0x10 as Btime,
 LastModified0x10 as Mtime,
 parse_xml(file=OSPath) AS ParsedXML 
 FROM Artifact.Windows.NTFS.MFT(FileRegex='^netscan\.(lic|xml)$',AllDrives=AllDrives)
 WHERE NOT OSPath =~ '''\\&amp;lt;Err&amp;gt;\\'''

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.TabState</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/tabstate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/tabstate/</guid><description>&lt;p&gt;This artifact parses notepad TabState files in available in Windows 11.&lt;/p&gt;
&lt;p&gt;In Windows 11, notepad has implemented a feature to repopulate previously
open notepad tabs - both saved and unsaved. This data is stored on disk and
provides an interesting opportunity for DFIR practitioners.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.TabState
author: Matt Green - @mgreen27
description: |
 This artifact parses notepad TabState files in available in Windows 11.
 
 In Windows 11, notepad has implemented a feature to repopulate previously 
 open notepad tabs - both saved and unsaved. This data is stored on disk and 
 provides an interesting opportunity for DFIR practitioners.
 
reference:
 - https://medium.com/@mahmoudsoheem/new-digital-forensics-artifact-from-windows-notepad-527645906b7b
 - https://www.youtube.com/watch?v=zSSBbv2fc2s
 
type: CLIENT

parameters:
 - name: TargetGlob
 description: Target glob for notepad TabState bin files.
 default: C:\Users\*\AppData\Local\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState\*.bin
 - name: ContentRegex
 description: Content filter regex to select which TabState files return a row.
 type: regex
 default: .
 - name: FilenameRegex
 description: Filter regex to select Saved filename path. ```^$``` returns only unsaved files.
 type: regex
 default: .
 - name: UploadFile
 description: If selected will upload TabState file.
 type: bool

export: |
 LET TSProfile = '''[
 ["TabState", 0, [
 ["__Magic", 0, "String", {"length": 3, "term_hex" : "FFFFFF" }],
 ["__Saved", 3, "char"],
 ["__FileNameSize", 4, "int8"],
 ["__Filename", 5, "String", {
 encoding: "utf8",
 length: "x=&amp;gt;x.__FileNameSize * 2", 
 term_hex : "000000",
 }],
 ["Filename",0,"Value",{"value": "x=&amp;gt;if(condition= x.__Saved &amp;gt; 0, then=utf16(string=x.__Filename),else='')"}],
 
 ["__HeaderPrefix", "x=&amp;gt;5 + len(list=x.__Filename)", "String",{"term_hex": "0100", length: 1000, max_length: 1000}],
 ["__DataOffset",0,"Value",{ "value": "x=&amp;gt;5 + len(list=x.__Filename) + len(list=x.__HeaderPrefix)"}],
 ["__Data", "x=&amp;gt; x.__DataOffset + 5", "String", {
 encoding: "utf8",
 length: 100000,
 max_length: 100000, 
 "term_hex" : "000000000000000000000000" 
 }],
 ["StateData",0,"Value",{ "value": "x=&amp;gt;utf16(string=x.__Data[:(len(list=x.__Data) - 5)])"}],
 ]]]'''


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

 query: |
 LET results = SELECT OSPath, Name,Mtime,Atime,Ctime,Btime,
 parse_binary(filename=OSPath,profile=TSProfile,struct='TabState') as Parsed
 FROM glob(globs=expand(path=TargetGlob)) 
 WHERE NOT IsDir 
 AND NOT OSPath =~'''\.(0|1)\.bin$'''
 AND Parsed.StateData =~ ContentRegex
 AND Parsed.Filename =~ FilenameRegex
 
 SELECT 
 Name,Mtime,Atime,Ctime,Btime,
 Parsed.Filename as SavedFilename,
 Parsed.StateData as StateData,
 OSPath
 FROM if(condition= UploadFile,
 then={ 
 SELECT *, upload(file=OSPath) as Upload 
 FROM results 
 },
 else= results )


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.ThumbCache</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/thumbcache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/thumbcache/</guid><description>&lt;p&gt;ThumbCache_xx.db parser.&lt;/p&gt;
&lt;p&gt;Windows 8 and above is supported. This does NOT parse Win7/Vista caches.&lt;/p&gt;
&lt;p&gt;By default, for resident files, the NAME field in a cache entry contains the
ASCII equivalent of the cache id, a 64 bit number. However for some deleted
files and files residing on external hosts or external storage, there is
either a file name, full UNC path or an alternate representation such as:
&lt;code&gt;&amp;lt;VOLUME NAME&amp;gt;?&amp;lt;VOLUME NUMBER&amp;gt;?&amp;lt;FILENAME&amp;gt; &lt;/code&gt;&lt;br&gt;
or&lt;br&gt;
&lt;code&gt;&amp;lt;VOLUME NAME&amp;gt;?&amp;lt;VOLUME NUMBER&amp;gt;?&amp;lt;MFT REFERENCE NUMBER&amp;gt;&lt;/code&gt;&lt;br&gt;
or&lt;br&gt;
&lt;code&gt;\\&amp;lt;hostname&amp;gt;\c$\&amp;lt;file path&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This artifact &lt;b&gt;omits&lt;/b&gt; the default resident files by removing any entries that
look like the cache ids leaving behind the &lt;b&gt;interesting files&lt;/b&gt;, usually
references to external disks or deleted files. At times there are references
to external files that may be useful to an investigation, when other
artifacts have been removed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.ThumbCache
author: "Yogesh Khatri - @SwiftForensics / CyberCX"
description: |
 ThumbCache_xx.db parser. 
 
 Windows 8 and above is supported. This does NOT parse Win7/Vista caches.
 
 By default, for resident files, the NAME field in a cache entry contains the
 ASCII equivalent of the cache id, a 64 bit number. However for some deleted 
 files and files residing on external hosts or external storage, there is 
 either a file name, full UNC path or an alternate representation such as:
 ```&amp;lt;VOLUME NAME&amp;gt;?&amp;lt;VOLUME NUMBER&amp;gt;?&amp;lt;FILENAME&amp;gt; ``` 
 or 
 ```&amp;lt;VOLUME NAME&amp;gt;?&amp;lt;VOLUME NUMBER&amp;gt;?&amp;lt;MFT REFERENCE NUMBER&amp;gt;``` 
 or 
 ```\\&amp;lt;hostname&amp;gt;\c$\&amp;lt;file path&amp;gt;```
 
 This artifact &amp;lt;b&amp;gt;omits&amp;lt;/b&amp;gt; the default resident files by removing any entries that 
 look like the cache ids leaving behind the &amp;lt;b&amp;gt;interesting files&amp;lt;/b&amp;gt;, usually 
 references to external disks or deleted files. At times there are references
 to external files that may be useful to an investigation, when other 
 artifacts have been removed.

reference:
 - https://github.com/jas502n/010-Editor-Template/blob/main/ThumbCache.bt
 - https://www.hackerfactor.com/blog/index.php?/archives/360-Thumbs-Up.html

type: CLIENT

parameters:
 - name: GlobPath
 default: "C:/Users/**/AppData/Local/Microsoft/Windows/Explorer/thumbcache_*.db"
 description: Change this to scan custom folders
 
 - name: MaxCountPerFile
 default: 10000
 type: int64
 description: Don't change unless you have a good reason to. By default, the max count is far less than this.

 - name: NameRegex
 default: .
 type: regex
 description: Regex to filter on Name field. E.g Add ^\\\\ to hunt for UNC path.
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'

 query: |
 
 LET ProfileX = '''
 [
 ["Header", 0, [
 ["Signature", 0, "String", { "length": 4 }],
 ["Version", 4, "Enumeration", {
 "type": "uint32",
 "map": {
 "WINDOWS_VISTA" : 0x14,
 "WINDOWS_7" : 0x15,
 "WINDOWS_8" : 0x1A,
 "WINDOWS_8v2" : 0x1C,
 "WINDOWS_8v3" : 0x1E,
 "WINDOWS_8_1" : 0x1F,
 "WINDOWS_10" : 0x20,
 }
 }
 ],
 ["HeaderSize", 16, "uint32"],
 ["records", "x=&amp;gt;x.HeaderSize", "Array", {
 "type": "Entry",
 "max_count": "x=&amp;gt;MaxCountPerFile",
 "count": "x=&amp;gt;MaxCountPerFile",
 }]
 ]],
 ["Entry", "x=&amp;gt;x.Size", [
 ["Signature", 0, "String", { "length": 4 }],
 ["Size", 4, "uint32"],
 ["NameSize", 16, "uint32"],
 ["Name", 56, "String", {"encoding": "utf16", "length": "x=&amp;gt;x.NameSize"}]
 ],
 ]
 ]
 '''
 
 LET targets &amp;lt;= SELECT OSPath, 
 read_file(filename=OSPath,offset=0,length=4) as _Header
 FROM glob(globs=GlobPath)
 WHERE NOT IsDir 
 AND OSPath =~ "thumbcache_[0-9]+\.db"
 AND _Header =~ '^CMMM$'

 LET thumbcache_data &amp;lt;= SELECT OSPath,
 parse_binary(filename=OSPath,
 profile=ProfileX, struct="Header") AS Parsed 
 FROM targets
 WHERE NOT Parsed.Version IN ("WINDOWS_VISTA", "WINDOWS_7")
 
 SELECT OSPath, Name, Version FROM 
 foreach(row=thumbcache_data, query={
 SELECT Name, OSPath, Parsed.Version as Version
 FROM foreach(row=Parsed.records) 
 })
 WHERE Name
 AND Name =~ NameRegex
 AND NOT Name =~ "^[0-9a-fA-F]{14,16}$" 
 AND NOT Name =~ "^::{"

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.Trawler</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/trawler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/trawler/</guid><description>&lt;p&gt;Trawler [https://github.com/joeavanzato/Trawler] is a PowerShell script designed to help Incident
Responders rapidly identify potential adversary persistence mechanisms on Windows. It is similar
in nature to PersistenceSniper with additional targeted checks as well as the capability to operate
against a &amp;lsquo;dead box&amp;rsquo; (mounted drive). The output is simplified compared to PersistenceSniper, providing
the user with the details needed to kick off an investigation into any identified mechanisms.
Think of these tools as autoruns on steroids.&lt;/p&gt;
&lt;p&gt;Please ensure the Velociraptor binary (and child powershell process) are excluded in any EDR/AV products.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.Trawler
description: |
 Trawler [https://github.com/joeavanzato/Trawler] is a PowerShell script designed to help Incident
 Responders rapidly identify potential adversary persistence mechanisms on Windows. It is similar
 in nature to PersistenceSniper with additional targeted checks as well as the capability to operate
 against a 'dead box' (mounted drive). The output is simplified compared to PersistenceSniper, providing
 the user with the details needed to kick off an investigation into any identified mechanisms.
 Think of these tools as autoruns on steroids.

 Please ensure the Velociraptor binary (and child powershell process) are excluded in any EDR/AV products.

author: Joe Avanzato

parameters:
 - name: UploadResults
 type: bool
 default: true

tools:
 - name: Trawler
 url: https://github.com/joeavanzato/Trawler/releases/download/1_0_0/trawler_release_v1_0_0.zip
 expected_hash: efade9e0e6d228c118c4c28de2e45c37ae2fa4973283d5f851e6c62c7b72f53b

type: Client

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

sources:
 - query: |
 LET TmpDir &amp;lt;= tempdir(remove_last='Y')

 LET TrawlerZIP &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="Trawler", IsExecutable=FALSE)

 LET _ &amp;lt;= SELECT * FROM unzip(filename=TrawlerZIP.FullPath, output_directory=TmpDir)

 LET TrawlerLocation = path_join(components=[TmpDir, 'trawler.ps1'], path_type='windows')

 LET TrawlerOutput &amp;lt;= path_join(components=[TmpDir + '\\detections.csv'], path_type='windows')
 LET TrawlerOutputPath = '"' + TrawlerOutput.Path + '"'

 LET cmdline &amp;lt;= join(
 array=[TrawlerLocation, '-outpath', TrawlerOutputPath],
 sep=' ')

 LET _ &amp;lt;= SELECT *
 FROM execve(
 argv=["powershell", "-ExecutionPolicy", "bypass", "-command", cmdline])

 LET LocalUploadTrawlerRecords = SELECT *
 FROM parse_csv(filename=TrawlerOutput)

 LET UploadTrawlerRecords = SELECT *, upload(file=TrawlerOutput) AS Upload
 FROM LocalUploadTrawlerRecords

 SELECT *
 FROM if(
 condition=UploadResults,
 then=UploadTrawlerRecords,
 else=LocalUploadTrawlerRecords)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.UEFI.BootApplication</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/bootapplication/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/bootapplication/</guid><description>&lt;p&gt;This artifact parses Windows MeasuredBoot TCGLogs to extract PathName of
EV_EFI_Boot_Services_Application events, which can assist detection of
potential ESP based persistance.&lt;/p&gt;
&lt;p&gt;\EFI\Microsoft\Boot\bootmgfw.efi - the Windows boot manager on systems with
UEFI firmware.&lt;/p&gt;
&lt;p&gt;The artifact leverages Velociraptor tools to deploy and execute a powershell
module to parse TCGLogs on disk and memory.&lt;/p&gt;
&lt;p&gt;NOTE:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recommended to host TCGLogTools and TCGLogToolsExecution locally to mitigate github connection limits.&lt;/li&gt;
&lt;li&gt;AllParsedTCGLog can be large and is best suited to triage.&lt;/li&gt;
&lt;li&gt;Thank you to mattifestation for TCGTools!&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.UEFI.BootApplication
author: "Matt Green - @mgreen27"
description: |
 This artifact parses Windows MeasuredBoot TCGLogs to extract PathName of 
 EV_EFI_Boot_Services_Application events, which can assist detection of 
 potential ESP based persistance. 
 
 \EFI\Microsoft\Boot\bootmgfw.efi - the Windows boot manager on systems with 
 UEFI firmware.

 
 The artifact leverages Velociraptor tools to deploy and execute a powershell 
 module to parse TCGLogs on disk and memory.
 
 NOTE:
 
 - Recommended to host TCGLogTools and TCGLogToolsExecution locally to mitigate github connection limits.
 - AllParsedTCGLog can be large and is best suited to triage.
 - Thank you to mattifestation for TCGTools!

reference:
 - https://www.microsoft.com/en-us/security/blog/2023/04/11/guidance-for-investigating-attacks-using-cve-2022-21894-the-blacklotus-campaign/
 
type: CLIENT
resources:
 timeout: 6000

tools:
 - name: TCGLogTools
 url: https://raw.githubusercontent.com/mattifestation/TCGLogTools/master/TCGLogTools.psm1
 - name: TCGLogToolsExecution
 url: https://gist.githubusercontent.com/mgreen27/d7bd2480069f714f31296d5f38fe7f0c/raw/708002dd858a38e8e8885e926c3016f80057a7d4/Run-TCGLogTools.ps1
 

parameters:
 - name: TCGLogLocationGlob
 default: c:\Windows\Logs\MeasuredBoot\*.log
 - name: AllParsedTCGLog
 type: bool
 description: Return all parsed TCGLog data. This can be very large so best used as triage only!


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

sources:
 - query: |
 -- Get the path to the TCGLogTools tool
 LET module &amp;lt;= SELECT OSPath
 FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="TCGLogTools",
 IsExecutable=FALSE
 )
 LET script &amp;lt;= SELECT OSPath
 FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="TCGLogToolsExecution",
 IsExecutable=FALSE
 )
 
 -- Run the tool and relay back the output
 LET data = SELECT * 
 FROM execve(argv=['powershell','-ExecutionPolicy','Unrestricted','-NoProfile','-File',script.OSPath[0]],
 env=dict(
 `TCGLogTools` = str(str=module.OSPath[0]),
 `TCGLogLocation` = TCGLogLocationGlob ),
 length=100000000)
 WHERE Stdout
 
 LET file_info(path) = SELECT OSPath,Size,Mtime,Atime,Ctime,Btime 
 FROM stat(filename=path)
 
 LET results &amp;lt;= SELECT *,
 if(condition= LogPath,
 then= file_info(path=LogPath)[0],
 else= Null ) as FileInfo
 FROM parse_json_array(data=data.Stdout)
 
 -- quick dynamic function to clean up multi entries for PathName
 LET bootapplication(data) = SELECT PathName FROM data.Event.DevicePath.DeviceInfo 
 WHERE PathName
 GROUP BY lowcase(string=PathName)
 
 LET clean_bootapplication(data) = SELECT _value as PathName FROM foreach(row=data) GROUP BY _value
 
 LET boot_application = SELECT 
 if(condition=FileInfo,
 then= FileInfo.OSPath,
 else= 'Current InMemory' ) as OSPath,
 FileInfo.Size as Size,
 FileInfo.Mtime as Mtime,
 FileInfo.Ctime as Ctime,
 FileInfo.Btime as Btime,
 clean_bootapplication(data=array(a=Events.PCR4.Event.DevicePath.DeviceInfo.PathName)).PathName as BootApplication
 FROM results
 
 -- cleaning up results and ensuring single string if not multiple BootApplication entries
 SELECT *,
 if(condition=len(list=BootApplication)=1,
 then= BootApplication[0],
 else= BootApplication ) as BootApplication
 FROM boot_application

 notebook:
 - type: vql
 name: BootApplication count
 template: |
 /*
 ## BootApplication by count
 */
 SELECT 
 BootApplication,
 min(item=Btime) as EarliestBtime,
 count() as TotalBoots
 FROM source(artifact="Exchange.Windows.Forensics.UEFI.BootApplication")
 GROUP BY lowcase(string=BootApplication)
 
 /*
 ## All BootApplication
 */
 SELECT BootApplication, OSPath, Size, Mtime, Ctime, Btime
 FROM source(artifact="Exchange.Windows.Forensics.UEFI.BootApplication")
 
 - name: AllParsed
 queries:
 - |
 SELECT FileInfo,Header,Events
 FROM if(condition=AllParsedTCGLog, 
 then= results )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Forensics.WindowsNotepadParser</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.windowsnotepadparser/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.forensics.windowsnotepadparser/</guid><description>&lt;p&gt;Runs the WindowsNotepadParser (&lt;a href="https://github.com/ogmini/Notepad-State-Library" target="_blank" &gt;https://github.com/ogmini/Notepad-State-Library&lt;/a&gt;
) tool to collect and parse
forensic artifacts related to Windows Notepad on Windows 11.&lt;/p&gt;
&lt;p&gt;Documentation and details about the artifacts can be found at - &lt;a href="https://github.com/ogmini/Notepad-State-Library" target="_blank" &gt;https://github.com/ogmini/Notepad-State-Library&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id="history"&gt;History&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1.0 - Creation&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Forensics.WindowsNotepadParser
description: |
 Runs the WindowsNotepadParser (https://github.com/ogmini/Notepad-State-Library) tool to collect and parse 
 forensic artifacts related to Windows Notepad on Windows 11. 
 
 Documentation and details about the artifacts can be found at - https://github.com/ogmini/Notepad-State-Library
 
 ### History
 
 - 1.0 - Creation
 
reference: 
 - https://github.com/ogmini/Notepad-State-Library
 - https://ogmini.github.io/tags.html#Windows-Notepad

author: ogmini https://ogmini.github.io/

required_permissions:
 - EXECVE
 - FILESYSTEM_WRITE

type: CLIENT

tools:
 - name: WindowsNotepadParser
 url: https://github.com/ogmini/Notepad-State-Library/releases/download/v1.0.4/WindowsNotepadParser-Minimal-v1.0.4-standalone.zip
 version: 1.0.4
 expected_hash: 4ac5a26bec26bf5f4c62354113d82dd34205c0b0ff3de71f18d2de1d09c03927

parameters:
 - name: outputDirectory
 default: "C:\\Velociraptor\\WindowsNotepadParser\\"
 description: Output directory for the csv files generated by the tool.

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

sources:
 - name: FileTabs
 description: These tabs have been saved to disk or have been opened from a file on disk.
 query: |
 -- get context on target binary
 LET windowsnotepadparserpackage &amp;lt;= SELECT * FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="WindowsNotepadParser", IsExecutable=FALSE)

 -- build tempfolder for output
 LET tmpdir &amp;lt;= tempdir()

 -- decompress utility
 LET payload = SELECT *
 FROM unzip(filename=windowsnotepadparserpackage[0].FullPath,
 output_directory=tmpdir) WHERE OriginalPath =~ "WindowsNotepadParser-Minimal.exe"

 -- execute payload
 LET deploy &amp;lt;= SELECT *
 FROM execve(argv=[payload.NewPath[0], "-o", outputDirectory])
 
 SELECT *
 FROM parse_csv(filename=outputDirectory + "NoFileTabs.csv")

 - name: NoFileTabs
 description: These tabs have not been saved to disk and have not been opened from a file on disk. They only exist in the *.bin files.
 query: |
 SELECT *
 FROM parse_csv(filename=outputDirectory + "NoFileTabs.csv")
 
 - name: StateTabs
 description: These are the *.0.bin and *.1.bin files and store extra information about the related matching GUID *.bin.
 query: |
 SELECT *
 FROM parse_csv(filename=outputDirectory + "StateTabs.csv")
 
 - name: WindowStateTabs
 description: The windowstate files store information about opened windows of Windows Notepad and files are created for each opened window. 
 query: |
 SELECT *
 FROM parse_csv(filename=outputDirectory + "WindowStateTabs.csv")
 
 - name: UnsavedBufferChunks
 description: Unsaved changes to a tab. Will only exist while Windows Notepad is open.
 query: |
 SELECT * FROM foreach(row={
 SELECT OSPath
 FROM glob(globs="*-UnsavedBufferChunks.csv", root=outputDirectory)
 }, query={
 SELECT *
 FROM parse_csv(filename=OSPath)
 
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Generic.Internet.BlockAccess</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.generic.internet.blockaccess/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.generic.internet.blockaccess/</guid><description>&lt;p&gt;Simply adds a new inbound or outbound firewall rule that filters traffic by allowing or blocking network packets that match the specified criteria via &lt;code&gt;netsh advfirewall add rule&lt;/code&gt; command. Applicable in case of blocking Internet access.&lt;/p&gt;
&lt;p&gt;HOW it does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a configurable lookup table to generate additional entries.
&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;nslookup&lt;/code&gt; command first to get IP from specific domain&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An optional &lt;code&gt;MessageBox&lt;/code&gt; may also be configured to alert all logged in users.
&lt;ul&gt;
&lt;li&gt;The message will be truncated to 256 characters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After advfirewall rules application, connection back to the Velociraptor
frontend is tested and the rule removed if connection unavailable.&lt;/li&gt;
&lt;li&gt;To remove rule, select the &lt;code&gt;RemoveRule&lt;/code&gt; checkbox.&lt;/li&gt;
&lt;li&gt;To update rule, simply rerun the artifact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WHY advfirewall?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;netsh ipsec&lt;/code&gt; and &lt;code&gt;netsh firewall&lt;/code&gt; contexts are provided for backwards-compatibility with Windows 2000/XP/2003 (Now they are all &lt;strong&gt;EOL&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Netsh AdvFirewall&lt;/code&gt; applies to: Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista.&lt;/li&gt;
&lt;li&gt;If you are new to advfirewall, please check reference link from MS first for more information.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: Test carefully before running at scale in production environment&lt;/p&gt;
&lt;p&gt;Inspired by &lt;code&gt;Windows.Remediation.Quarantine&lt;/code&gt; from Matt Green - @mgreen27 (use netsh IPsec)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Generic.Internet.BlockAccess
description: |
 Simply adds a new inbound or outbound firewall rule that filters traffic by allowing or blocking network packets that match the specified criteria via `netsh advfirewall add rule` command. Applicable in case of blocking Internet access.
 
 HOW it does:
 
 - Use a configurable lookup table to generate additional entries.
 - Using `nslookup` command first to get IP from specific domain
 - An optional `MessageBox` may also be configured to alert all logged in users.
 - The message will be truncated to 256 characters.
 - After advfirewall rules application, connection back to the Velociraptor
 frontend is tested and the rule removed if connection unavailable.
 - To remove rule, select the `RemoveRule` checkbox.
 - To update rule, simply rerun the artifact.
 
 WHY advfirewall?
 
 - The `netsh ipsec` and `netsh firewall` contexts are provided for backwards-compatibility with Windows 2000/XP/2003 (Now they are all **EOL**). 
 - `Netsh AdvFirewall` applies to: Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista.
 - If you are new to advfirewall, please check reference link from MS first for more information.
 
 NOTE: Test carefully before running at scale in production environment
 
 Inspired by `Windows.Remediation.Quarantine` from Matt Green - @mgreen27 (use netsh IPsec)

author: TueDenn - @tuedenn

reference:
 - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-r2-and-2008/dd734783(v=ws.10)
 - https://serverfault.com/questions/851922/blocking-ip-address-with-netsh-filter
 - https://docs.velociraptor.app/artifact_references/pages/windows.remediation.quarantine/

required_permissions:
 - EXECVE

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

parameters:
 - name: RuleName
 default: "VeloBlockAccess"
 - name: RuleLookupTable
 type: csv
 default: |
 dir,remoteip,protocol,interface,action,enable,description
 out,13.107.237.39,any,any,block,yes,block openai.com 1
 out,13.107.238.39,any,any,block,yes,block openai.com 2
 out,157.240.199.35,any,any,block,yes,block facbook.com
 - name: MessageBox
 description: |
 Optional message box notification to send to logged in users. 256
 character limit.
 - name: RemoveRule
 type: bool
 description: Tickbox to remove advfirewall rule.

sources:
 - query: |

 // If a MessageBox configured truncate to 256 character limit
 LET MessageBox &amp;lt;= parse_string_with_regex(
 regex='^(?P&amp;lt;Message&amp;gt;.{0,255}).*',
 string=MessageBox).Message

 // extract configurable policy from lookuptable
 LET configurable_rule &amp;lt;= SELECT
 dir,remoteip,protocol,interface,action,enable,description
 FROM RuleLookupTable
 
 // Emit the message if no output is emitted, otherwise emit the output.
 LET combine_results(Stdout, Stderr, ReturnCode, Message) = if(
 condition=Stdout =~ "[^\\s]", then=Stdout,
 else= if(condition=Stderr =~ "[^\\s]", then=Stderr,
 else= if(condition= ReturnCode=0,
 then=Message )))

 // Removes empty options from the command line
 LET clean_cmdline(CMD) = filter(list=CMD, regex='^(\\w+|\\w+=.+)$')

 LET delete_cmdline = clean_cmdline(
 CMD=('netsh','advfirewall','firewall','delete','rule', 'name=' + RuleName))

 LET entry_cmdline(RuleName, dir,interface,action,remoteip,protocol,enable) = clean_cmdline(
 CMD=('netsh','advfirewall','firewall','add','rule',
 format(format='name=%s', args=RuleName),
 format(format='dir=%s', args=dir),
 format(format='interface=%s', args=interface),
 format(format='action=%s', args=action),
 format(format='remoteip=%s', args=remoteip),
 format(format='protocol=%s', args=protocol),
 format(format='enable=%s', args=enable)))
 
 
 // delete old or unwanted policy
 LET delete_rule = SELECT
 timestamp(epoch=now()) as Time,
 RuleName + ' firewall rule deleted.' AS Result
 FROM execve(argv=delete_cmdline, length=10000)

 // loop over configurable_rule to create advfirewall rule
 LET create_rule = SELECT * FROM foreach(
 row=configurable_rule,
 query= {
 SELECT
 timestamp(epoch=now()) as Time,
 combine_results(Stdout=Stdout, Stderr=Stderr,
 ReturnCode=ReturnCode,
 Message='Rule added: ' +
 join(array=entry_cmdline(RuleName=RuleName, 
 dir=dir,
 interface=interface,
 action=action,
 remoteip=remoteip,
 protocol=protocol,
 enable=enable), sep=" ")) AS Result
 FROM execve(argv=entry_cmdline(RuleName=RuleName, 
 dir=dir,
 interface=interface,
 action=action,
 remoteip=remoteip,
 protocol=protocol,
 enable=enable), length=10000)
 })
 
 // Parse a URL to get domain name.
 LET get_domain(URL) = parse_string_with_regex(
 string=URL, regex='^https?://(?P&amp;lt;Domain&amp;gt;[^:/]+)').Domain

 // Parse a URL to get the port
 LET get_port(URL) = if(condition= URL=~"https://[^:]+/", then="443",
 else=if(condition= URL=~"http://[^:]+/", then="80",
 else=parse_string_with_regex(string=URL,
 regex='^https?://[^:/]+(:(?P&amp;lt;Port&amp;gt;[0-9]*))?/').Port))

 // extract Velociraptor config to get domain and port information
 LET extracted_config &amp;lt;= SELECT * FROM foreach(
 row=config.server_urls,
 query={
 SELECT
 get_domain(URL=_value) AS DstAddr,
 get_port(URL=_value) AS DstPort,
 'VelociraptorFrontEnd' AS Description,
 _value AS URL
 FROM scope()
 })
 
 // Check connection to Velociraptor frontend server
 LET test_connection = SELECT * FROM foreach(
 row={
 SELECT * FROM extracted_config
 WHERE Description = 'VelociraptorFrontEnd'
 },
 query={
 SELECT *
 Url,
 response
 FROM
 http_client(url='https://' + DstAddr + ':' + DstPort + '/server.pem',
 disable_ssl_security='TRUE')
 WHERE Response = 200
 LIMIT 1
 })
 
 // final check to keep or remove policy
 LET final_check = SELECT * FROM if(condition= test_connection,
 then={
 SELECT
 timestamp(epoch=now()) as Time,
 if(condition=MessageBox,
 then= RuleName + ' connection test successful. MessageBox sent.',
 else= RuleName + ' connection test successful.'
 ) AS Result
 FROM if(condition=MessageBox,
 then= {
 SELECT * FROM execve(argv=['msg','*',MessageBox])
 },
 else={
 SELECT * FROM scope()
 })
 },
 else={
 SELECT
 timestamp(epoch=now()) as Time,
 RuleName + ' failed connection test. Removing advfirewall rule.' AS Result
 FROM delete_rule
 })

 // Execute content
 SELECT * FROM if(condition=RemoveRule,
 then=delete_rule,
 else={
 SELECT * FROM chain(
 a=delete_rule,
 b=create_rule,
 c=final_check)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Hunter.Yara.LOLDrivers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.hunter.yara.loldrivers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.hunter.yara.loldrivers/</guid><description>&lt;p&gt;This artifact scans system driver directories using two user-supplied YARA rules:&lt;/p&gt;
&lt;p&gt;One for malware detection and another for vulnerability detection. If no rules are supplied the artifact runs its encoded rule sets by default, which are these one&amp;rsquo;s from Florian Roth: &lt;a href="https://github.com/magicsword-io/LOLDrivers/tree/main/detections/yara" target="_blank" &gt;https://github.com/magicsword-io/LOLDrivers/tree/main/detections/yara&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Matching files will show the match type as either &amp;ldquo;malware&amp;rdquo; or &amp;ldquo;vulnerability&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Matching files can also be optionally uploaded.&lt;/p&gt;
&lt;p&gt;This artifact is modeled after &lt;code&gt;Custom.Generic.Detection.Yara.Glob&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Hunter.Yara.LOLDrivers
author: Kaizar Lehri and Blake McDermott
description: |
 This artifact scans system driver directories using two user-supplied YARA rules:
 
 One for malware detection and another for vulnerability detection. If no rules are supplied the artifact runs its encoded rule sets by default, which are these one's from Florian Roth: https://github.com/magicsword-io/LOLDrivers/tree/main/detections/yara 
 
 Matching files will show the match type as either "malware" or "vulnerability".
 
 Matching files can also be optionally uploaded.
 
 This artifact is modeled after `Custom.Generic.Detection.Yara.Glob`.
 
type: CLIENT

parameters:
 - name: ScanMalwareYaraRule
 description: Whether to scan with the malware YARA rule.
 type: bool
 default: true

 - name: MalwareYaraRule
 description: YARA rule used to detect malware. If provided, we use these rules instead of the built-in set.
 type: yara

 - name: ScanVulnerabilityYaraRule
 description: Whether to scan with the vulnerability YARA rule.
 type: bool
 default: true

 - name: VulnerabilityYaraRule
 description: YARA rule used to detect vulnerabilities. If provided, we use these rules instead of the built-in set.
 type: yara

 - name: UploadMatches
 description: Whether to upload matching files.
 type: bool
 default: false

 - name: NumberOfHits
 description: Maximum number of matches per file.
 type: int
 default: 1

 - name: SizeMin
 description: Minimum file size in bytes to scan.
 type: int64

 - name: SizeMax
 description: Maximum file size in bytes to scan.
 type: int64

export:
 LET Scan(YaraRules, Type, NumberOfHits) =
 SELECT * FROM foreach(row=files, query={
 SELECT 
 OSPath, Rule, Tags, Meta,
 String.Name AS YaraString,
 String.Offset AS HitOffset,
 Type AS MatchType
 FROM yara(rules=YaraRules, files=OSPath, number=NumberOfHits)
 })

sources:
 - name: MalwareYaraRule
 query: |
 LET decoded_malware_rule &amp;lt;= MalwareYaraRule || gunzip(string=base64decode(string="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"))

 LET driver_dirs = SELECT
 lowcase(string=pathspec(parse=PathName).Dirname) AS Folder
 FROM wmi(
 query="SELECT PathName FROM Win32_SystemDriver"
 )
 GROUP BY Folder

 LET files = SELECT * FROM foreach(row=driver_dirs, query={
 SELECT OSPath, Name, Size
 FROM glob(globs="*", root=Folder, nosymlink="True")
 WHERE NOT IsDir AND NOT IsLink
 AND if(condition=SizeMin, then=Size &amp;gt;= SizeMin, else=True)
 AND if(condition=SizeMax, then=Size &amp;lt;= SizeMax, else=True)
 })

 LET malware_results = SELECT * FROM if(condition=ScanMalwareYaraRule,
 then={
 SELECT * FROM Scan(
 YaraRules=decoded_malware_rule,
 Type="malware",
 NumberOfHits=NumberOfHits
 )
 })

 LET malware_uploads = SELECT *, upload(file=OSPath, name=OSPath) AS Upload FROM malware_results

 SELECT * FROM if(condition=UploadMatches,
 then=malware_uploads,
 else=malware_results)

 - name: VulnerabilityYaraRule
 query: |
 LET decoded_vuln_rule &amp;lt;= VulnerabilityYaraRule || gunzip(string=base64decode(string="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"))

 LET driver_dirs = SELECT
 lowcase(string=pathspec(parse=PathName).Dirname) AS Folder
 FROM wmi(
 query="SELECT PathName FROM Win32_SystemDriver"
 )
 GROUP BY Folder

 LET files = SELECT * FROM foreach(row=driver_dirs, query={
 SELECT OSPath, Name, Size
 FROM glob(globs="*", root=Folder, nosymlink="True")
 WHERE NOT IsDir AND NOT IsLink
 AND if(condition=SizeMin, then=Size &amp;gt;= SizeMin, else=True)
 AND if(condition=SizeMax, then=Size &amp;lt;= SizeMax, else=True)
 })

 LET vuln_results = SELECT * FROM if(condition=ScanVulnerabilityYaraRule,
 then={
 SELECT * FROM Scan(
 YaraRules=decoded_vuln_rule,
 Type="vulnerability",
 NumberOfHits=NumberOfHits
 )
 })

 LET vuln_uploads = SELECT *, upload(file=OSPath, name=OSPath) AS Upload FROM vuln_results

 SELECT * FROM if(condition=UploadMatches,
 then=vuln_uploads,
 else=vuln_results)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Kerberos.GoldenTicketTriage</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.kerberos.goldentickettriage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.kerberos.goldentickettriage/</guid><description>&lt;p&gt;It analyzes klist output to identify Kerberos tickets with unusually long lifetimes as well as tickets where the Kdc Called field is empty.&lt;/p&gt;
&lt;p&gt;It detects forged or abnormal Kerberos tickets by inspecting the local ticket cache and, optionally, session-specific caches.&lt;/p&gt;
&lt;p&gt;Golden Tickets often stand out due to their unusually long lifetimes and/or an empty Kdc Called field, since the TGT is generated offline rather than issued by a legitimate KDC.&lt;/p&gt;
&lt;p&gt;Within the artifact, you can configure a ticket lifetime threshold (for example, 1 year or more).&lt;/p&gt;
&lt;p&gt;Setting this value to 0 disables filtering and returns all ticket information.&lt;/p&gt;
&lt;p&gt;Additionally, there is an optional filter for FlagEmptyKdcCalled, which only triggers when FlagEmptyKdcCalled = true.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CacheTickets:
&lt;ul&gt;
&lt;li&gt;Runs &lt;code&gt;klist&lt;/code&gt; and parses ALL tickets (#0/#1/#2/&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SessionTickets:
&lt;ul&gt;
&lt;li&gt;Runs &lt;code&gt;klist sessions&lt;/code&gt; then tries &lt;code&gt;klist -li 0x&amp;lt;LogonId&amp;gt;&lt;/code&gt; for interactive user sessions&lt;/li&gt;
&lt;li&gt;Sessions that error (1314 / klist failed) are silently skippe&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TicketType:
&lt;ul&gt;
&lt;li&gt;TGT if Server starts with &amp;ldquo;krbtgt/&amp;rdquo;&lt;/li&gt;
&lt;li&gt;TGS otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Filtering:
&lt;ul&gt;
&lt;li&gt;MaxLifetimeYears = 0 -&amp;gt; no filtering (returns all tickets)&lt;/li&gt;
&lt;li&gt;Otherwise returns only suspicious tickets:
&lt;ul&gt;
&lt;li&gt;Long lifetime &amp;gt;= MaxLifetimeYears&lt;/li&gt;
&lt;li&gt;Empty &amp;ldquo;Kdc Called:&amp;rdquo; (only if FlagEmptyKdcCalled=true)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Kerberos.GoldenTicketTriage
author: Deniz Ciftci
description: |
 It analyzes klist output to identify Kerberos tickets with unusually long lifetimes as well as tickets where the Kdc Called field is empty.
 
 It detects forged or abnormal Kerberos tickets by inspecting the local ticket cache and, optionally, session-specific caches.
 
 Golden Tickets often stand out due to their unusually long lifetimes and/or an empty Kdc Called field, since the TGT is generated offline rather than issued by a legitimate KDC.
 
 Within the artifact, you can configure a ticket lifetime threshold (for example, 1 year or more). 
 
 Setting this value to 0 disables filtering and returns all ticket information. 
 
 Additionally, there is an optional filter for FlagEmptyKdcCalled, which only triggers when FlagEmptyKdcCalled = true.

 - CacheTickets:
 - Runs `klist` and parses ALL tickets (#0/#1/#2/...)
 - SessionTickets:
 - Runs `klist sessions` then tries `klist -li 0x&amp;lt;LogonId&amp;gt;` for interactive user sessions
 - Sessions that error (1314 / klist failed) are silently skippe
 - TicketType:
 - TGT if Server starts with "krbtgt/"
 - TGS otherwise
 - Filtering:
 - MaxLifetimeYears = 0 -&amp;gt; no filtering (returns all tickets)
 - Otherwise returns only suspicious tickets:
 * Long lifetime &amp;gt;= MaxLifetimeYears
 * Empty "Kdc Called:" (only if FlagEmptyKdcCalled=true)

type: CLIENT

parameters:
 - name: MaxLifetimeYears
 type: int
 default: 1
 description: Set 0 to return all tickets.

 - name: FlagEmptyKdcCalled
 type: bool
 default: true
 description: Flag empty "Kdc Called:".

required_permissions:
 - EXECVE

sources:
 - precondition:
 SELECT OS FROM info() WHERE OS = 'windows'
 name: CacheTickets
 query: |
 LET PS = '$ErrorActionPreference="SilentlyContinue";' +
 'function gf($b,$pat){$m=[regex]::Match($b,$pat);if($m.Success){$m.Groups[1].Value.Trim()}else{$null}};' +
 '$txt=(&amp;amp; klist 2&amp;gt;&amp;amp;1 | Out-String);' +
 '$logon="0x0"; if($txt -match "Current LogonId is 0:0x([0-9a-fA-F]+)"){ $logon=("0x"+$Matches[1]) };' +
 '$out=@();' +
 '$ms=[regex]::Matches($txt,"(?ms)^#(?&amp;lt;Idx&amp;gt;\d+)&amp;gt;\\s*(?&amp;lt;Block&amp;gt;.*?)(?=^#\\d+&amp;gt;|\\z)");' +
 'foreach($m in $ms){' +
 '$idx=[int]$m.Groups["Idx"].Value;' +
 '$b=$m.Groups["Block"].Value;' +
 '$client=gf $b "(?m)^\\s*Client:\\s*(.+?)\\s*$";' +
 '$server=gf $b "(?m)^\\s*Server:\\s*(.+?)\\s*$";' +
 '$enctype=gf $b "(?m)^\\s*KerbTicket Encryption Type:\\s*(.+?)\\s*$";' +
 '$flags=gf $b "(?m)^\\s*Ticket Flags\\s*(.+?)\\s*$";' +
 '$st=gf $b "(?m)^\\s*Start Time:\\s*(.+?)\\s*$";' +
 '$et=gf $b "(?m)^\\s*End Time:\\s*(.+?)\\s*$";' +
 '$rt=gf $b "(?m)^\\s*Renew Time:\\s*(.+?)\\s*$";' +
 '$kdc=gf $b "(?m)^\\s*Kdc Called:\\s*(.*?)\\s*$";' +

 '$days=$null; $hours=$null; $life=$null; $sy=$null; $ey=$null;' +
 'try{' +
 '$stc=($st -replace "\\s*\\(local\\)\\s*","").Trim();' +
 '$etc=($et -replace "\\s*\\(local\\)\\s*","").Trim();' +
 '$sd=[datetime]::Parse($stc);' +
 '$ed=[datetime]::Parse($etc);' +
 '$ts=($ed-$sd);' +
 '$days=[int]([math]::Floor($ts.TotalDays));' +
 '$hours=[int]([math]::Floor($ts.TotalHours));' +
 '$life = if($ts.TotalDays -ge 1){ "{0}d {1}h" -f $days, $ts.Hours } else { "{0}h {1}m" -f $ts.Hours, $ts.Minutes };' +
 '}catch{}' +
 'try{' +
 '$sy=[int]([regex]::Match($st,"(\\d{4})").Groups[1].Value);' +
 '$ey=[int]([regex]::Match($et,"(\\d{4})").Groups[1].Value);' +
 '}catch{}' +

 '$tt= if($server -match "^(?i)krbtgt/"){ "TGT" } else { "TGS" };' +
 '$out += [pscustomobject]@{' +
 'Source="CACHE";LogonIdHex=$logon;TicketType=$tt;TicketIndex=$idx;' +
 'Client=$client;Server=$server;EncType=$enctype;TicketFlags=$flags;' +
 'StartTime=$st;EndTime=$et;RenewTime=$rt;KdcCalled=$kdc;' +
 'LifetimeDays=$days;LifetimeHours=$hours;Lifetime=$life;' +
 'LifetimeYears=if($sy -ne $null -and $ey -ne $null){ ($ey-$sy) } else { $null }' +
 '};' +
 '};' +
 '$out | ConvertTo-Json -Compress'

 LET R = SELECT Stdout, Stderr, ExitStatus
 FROM execve(argv=['powershell.exe','-NoProfile','-NonInteractive','-ExecutionPolicy','Bypass','-Command', PS])

 LET J = SELECT row
 FROM foreach(row=R, query={
 SELECT row
 FROM foreach(row=parse_json(data=Stdout), query={ SELECT row FROM scope() })
 })

 SELECT
 row.Source AS Source,
 row.LogonIdHex AS LogonIdHex,
 row.TicketType AS TicketType,
 row.TicketIndex AS TicketIndex,
 row.Client AS Client,
 row.Server AS Server,
 row.EncType AS EncType,
 row.TicketFlags AS TicketFlags,
 row.StartTime AS StartTime,
 row.EndTime AS EndTime,
 row.RenewTime AS RenewTime,
 row.KdcCalled AS KdcCalled,

 row.LifetimeYears AS LifetimeYears,
 row.LifetimeDays AS LifetimeDays,
 row.LifetimeHours AS LifetimeHours,
 row.Lifetime AS Lifetime,

 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears)) AS Flag_LongLifetime,
 (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$')) AS Flag_EmptyKdcCalled,
 (
 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears))
 OR (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$'))
 ) AS Suspicious
 FROM J
 WHERE (MaxLifetimeYears = 0)
 OR (
 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears))
 OR (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$'))
 )

 - precondition:
 SELECT OS FROM info() WHERE OS = 'windows'
 name: SessionTickets
 query: |
 LET PS = '$ErrorActionPreference="SilentlyContinue";' +
 'function gf($b,$pat){$m=[regex]::Match($b,$pat);if($m.Success){$m.Groups[1].Value.Trim()}else{$null}};' +
 '$sess=(&amp;amp; klist sessions 2&amp;gt;&amp;amp;1 | Out-String);' +
 '$out=@();' +
 '$lines=$sess -split "`r?`n";' +
 'foreach($ln in $lines){' +
 'if($ln -notmatch "0:0x"){ continue };' +
 'if($ln -notmatch "Interactive"){ continue };' +
 'if($ln -notmatch "0:0x([0-9a-fA-F]+)"){ continue };' +
 '$luid=$Matches[1];' +
 '$user=""; if($ln -match "0:0x[0-9a-fA-F]+\\s+(.+?)\\s+\\S+:\\S+"){ $user=$Matches[1].Trim() };' +
 'if($user -notmatch "^[^\\\\]+\\\\[^\\\\]+$"){ continue };' +
 'if($user -match "\\$$"){ continue };' +
 'if($user -match "^NT AUTHORITY\\\\"){ continue };' +
 'if($user -match "^Window Manager\\\\"){ continue };' +
 'if($user -match "^Font Driver Host\\\\"){ continue };' +

 '$txt=(&amp;amp; cmd.exe /c ("klist -li 0x"+$luid) 2&amp;gt;&amp;amp;1 | Out-String);' +
 'if($txt -notmatch "Cached Tickets"){ continue };' +
 'if($txt -match "Error calling API"){ continue };' +
 'if($txt -match "klist failed"){ continue };' +

 '$logon=("0x"+$luid);' +
 '$ms=[regex]::Matches($txt,"(?ms)^#(?&amp;lt;Idx&amp;gt;\d+)&amp;gt;\\s*(?&amp;lt;Block&amp;gt;.*?)(?=^#\\d+&amp;gt;|\\z)");' +
 'foreach($m in $ms){' +
 '$idx=[int]$m.Groups["Idx"].Value;' +
 '$b=$m.Groups["Block"].Value;' +
 '$client=gf $b "(?m)^\\s*Client:\\s*(.+?)\\s*$";' +
 '$server=gf $b "(?m)^\\s*Server:\\s*(.+?)\\s*$";' +
 '$enctype=gf $b "(?m)^\\s*KerbTicket Encryption Type:\\s*(.+?)\\s*$";' +
 '$flags=gf $b "(?m)^\\s*Ticket Flags\\s*(.+?)\\s*$";' +
 '$st=gf $b "(?m)^\\s*Start Time:\\s*(.+?)\\s*$";' +
 '$et=gf $b "(?m)^\\s*End Time:\\s*(.+?)\\s*$";' +
 '$rt=gf $b "(?m)^\\s*Renew Time:\\s*(.+?)\\s*$";' +
 '$kdc=gf $b "(?m)^\\s*Kdc Called:\\s*(.*?)\\s*$";' +

 '$days=$null; $hours=$null; $life=$null; $sy=$null; $ey=$null;' +
 'try{' +
 '$stc=($st -replace "\\s*\\(local\\)\\s*","").Trim();' +
 '$etc=($et -replace "\\s*\\(local\\)\\s*","").Trim();' +
 '$sd=[datetime]::Parse($stc);' +
 '$ed=[datetime]::Parse($etc);' +
 '$ts=($ed-$sd);' +
 '$days=[int]([math]::Floor($ts.TotalDays));' +
 '$hours=[int]([math]::Floor($ts.TotalHours));' +
 '$life = if($ts.TotalDays -ge 1){ "{0}d {1}h" -f $days, $ts.Hours } else { "{0}h {1}m" -f $ts.Hours, $ts.Minutes };' +
 '}catch{}' +
 'try{' +
 '$sy=[int]([regex]::Match($st,"(\\d{4})").Groups[1].Value);' +
 '$ey=[int]([regex]::Match($et,"(\\d{4})").Groups[1].Value);' +
 '}catch{}' +

 '$tt= if($server -match "^(?i)krbtgt/"){ "TGT" } else { "TGS" };' +
 '$out += [pscustomobject]@{' +
 'Source="SESSIONS";LogonIdHex=$logon;TicketType=$tt;TicketIndex=$idx;' +
 'Client=$client;Server=$server;EncType=$enctype;TicketFlags=$flags;' +
 'StartTime=$st;EndTime=$et;RenewTime=$rt;KdcCalled=$kdc;' +
 'LifetimeDays=$days;LifetimeHours=$hours;Lifetime=$life;' +
 'LifetimeYears=if($sy -ne $null -and $ey -ne $null){ ($ey-$sy) } else { $null }' +
 '};' +
 '};' +
 '};' +
 '$out | ConvertTo-Json -Compress'

 LET R = SELECT Stdout, Stderr, ExitStatus
 FROM execve(argv=['powershell.exe','-NoProfile','-NonInteractive','-ExecutionPolicy','Bypass','-Command', PS])

 LET J = SELECT row
 FROM foreach(row=R, query={
 SELECT row
 FROM foreach(row=parse_json(data=Stdout), query={ SELECT row FROM scope() })
 })

 SELECT
 row.Source AS Source,
 row.LogonIdHex AS LogonIdHex,
 row.TicketType AS TicketType,
 row.TicketIndex AS TicketIndex,
 row.Client AS Client,
 row.Server AS Server,
 row.EncType AS EncType,
 row.TicketFlags AS TicketFlags,
 row.StartTime AS StartTime,
 row.EndTime AS EndTime,
 row.RenewTime AS RenewTime,
 row.KdcCalled AS KdcCalled,

 row.LifetimeYears AS LifetimeYears,
 row.LifetimeDays AS LifetimeDays,
 row.LifetimeHours AS LifetimeHours,
 row.Lifetime AS Lifetime,

 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears)) AS Flag_LongLifetime,
 (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$')) AS Flag_EmptyKdcCalled,
 (
 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears))
 OR (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$'))
 ) AS Suspicious
 FROM J
 WHERE (MaxLifetimeYears = 0)
 OR (
 ((MaxLifetimeYears &amp;gt; 0) AND (row.LifetimeYears &amp;gt;= MaxLifetimeYears))
 OR (FlagEmptyKdcCalled AND (row.KdcCalled = NULL OR row.KdcCalled =~ '^\\s*$'))
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.LastDomainUsers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.lastdomainusers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.lastdomainusers/</guid><description>&lt;p&gt;Enumerate Domain Users by creation date. This artifact can be used to quickly detect new domain accounts that may have been created by attackers. This artifact must be run on Domain Joined systems with the PowerShell Active Directory module installed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.LastDomainUsers
description: Enumerate Domain Users by creation date. This artifact can be used to quickly detect new domain accounts that may have been created by attackers. This artifact must be run on Domain Joined systems with the PowerShell Active Directory module installed.

author: AnthoLaMalice - Anthony Hannouille

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

sources:
 - query: | 
 LET cmdline = 'Get-ADUser -Filter {Enabled -eq $True} -Property Created, LastLogon | Select-Object Name, SAMAccountName, @{Name="Created";Expression={$_.Created.ToString("yyyy-MM-dd HH:mm:ss")}}, @{Name="LastLogon";Expression={if ($_.LastLogon) { [datetime]::FromFileTime($_.LastLogon).ToString("yyyy-MM-dd HH:mm:ss") } else { "Never Logged In" }}} | Sort-Object Created | ConvertTo-Json'
 SELECT * FROM foreach(
 row={
 SELECT Stdout FROM execve(argv=["Powershell", cmdline], length=104857600)
 }, query={
 SELECT * FROM parse_json_array(data=Stdout) where log(message=Stdout) AND log(message=Stderr)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Memory.HollowsHunter</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/hollowshunter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/hollowshunter/</guid><description>&lt;p&gt;Use hollows_hunter to detect suspicious process injections.&lt;/p&gt;
&lt;p&gt;Upload any findings to the server, including process dumps.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Memory.HollowsHunter
description: |
 Use hollows_hunter to detect suspicious process injections.

 Upload any findings to the server, including process dumps.

tools:
 - name: hollows_hunter
 github_project: hasherezade/hollows_hunter
 github_asset_regex: hollows_hunter64.exe
 serve_locally: true

precondition:
 SELECT OS From info() where OS = 'windows'
 
sources:
 - name: Output
 query: |
 -- Get the path to the hollows_hunter tool and a fresh temp directory.\
 LET TempDir &amp;lt;= tempdir(remove_last=TRUE)
 LET binaries &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(ToolName="hollows_hunter")

 -- Run the tool and relay back the output, as well as upload all the files from the tempdir.
 SELECT *
 FROM execve(argv=[binaries[0].FullPath,"/hooks",
 "/json", "/dir", TempDir], sep="\n")
 
 - name: Summary
 query: |
 LET LookupPid(pid) = SELECT Name, CommandLine, Exe FROM pslist(pid=pid)

 SELECT *, LookupPid(pid=pid)[0] AS ProcessInfo
 FROM foreach(row=parse_json(
 data=read_file(filename=TempDir + "/summary.json")).suspicious) 
 
 - name: Uploads
 query: |
 SELECT upload(file=FullPath) AS Upload
 FROM glob(globs="*", root=TempDir)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Memory.InjectedThreadEx</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/injectedthreadex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/injectedthreadex/</guid><description>&lt;p&gt;This artifact runs Get-InjetedThreadEx to detect process injection and hooking.&lt;/p&gt;
&lt;p&gt;The artifact uses environment variables to configure the scan and outputs
parsed fields, as well as a raw section. Some of the scanning options include:
Default, Brief and Aggressive. The User can also target a specific ProcessId.&lt;/p&gt;
&lt;p&gt;For all process scanning the recommendation would be first run in brief mode,
then add more aggressive scanning as required. The default timeout has been
increased significantly to cover aggressive scanning mode.&lt;/p&gt;
&lt;p&gt;IMPORTANT NOTES::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this query is complex powershell. Run it after a scriptblock hunt as it
will generate scriptblock logs, even if not configured.&lt;/li&gt;
&lt;li&gt;Some EPP/EDR tools may block the scriptblock execution, please ensure
exclusions are made for velociraptor child powershell processes.&lt;/li&gt;
&lt;li&gt;The default output for Default and Aggressive scan excludes Thread User
information, however this can be confired by the field IsUniqueThreadToken
and if &amp;lsquo;True&amp;rsquo; checked in raw data in the Windows.Memory.InjectedThreadEx/RawResults
namespace.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Memory.InjectedThreadEx
author: "Matt Green - @mgreen27"
description: |
 This artifact runs Get-InjetedThreadEx to detect process injection and hooking.

 The artifact uses environment variables to configure the scan and outputs 
 parsed fields, as well as a raw section. Some of the scanning options include: 
 Default, Brief and Aggressive. The User can also target a specific ProcessId.

 For all process scanning the recommendation would be first run in brief mode, 
 then add more aggressive scanning as required. The default timeout has been 
 increased significantly to cover aggressive scanning mode. 

 IMPORTANT NOTES::
 
 - this query is complex powershell. Run it after a scriptblock hunt as it 
 will generate scriptblock logs, even if not configured.
 - Some EPP/EDR tools may block the scriptblock execution, please ensure 
 exclusions are made for velociraptor child powershell processes. 
 - The default output for Default and Aggressive scan excludes Thread User 
 information, however this can be confired by the field IsUniqueThreadToken 
 and if 'True' checked in raw data in the Windows.Memory.InjectedThreadEx/RawResults 
 namespace.

reference:
 - https://www.elastic.co/security-labs/get-injectedthreadex-detection-thread-creation-trampolines
type: CLIENT
resources:
 timeout: 6000

tools:
 - name: Get-InjectedThreadEx
 url: https://gist.githubusercontent.com/mgreen27/b37467aa725e0445d966c9589c90381a/raw/a3f8ac05fead58f5ba9465da67ae5881576b1762/Get-InjectedThreadEx.ps1

parameters:
 - name: TargetPid
 type: int
 description: Pid to pass through to tool. Default no entry scans all Pids, only one specific Pid can be added at a time.
 - name: ScanType
 type: choices
 description: Select memory permission you would like to return. Default All.
 default: Default
 choices:
 - Default
 - Brief
 - Aggressive


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

sources:
 - query: |
 -- Get the path to the Get-InjectedThread tool
 LET script &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="Get-InjectedThreadEx",
 IsExecutable='N'
 )
 LET scan_type = if(condition= ScanType='Default', 
 then= '',
 else= ScanType)
 LET target_pid = if(condition= TargetPid=0, then='', else= TargetPid)

 -- Run the tool and relay back the output
 LET results &amp;lt;= SELECT *,
 parse_string_with_regex(
 string=Stdout,
 regex=['''ProcessName\s+:\s+(?P&amp;lt;ProcessName&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessId\s+:\s+(?P&amp;lt;ProcessId&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessLogonId\s+:\s+(?P&amp;lt;ProcessLogonId&amp;gt;\d*)\s+\w+\s+:''',
 '''\s+Wow64\s+:\s+(?P&amp;lt;Wow64&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+Path\s+:\s+(?P&amp;lt;Path&amp;gt;[ -~]*)\s+\w+\s+:''',
 '''\s+KernelPath\s+:\s+(?P&amp;lt;KernelPath&amp;gt;[ -~]*)\s+\w+\s+:''',
 '''\s+CommandLine\s+:\s+(?P&amp;lt;CommandLine&amp;gt;[ -~]*)\s+\w+\s+:''',
 '''\s+PathMismatch\s+:\s+(?P&amp;lt;PathMismatch&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessIntegrity\s+:\s+(?P&amp;lt;ProcessIntegrity&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessPrivilege\s+:\s+(?P&amp;lt;ProcessPrivilege&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessLogonId\s+:\s+(?P&amp;lt;ProcessLogonId&amp;gt;\d*)\s+\w+\s+:''',
 '''\s+ProcessSecurityIdentifier\s+:\s+(?P&amp;lt;ProcessSecurityIdentifier&amp;gt;[S\d\-]*)\s+\w+\s+:''',
 '''\s+ProcessUserName\s+:\s+(?P&amp;lt;ProcessUserName&amp;gt;[ -~]*)\s\s+\w+\s+:''',
 '''\s+ProcessLogonSessionStartTime\s+:\s+(?P&amp;lt;ProcessLogonSessionStartTime&amp;gt;[\d:/ ]*\w{2})\s+\w+\s+:''',
 '''\s+ProcessLogonType\s+:\s+(?P&amp;lt;ProcessLogonType&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ProcessAuthenticationPackage\s+:\s+(?P&amp;lt;ProcessAuthenticationPackage&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadId\s+:\s+(?P&amp;lt;ThreadId&amp;gt;\d*)\s+\w+\s+:''',
 '''\s+ThreadStartTime\s+:\s+(?P&amp;lt;ThreadStartTime&amp;gt;[\d:/ ]*\w{2})\s+\w+\s+:''',
 '''\s+BasePriority\s+:\s+(?P&amp;lt;BasePriority&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+WaitReason\s+:\s+(?P&amp;lt;WaitReason&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+IsUniqueThreadToken\s+:\s+(?P&amp;lt;IsUniqueThreadToken&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadIntegrity\s+:\s+(?P&amp;lt;ThreadIntegrity&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+AdditionalThreadPrivilege\s+:\s+(?P&amp;lt;AdditionalThreadPrivilege&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadLogonId\s+:\s+(?P&amp;lt;ThreadLogonId&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadSecurityIdentifier\s+:\s+(?P&amp;lt;ThreadSecurityIdentifier&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadUserName\s+:\s+(?P&amp;lt;ThreadUserName&amp;gt;.*)\s+\w+\s+:''',
 '''\s+ThreadLogonSessionStartTime\s+:\s+(?P&amp;lt;ThreadLogonSessionStartTime&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadLogonType\s+:\s+(?P&amp;lt;ThreadLogonType&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+ThreadAuthenticationPackage\s+:\s+(?P&amp;lt;ThreadAuthenticationPackage&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+AllocatedMemoryProtection\s+:\s+(?P&amp;lt;AllocatedMemoryProtection&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+MemoryProtection\s+:\s+(?P&amp;lt;MemoryProtection&amp;gt;[\w_]*)\s+\w+\s+:''',
 '''\s+MemoryState\s+:\s+(?P&amp;lt;MemoryState&amp;gt;[\w_]*)\s+\w+\s+:''',
 '''\s+MemoryType\s+:\s+(?P&amp;lt;MemoryType&amp;gt;[\w_]*)\s+\w+\s+:''',
 '''\s+Win32StartAddress\s+:\s+(?P&amp;lt;Win32StartAddress&amp;gt;[0-9A-F]*)\s+\w+\s+:''',
 '''\s+Win32StartAddressModule\s+:\s+(?P&amp;lt;Win32StartAddressModule&amp;gt;[ -~]*)\s+\w+\s+:''',
 '''\s+Win32StartAddressModuleSigned\s+:\s+(?P&amp;lt;Win32StartAddressModuleSigned&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+Win32StartAddressPrivate\s+:\s+(?P&amp;lt;Win32StartAddressPrivate&amp;gt;[^\s]*)\s+\w+\s+:''',
 '''\s+Size\s+:\s+(?P&amp;lt;Size&amp;gt;\d*)\s+\w+\s+:''',
 '''\s+TailBytes\s+:\s+(?P&amp;lt;TailBytes&amp;gt;[0-9A-F]*)\s+''',
 '''\s+StartBytes\s+:\s+(?P&amp;lt;StartBytes&amp;gt;[0-9A-F]*)''',
 '''\s+Detections\s+:\s+(?P&amp;lt;Detections&amp;gt;.*)$'''
 ]) as Parsed 
 FROM execve(argv=['powershell','-ExecutionPolicy','Unrestricted','-NoProfile','-File',script.FullPath[0]],
 env=dict(
 `GetInjectedThreadScan` = scan_type,
 `GetInjectedThreadTarget` = str(str=target_pid) ),
 sep='\r\n\r\n')
 WHERE Stdout
 

 -- output rows
 --SELECT * FROM foreach(row=results.Parsed) WHERE NOT Stdout =~ '^WARNING'
 SELECT * FROM column_filter(
 query={ 
 SELECT * FROM foreach(row=results.Parsed) 
 WHERE NOT Stdout =~ '^WARNING'
 },
 exclude=['ThreadIntegrity','AdditionalThreadPrivilege','ThreadLogonId','ThreadSecurityIdentifier',
 'ThreadUserName','ThreadLogonSessionStartTime','ThreadLogonType','ThreadAuthenticationPackage']
 )
 
 - name: RawResults
 queries:
 - |
 SELECT Stdout, Stderr, ReturnCode, Complete,
 dict( ScanType = scan_type,
 PidTarget = str(str=target_pid) ) as ScanSettings
 FROM results
 
 
column_types:
 - name: ProcessLogonSessionStartTime
 type: timestamp
 - name: ThreadStartTime
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Memory.Mem2Disk</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.memory.mem2disk/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.memory.mem2disk/</guid><description>&lt;p&gt;This artifact compares executables in memory (RAM) with those
on hard disk. This way, RAM injections are detected. This rarely
happens legitimately and is mostly used by malware.
This check is executed without dumping the memory and works live
on the target system(s).
See also &lt;a href="https://github.com/lautarolecumberry/DetectingFilelessMalware" target="_blank" &gt;https://github.com/lautarolecumberry/DetectingFilelessMalware&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;(Ignored) False Positives&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ASLR&lt;/code&gt;: If jumps or comparisons are not relative and Address Space Layout Randomization
(ASLR) is enabled, then addresses within these jumps are adjusted in RAM
with a constant offset. This offset can be computed and ignored.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BaseOfData&lt;/code&gt;: Relative Virtual Adresses (RVA) cause an offset in the code in memory of a
32-bit process. This is the case when the field BaseOfData is set.
Like ASLR it is a constant offset that is added to addresses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Test this artifact using &lt;code&gt;AMSIBypassPatch.ps1&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Memory.Mem2Disk
author: Lautaro Lecumberry, Dr. Michael Denzel
description: |
 This artifact compares executables in memory (RAM) with those
 on hard disk. This way, RAM injections are detected. This rarely
 happens legitimately and is mostly used by malware.
 This check is executed without dumping the memory and works live
 on the target system(s).
 See also https://github.com/lautarolecumberry/DetectingFilelessMalware

 (Ignored) False Positives
 - `ASLR`: If jumps or comparisons are not relative and Address Space Layout Randomization
 (ASLR) is enabled, then addresses within these jumps are adjusted in RAM
 with a constant offset. This offset can be computed and ignored.
 - `BaseOfData`: Relative Virtual Adresses (RVA) cause an offset in the code in memory of a
 32-bit process. This is the case when the field BaseOfData is set.
 Like ASLR it is a constant offset that is added to addresses.

 Test this artifact using `AMSIBypassPatch.ps1`

references:
 - https://github.com/okankurtuluss/AMSIBypassPatch/blob/090b54a518fecf1ccf8f54f8691805ef0f9a30f1/AMSIBypassPatch.ps1

parameters:
- name: UploadFindings
 description: Upload all executables where code in memory does not match code on disk. This
 can potentially generate a lot of traffic. Dry-run before enabling this option.
 default: False
 type: bool
- name: ProcessNameFilter
 type: regex
 default: .
- name: PidFilter
 default: .
 type: regex
- name: ModuleRegEx
 type: regex
 description: Filter for modules to check. If you want to scan all modules (i.e. libraries) within
 a binary, replace with `.*`. The default parameter checks the original binary itself (.exe)
 as well as kernelbase.dll, ntdll.dll, user32.dll, kernel32.dll, shell32.dll, msvcrt.dll,
 advapi32.dll, and comdlg32.dll (i.e. commonly injected libraries).
 default: "\\.exe$|(KERNELBASE|ntdll|amsi|user32|kenrel32|shell32|msvcrt|advapi32|comdlg32)\\.dll$"
- name: Workers
 type: int
 default: "5"
 description: "Number of parallel workers to use"

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

export: |
 -- These functions help to resolve the Kernel Device Filenames
 -- into a regular filename with drive letter.
 LET DriveReplaceLookup &amp;lt;= SELECT
 split(sep_string="\\", string=Name)[-1] AS Drive,
 upcase(string=SymlinkTarget) AS Target,
 len(list=SymlinkTarget) AS Len
 FROM winobj()
 WHERE Name =~ "^\\\\GLOBAL\\?\\?\\\\.:"

 LET _DriveReplace(Path) = SELECT Drive + Path[Len:] AS ResolvedPath
 FROM DriveReplaceLookup
 WHERE upcase(string=Path[:Len]) = Target

 LET DriveReplace(Path) = _DriveReplace(Path=Path)[0].ResolvedPath ||
 Path

sources:
- query: |
 -- get all processes
 LET GetPids = SELECT Pid,
 Name,
 Username,
 if(condition=IsWow64, then=4, else=8) AS IntSize
 FROM pslist()
 WHERE Name =~ ProcessNameFilter
 AND format(format="%d", args=Pid) =~ PidFilter

 -- get all memory pages for a certain pid
 LET InfoFromVad(Pid) = SELECT Address,
 Size,
 DriveReplace(Path=MappingName) AS Path
 FROM vad(pid=Pid)
 WHERE MappingName
 AND Protection =~ "xr-"
 AND MappingName =~ ModuleRegEx

 LET GetTextSegment(Path) = filter(condition="x=&amp;gt;x.Name = '.text'",
 list=parse_pe(file=Path).Sections)[0]

 -- parse the executable (PE) from memory (specifically, the text segment)
 LET GetMetadata(Pid) = SELECT
 Path,
 str(str=Pid) AS PidFilename,
 Address,
 GetTextSegment(Path=Path) AS TextSegmentData
 FROM InfoFromVad(Pid=Pid)
 WHERE Address != 0
 AND TextSegmentData.FileOffset

 -- helper function for formating
 LET Hex(X) = format(format="%#x", args=X)

 LET Int64(X) = parse_binary(profile="",
 struct="int64",
 accessor="data",
 filename=X)

 -- ASLR may be shifted due to alignment.
 -- This is OK so the following values are allowed.
 LET CalculateAllowedASLR(ASLR) = SELECT *
 FROM foreach(row={
 SELECT format(format="00" * 7 + "%08x" + "00" * 8, args=ASLR) AS Data
 FROM scope()
 }, query={
 SELECT int(int="0x" + Data[_value:(_value + 16)]) AS Allowed
 FROM range(start=0, end=22, step=2)
 })

 -- read the executable from memory and hard disk
 LET GetContent(Pid, Name) = SELECT
 *,
 Name,
 Path,
 Address AS MemAddress,
 TextSegmentData.RVA AS BaseRVA,
 --calculate ASLR offset to later filter it out
 Address - TextSegmentData.VMA AS ASLR,

 CalculateAllowedASLR(ASLR=Address - TextSegmentData.VMA).Allowed AS AllowedASLR,
 read_file(accessor="process",
 offset=Address,
 filename=PidFilename,
 length=TextSegmentData.Size) AS MemoryData,
 TextSegmentData.FileOffset AS DiskAddress,
 TextSegmentData.Size AS SegmentSize,
 read_file(accessor="file",
 offset=TextSegmentData.FileOffset,
 filename=Path,
 length=TextSegmentData.Size) AS DiskData
 FROM GetMetadata(Pid=Pid)
 WHERE MemoryData
 AND log(dedup=-1,
 message="Inspecting Pid %v (%v): %#x-%#x vs %#x-%#x in %v",
 args=[Pid, Name, Address, Address + SegmentSize,
 DiskAddress, DiskAddress + SegmentSize, Path])

 LET FilterContent(Pid, Name) = SELECT *
 MemoryData = DiskData AS Comparison
 FROM GetContent(Pid=Pid, Name=Name)

 -- Filter out not needed comparisons early
 WHERE NOT Comparison

 -- parameter for start PAGESIZE; compare 1 MB pages first
 LET PAGESIZE &amp;lt;= 1024 * 1024

 -- helper function for comparisons of PAGESIZE
 LET _CompareRegions(Base, X, Y, PAGESIZE) = SELECT
 _value + Base AS Offset,
 X[_value:(_value + PAGESIZE)] AS XInt,
 Y[_value:(_value + PAGESIZE)] AS YInt
 FROM range(end=len(list=X), step=PAGESIZE)
 WHERE XInt != YInt

 -- compare full pages (to speed up comparison)
 -- for each 1 MB page which does not match
 -- compare 4096 B page
 -- for each 4096 B page which does not match
 -- compare single integers
 LET CompareRegions(X, Y, IntSize) = SELECT
 Offset,
 Hex(X=XInt) AS X,
 Hex(X=YInt) AS Y,
 Int64(X=XInt) AS ValueX,
 Int64(X=YInt) AS ValueY
 FROM foreach(row={
 -- 1 MB pages
 SELECT *
 FROM _CompareRegions(Base=0, X=X, Y=Y, PAGESIZE=PAGESIZE)
 },
 query={
 SELECT *
 FROM foreach(row={
 -- 4096 B pages
 SELECT *
 FROM _CompareRegions(Base=Offset, X=XInt, Y=YInt, PAGESIZE=4096)
 },
 query={
 -- single integers
 SELECT *
 FROM _CompareRegions(Base=Offset, X=XInt, Y=YInt, PAGESIZE=IntSize)
 })
 })
 LIMIT 500

 -- check if offsets between X and Y (i.e. RAM and disk) are
 -- always the same offset. Then it is ASLR or BaseOfData.
 LET CompareUniqueRegions(X, Y, IntSize, ASLR) = SELECT *,
 ValueX - ValueY AS Difference
 FROM CompareRegions(X=X, Y=Y, IntSize=IntSize)
 WHERE ValueX AND NOT Difference IN AllowedASLR
 GROUP BY Difference

 LET DescribeAddress(rva, module) = version(function="describe_address") != NULL &amp;amp;&amp;amp;
 describe_address(rva=rva, module=module).func

 -- compare the executable from memory and hard disk
 -- only print the ones where they do not match
 LET Compare(Pid, Name, IntSize) =
 SELECT Pid,
 Name,
 Path,
 ASLR,
 {
 SELECT Offset + BaseRVA AS RVA,
 Offset AS TextOffset,
 DescribeAddress(rva= Offset + BaseRVA, module=Path) AS Func,
 X AS MemoryValue,
 Y AS DiskValue,
 Hex(X=Difference) AS Difference,
 Hex(X=ASLR) AS ASLR
 FROM CompareUniqueRegions(
 X=MemoryData,
 Y=DiskData,
 IntSize=IntSize,
 ASLR=ASLR)
 } AS Differences,
 MemAddress,
 DiskAddress,
 SegmentSize
 FROM FilterContent(Pid=Pid, Name=Name)
 WHERE Differences AND log(dedup=-1,
 message="Comparing process %v - %v", args=[Pid, Name])

 -- compare with uploading the suspicious executables
 LET CompareAndUpload(Pid, Name, IntSize) = SELECT
 Pid,
 Name,
 Path,
 ASLR,
 MemAddress,
 DiskAddress,
 SegmentSize,
 upload(
 file=pathspec(DelegateAccessor="process",
 DelegatePath=PidFilename,
 Path=[dict(Offset=MemAddress, Length=SegmentSize), ]),
 name=pathspec(parse=format(format="%s.%d.mem", args=[Path, Pid]),
 path_type="windows"),
 accessor="sparse") AS UploadMem,
 upload(
 file=pathspec(DelegateAccessor="file",
 DelegatePath=Path,
 Path=[dict(Offset=DiskAddress, Length=SegmentSize), ]),
 name=pathspec(parse=format(format="%s.%d.disk", args=[Path, Pid]),
 path_type="windows"),
 accessor="sparse") AS UploadDisk,
 Differences
 FROM Compare(Pid=Pid, Name=Name, IntSize=IntSize)

 -- for every process, evaluate the memory-harddisk-comparison
 SELECT *,
 Hex(X=MemAddress) AS MemAddress,
 Hex(X=DiskAddress) AS DiskAddress,
 Hex(X=SegmentSize) AS SegmentSize
 FROM foreach(row=GetPids,
 workers=Workers,
 query={
 SELECT *
 FROM if(condition=UploadFindings,
 then={
 SELECT *
 FROM CompareAndUpload(Pid=Pid, Name=Name, IntSize=IntSize)
 },
 else={
 SELECT *
 FROM Compare(Pid=Pid, Name=Name, IntSize=IntSize)
 })
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.MobaXterm.Passwords</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/custom.windows.mobaxterm.passwords/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/custom.windows.mobaxterm.passwords/</guid><description>&lt;p&gt;Extract MobaXterm encrypted saved Master Passwords, Passwords and Credentials from registry.
Further information regarding decryption can be found here: &lt;a href="https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/" target="_blank" &gt;https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.MobaXterm.Passwords
author: "Yaron King - @Sam0rai"
description: |
 Extract MobaXterm encrypted saved Master Passwords, Passwords and Credentials from registry.
 Further information regarding decryption can be found here: https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/

type: CLIENT

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: SearchRegistryGlob
 default: HKEY_USERS\\S-1-5-21-*\\SOFTWARE\\Mobatek\MobaXterm\\{M,P,C}\\**
 description: Use a glob to define the registry path to search for saved (M)aster passwords, (P)asswords and (C)redentials.

sources:
 - query: |
 SELECT Data.value as EncryptedCreds, FullPath, ModTime
 FROM glob(globs=SearchRegistryGlob, accessor='reg')

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Monitor.USBPlugIn</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/usbplugin/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/usbplugin/</guid><description>&lt;p&gt;Monitor for plug in of USB volume. Output drive letter for
additional enrichment artifacts&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Monitor.USBPlugIn
description: |
 Monitor for plug in of USB volume. Output drive letter for
 additional enrichment artifacts

type: CLIENT_EVENT

sources:
 - query: |
 SELECT
 timestamp(winfiletime=int(int=Parse.TIME_CREATED)) as TimeCreated,
 Parse.DriveName as DriveName,
 Parse.EventType as EventType,
 Parse.__Type as Source,
 Raw
 FROM wmi_events(
 query="SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2",
 namespace="ROOT/CIMV2",
 wait=50000000)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Monitoring.PrintNightmare</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/printnightmaremonitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/printnightmaremonitor/</guid><description>&lt;p&gt;This artifact returns ETW PrintService events for potential
PrintNightmare activity. CVE-2021-1675 and CVE-2021-34527&lt;/p&gt;
&lt;p&gt;It monitors for DRIVER_ADDED events and enriches with binary
information for payload DataFile. Hunt for unexpected drivers with
malicious DataFiles.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Monitoring.PrintNightmare
author: Matt Green - @mgreen27
description: |
 This artifact returns ETW PrintService events for potential
 PrintNightmare activity. CVE-2021-1675 and CVE-2021-34527

 It monitors for DRIVER_ADDED events and enriches with binary
 information for payload DataFile. Hunt for unexpected drivers with
 malicious DataFiles.

type: CLIENT_EVENT
sources:
 - query: |
 -- Monitor ETW provider and extract enriched target events
 LET hits = SELECT
 System.TimeStamp AS EventTime,
 "Microsoft-Windows-PrintService" as Provider,
 System.ID as EventId,
 'DRIVER_ADDED' as Action,
 EventData,
 {
 SELECT
 split(string=Name, sep=',')[0] as Name,
 SupportedPlatform,
 Version,
 DriverPath,
 ConfigFile,
 DataFile
 FROM wmi(query='SELECT * FROM Win32_PrinterDriver',namespace='root/CIMV2')
 WHERE Name = EventData.param1
 } as DriverInformation
 FROM watch_etw(guid="{747EF6FD-E535-4D16-B510-42C90F6873A1}",
 name=format(format="Velociraptor-%v-PrintService", args=now()))
 WHERE EventId = 316

 -- output rows and final binary enrichment
 SELECT
 EventTime,
 Provider,
 EventId,
 Action,
 EventData.param1 as Name,
 EventData.param2 as Platform,
 DriverInformation.Version as Version,
 if(condition=DriverInformation,
 then= dict(
 DriverPath=DriverInformation.DriverPath,
 ConfigFile=DriverInformation.ConfigFile,
 DataFile=DriverInformation.DataFile),
 else= EventData.param4) as Files,
 hash(path=DriverInformation.DataFile) as DataFileHash,
 parse_pe(file=DriverInformation.DataFile) as DataFilePE,
 authenticode(filename=DriverInformation.DataFile) as DataFileAuthenticode
 FROM hits

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Mounted.Mass.Storage</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.mounted.mass.storage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.mounted.mass.storage/</guid><description>&lt;p&gt;Find drives/usb mass storage that were mounted&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Mounted.Mass.Storage
author: "Yaniv Radunsky &amp;amp; Kobi Arami @ 10root cyber security"
description: |
 Find drives/usb mass storage that were mounted


parameters:
 - name: programKeys
 default: &amp;gt;-
 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*


sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'
 queries:
 - |
 SELECT Key.Name as KeyName,
 Key.Mtime AS KeyLastWriteTimestamp,
 FriendlyName,
 HardwareID
 FROM read_reg_key(globs=split(string=programKeys, sep=',[\\s]*'),
 accessor="registry")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Nirsoft.LastActivityView</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.nirsoft.lastactivityview/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.nirsoft.lastactivityview/</guid><description>&lt;p&gt;LastActivityView is a tool for Windows operating system that
collects information from various sources on a running system, and
displays a log of actions made by the user and events occurred on
this computer. The activity displayed by LastActivityView includes:
Running .exe file, Opening open/save dialog-box, Opening file/folder
from Explorer or other software, software installation, system
shutdown/start, application or system crash, network
connection/disconnection and more&amp;hellip;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Nirsoft.LastActivityView
description: |
 LastActivityView is a tool for Windows operating system that
 collects information from various sources on a running system, and
 displays a log of actions made by the user and events occurred on
 this computer. The activity displayed by LastActivityView includes:
 Running .exe file, Opening open/save dialog-box, Opening file/folder
 from Explorer or other software, software installation, system
 shutdown/start, application or system crash, network
 connection/disconnection and more...

author: Yaniv Radunsky @ 10rootCyberSecurity

tools:
 - name: lastactivityview
 url: https://www.nirsoft.net/utils/lastactivityview.zip

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

sources:
 - name: Upload
 query: |

 LET Hostname &amp;lt;= SELECT Hostname as Host FROM info()

 -- Fetch the binary
 LET Toolzip &amp;lt;= SELECT FullPath
 FROM Artifact.Generic.Utils.FetchBinary(
 ToolName="lastactivityview", IsExecutable=FALSE)

 LET TmpDir &amp;lt;= tempdir()

 -- Unzip the binary
 LET _ &amp;lt;= SELECT * FROM unzip(filename=Toolzip.FullPath, output_directory=TmpDir)

 -- Set EXE
 LET LastActivityViewExe &amp;lt;= TmpDir + '\\LastActivityView.exe'

 -- Build the exec command
 LET LastActivityViewCmd &amp;lt;= filter(list=(LastActivityViewExe, "/scomma", TmpDir + "\\" + Hostname.Host[0] + "-LastActivityView.csv" )
 , regex=".+")

 -- Run the tool.
 LET ExecLastActivityView &amp;lt;= SELECT *
 FROM execve(argv=LastActivityViewCmd,sep="\n", length=10000)

 -- Upload CSV to the hunt
 LET Upload &amp;lt;= SELECT Name, upload(file=FullPath,name=relpath(base=TmpDir + Hostname.Host[0] + "-LastActivityView.csv", path=FullPath)) as FileDetails
 FROM glob(globs="/**", root=TmpDir)
 WHERE Name =~ "(csv)$"

 -- Parse CSV to Notebook
 SELECT * FROM parse_csv(filename= TmpDir + "\\" + Hostname.Host[0] + "-LastActivityView.csv")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.NTFS.MFT.HiveNightmare</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.ntfs.mft.hivenightmare/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.ntfs.mft.hivenightmare/</guid><description>&lt;p&gt;This artifact uses Windows.NTFS.MFT (By Matt Green - @mgreen27) to
find several files created as part of the POC tooling for
HiveNightmare (CVE-2021-36934):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;\hive_sam_ - &lt;a href="https://github.com/FireFart/hivenightmare" target="_blank" &gt;https://github.com/FireFart/hivenightmare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;\SAM-20 - &lt;a href="https://github.com/GossiTheDog/HiveNightmare" target="_blank" &gt;https://github.com/GossiTheDog/HiveNightmare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;\SAM-haxx - &lt;a href="https://github.com/GossiTheDog/HiveNightmare" target="_blank" &gt;https://github.com/GossiTheDog/HiveNightmare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;\Sam.save - PowerShell version&lt;/li&gt;
&lt;li&gt;\Sam.hive - &lt;a href="https://github.com/WiredPulse/Invoke-HiveNightmare" target="_blank" &gt;https://github.com/WiredPulse/Invoke-HiveNightmare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;C:\windows\temp\sam - &lt;a href="https://github.com/cube0x0/CVE-2021-36934" target="_blank" &gt;https://github.com/cube0x0/CVE-2021-36934&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See Florian Roth&amp;rsquo;s rule here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/SigmaHQ/sigma/blob/master/rules/windows/file_event/win_hivenightmare_file_exports.yml" target="_blank" &gt;https://github.com/SigmaHQ/sigma/blob/master/rules/windows/file_event/win_hivenightmare_file_exports.yml&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.NTFS.MFT.HiveNightmare
description: |
 This artifact uses Windows.NTFS.MFT (By Matt Green - @mgreen27) to
 find several files created as part of the POC tooling for
 HiveNightmare (CVE-2021-36934):

 - \hive_sam_ - https://github.com/FireFart/hivenightmare
 - \SAM-20 - https://github.com/GossiTheDog/HiveNightmare
 - \SAM-haxx - https://github.com/GossiTheDog/HiveNightmare
 - \Sam.save - PowerShell version
 - \Sam.hive - https://github.com/WiredPulse/Invoke-HiveNightmare
 - C:\windows\temp\sam - https://github.com/cube0x0/CVE-2021-36934

 See Florian Roth's rule here:
 - https://github.com/SigmaHQ/sigma/blob/master/rules/windows/file_event/win_hivenightmare_file_exports.yml

author: "Zach Stanford - @svch0st"

parameters:
 - name: MFTFilename
 default: "C:/$MFT"
 - name: Accessor
 default: ntfs
 - name: PathRegex
 description: "Regex search over FullPath."
 default: "Windows/Temp/sam$"
 - name: FileRegex
 description: "Regex search over File Name"
 default: "^(hive_sam_|SAM-2021-|SAM-2022-|SAM-haxx$|Sam.save$|Sam.hive$)"
 - 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 under this size in bytes."
 - name: SizeMin
 type: int64
 description: "Entries in the MFT over this size in bytes."
 - name: AllDrives
 type: bool
 description: "Select MFT search on all attached ntfs drives."


sources:
 - query: |
 -- firstly set timebounds for performance
 LET DateAfterTime &amp;lt;= if(condition=DateAfter,
 then=DateAfter, else="1600-01-01")
 LET DateBeforeTime &amp;lt;= if(condition=DateBefore,
 then=DateBefore, else="2200-01-01")
 -- find all ntfs drives
 LET ntfs_drives = SELECT FullPath + '/$MFT'as Path
 FROM glob(globs="/*", accessor="ntfs")
 -- function returning MFT entries
 LET mftsearch(MFTPath) = SELECT EntryNumber,InUse,ParentEntryNumber,
 MFTPath,FullPath,FileName,FileSize,ReferenceCount,IsDir,
 Created0x10,Created0x30,LastModified0x10,LastModified0x30,
 LastRecordChange0x10,LastRecordChange0x30,LastAccess0x10,LastAccess0x30
 FROM parse_mft(filename=MFTPath, accessor=Accessor)
 WHERE FullPath =~ PathRegex OR FileName =~ FileRegex
 AND Created0x10 &amp;lt; DateBeforeTime
 AND Created0x10 &amp;gt; DateAfterTime
 AND Created0x30 &amp;lt; DateBeforeTime
 AND Created0x30 &amp;gt; DateAfterTime
 AND LastModified0x10 &amp;lt; DateBeforeTime
 AND LastModified0x10 &amp;gt; DateAfterTime
 AND LastModified0x30 &amp;lt; DateBeforeTime
 AND LastModified0x30 &amp;gt; DateAfterTime
 AND LastRecordChange0x10 &amp;lt; DateBeforeTime
 AND LastRecordChange0x10 &amp;gt; DateAfterTime
 AND LastRecordChange0x30 &amp;lt; DateBeforeTime
 AND LastRecordChange0x30 &amp;gt; DateAfterTime
 AND LastAccess0x10 &amp;lt; DateBeforeTime
 AND LastAccess0x10 &amp;gt; DateAfterTime
 AND LastAccess0x30 &amp;lt; DateBeforeTime
 AND LastAccess0x30 &amp;gt; DateAfterTime
 AND if(condition=SizeMax,
 then=FileSize &amp;lt; atoi(string=SizeMax),
 else=TRUE)
 AND if(condition=SizeMin,
 then=FileSize &amp;gt; atoi(string=SizeMin),
 else=TRUE)
 -- include all attached drives
 LET all_drives = SELECT * FROM foreach(row=ntfs_drives,
 query={
 SELECT *
 FROM mftsearch(MFTPath=Path)
 WHERE log(message="Processing " + Path)
 })
 -- return rows
 SELECT * FROM if(condition=AllDrives,
 then= all_drives,
 else= {
 SELECT * FROM mftsearch(MFTPath=MFTFilename)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.NTFS.Timestomp</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/timestomp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/timestomp/</guid><description>&lt;p&gt;This artifact enables triage to detect potential time stomped files.&lt;/p&gt;
&lt;p&gt;Checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$STANDARD_INFORMATION “B” time prior to $FILE_NAME “B” time&lt;/li&gt;
&lt;li&gt;$STANDARD_INFORMATION “B” or &amp;ldquo;M&amp;rdquo; time has nanosecond precision.&lt;/li&gt;
&lt;li&gt;PE compile time prior to any $STANDARD_INFORMATION time stamp.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Optional:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$STANDARD_INFORMATION “M” time prior to ShimCache timestamp&lt;/li&gt;
&lt;li&gt;$STANDARD_INFORMATION times prior to $I30 slack &amp;ldquo;B&amp;rdquo; or &amp;ldquo;M&amp;rdquo; times.&lt;/li&gt;
&lt;li&gt;Full PE metadata output.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: If an option is selected the artifact will also output additional metadata for context.&lt;/p&gt;
&lt;p&gt;Available filters include:&lt;br&gt;
PathRegex (OSPath): e.g ^C:\folder\file.ext$ or partial \folder\folder2\ or string|string2|string3&lt;br&gt;
FileRegex: ^filename.ext$ or partial string1|string2&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
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 &amp;lt;= 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 &amp;lt;= 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 &amp;gt; mtime OR Btime &amp;gt; btime ) AND IsSlack,
 else= True )
 
 LET base_results = SELECT 
 OSPath,
 dict(Created0x10=Created0x10,Created0x30=Created0x30) as CreatedTimestamps,
 InUse,
 SI_Lt_FN as `SI&amp;lt;FN`,USecZeros,
 if(condition=PE.FileHeader.TimeDateStamp,
 then= if(condition= LastModified0x10 &amp;lt; PE.FileHeader.TimeDateStamp OR LastAccess0x10 &amp;lt; PE.FileHeader.TimeDateStamp OR LastRecordChange0x10 &amp;lt; PE.FileHeader.TimeDateStamp OR Created0x10 &amp;lt; 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 &amp;lt; 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&amp;lt;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&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 SuspiciousShimcache,
 SuspiciousI30,
 NtfsMetadata,
 Magic,
 Shimcache,
 I30
 FROM base_results
 },
 else= if(condition= ShimcacheTest AND OutputPEInfo,
 then={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 SuspiciousShimcache,
 NtfsMetadata,
 Magic,
 Shimcache,
 PE
 FROM base_results
 },
 else= if(condition= I30Test AND OutputPEInfo,
 then={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 SuspiciousI30,
 NtfsMetadata,
 Magic,
 I30,
 PE
 FROM base_results
 },
 else= if(condition= ShimcacheTest,
 then={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 SuspiciousShimcache,
 NtfsMetadata,
 Magic,
 Shimcache
 FROM base_results
 },
 else= if(condition= I30Test,
 then={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 SuspiciousI30,
 NtfsMetadata,
 Magic,
 I30
 FROM base_results
 },
 else= if(condition= OutputPEInfo,
 then={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;FN`,USecZeros,
 SuspiciousCompileTime,
 NtfsMetadata,
 Magic,
 PE
 FROM base_results
 },
 else={
 SELECT 
 OSPath,CreatedTimestamps,InUse,
 `SI&amp;lt;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)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Office.MRU</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.office.mru/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.office.mru/</guid><description>&lt;p&gt;This artifact enables hunting for recently used Office Documents.&lt;/p&gt;
&lt;p&gt;The artifact takes a Registry path, and extracts the Most Recently Used (= MRU) files list from Microsoft Office products (i.e.: Word, Excel, Powerpoint).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Office.MRU
author: "Yaron King - @Sam0rai"
description: |
 This artifact enables hunting for recently used Office Documents.

 The artifact takes a Registry path, and extracts the Most Recently Used (= MRU) files list from Microsoft Office products (i.e.: Word, Excel, Powerpoint).

type: CLIENT

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: OfficeMRU_RegistryGlob
 description: Registry path glob for Microsoft Office's MRU list.
 default: HKEY_USERS\S-1-5-21-*\Software\Microsoft\Office\1{4,5,6}.0\{Word,Excel,PowerPoint}\User MRU\*\File MRU\Item*

sources:
 - query: |
 Let OfficeMRU_RegistryGlob = '''HKEY_USERS\S-1-5-21-*\Software\Microsoft\Office\1{4,5,6}.0\{Word,Excel,PowerPoint}\User MRU\*\File MRU\Item*'''

 SELECT
 timestamp(winfiletime=int(int="0x" + parse_string_with_regex(string=Data.value, regex=['\\[T(?P&amp;lt;timestamp&amp;gt;\\w\+)']).timestamp)) as Timestamp,
 lookupSID(sid=(split(string=FullPath, sep='\\\\'))[2]) as SAMaccountname,
 (split(string=FullPath, sep='\\\\'))[7] as FileType, (split(string=Data.value, sep='\\*'))[1] as Path
 FROM
 glob(globs=OfficeMRU_RegistryGlob, accessor='reg')

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Persistence.VscodeTasks</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/vscodetasks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/vscodetasks/</guid><description>&lt;p&gt;This artifact parses VSCode configuration files to find potenital
persistence.&lt;/p&gt;
&lt;p&gt;Terminal Profiles via settings.json&lt;br&gt;
Visual Studio tasks via tasks.json&lt;/p&gt;
&lt;p&gt;The artifact has configurable options to Include all tasks and settings for
visibility.&lt;/p&gt;
&lt;p&gt;NOTE: experimental - additional research may include Visual Studio Code Extensions&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Persistence.VscodeTasks
author: Matt Green - @mgreen27
description: |
 This artifact parses VSCode configuration files to find potenital 
 persistence.
 
 Terminal Profiles via settings.json 
 Visual Studio tasks via tasks.json 

 The artifact has configurable options to Include all tasks and settings for 
 visibility. 
 
 NOTE: experimental - additional research may include Visual Studio Code Extensions
 
reference:
 - https://twitter.com/nas_bench/status/1618021415852335105
 - https://twitter.com/nas_bench/status/1618021838407495681


type: CLIENT

parameters:
 - name: IncludeAllTasks
 type: bool
 - name: IncludeAllSettings
 type: bool

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

 query: |
 SELECT
 OSPath,	
 FileSize,
 FileName,	
 parse_json(data=regex_replace(source=read_file(filename=OSPath) , re='''//.+\n''', replace='')) As Parsed,
 dict(
 Created0x10=Created0x10,	
 Created0x30=Created0x30,
 LastModified0x10=LastModified0x10,
 LastModified0x30=LastModified0x30,
 LastRecordChange0x10=LastRecordChange0x10,
 LastRecordChange0x30=LastRecordChange0x30,
 LastAccess0x10=LastAccess0x10,
 LastAccess0x30=LastAccess0x30
 ) as Timestamps
 FROM Artifact.Windows.NTFS.MFT(FileRegex='^(settings|tasks)\.json$',PathRegex='vscode')
 WHERE
 if(condition=IncludeAllTasks,
 then= FileName='tasks.json',
 else= Parsed.settings.`task.allowAutomaticTasks` = 'on' )
 OR if(condition=IncludeAllSettings,
 then= FileName='settings.json',
 else= Parsed.settings.`terminal.integrated.defaultprofile.windows` )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.AteraNetworks</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/ateranetworks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/ateranetworks/</guid><description>&lt;p&gt;Find AteraNetworks configuration details in the registry.
This artifact is best combined with Windows.Forensics.FilenameSearch
searching for the string &amp;ldquo;atera&amp;rdquo;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.AteraNetworks
description: |
 Find AteraNetworks configuration details in the registry.
 This artifact is best combined with Windows.Forensics.FilenameSearch 
 searching for the string "atera".

author: original author Eduardo Mattos - @eduardfir

reference:
 - https://www.advanced-intel.com/post/secret-backdoor-behind-conti-ransomware-operation-introducing-atera-agent
 
precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: SearchRegistryGlob
 default: \HKEY_LOCAL_MACHINE\SOFTWARE\ATERA Networks\AlphaAgent\**
 description: Use a glob to define the registry hives that will be searched.

sources:
 - query: |
 SELECT ModTime as LastModified,
 FullPath,
 Name as KeyName,
 Data.value as KeyValue,
 Data.type as KeyType
 FROM glob(globs=SearchRegistryGlob, accessor='registry')
 WHERE NOT Data.type = 'key'

column_types:
 - name: Modified
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.Bulk.ComputerName</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.bulk.computername/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.bulk.computername/</guid><description>&lt;p&gt;This looks through registry on all disks to determine the hostname for cases where multiple disks are mounted&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.Bulk.ComputerName
description: |
 This looks through registry on all disks to determine the hostname for cases where multiple disks are mounted
author: Angry-bender

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

parameters:
 - name: TargetDrive
 description: |
 The path to to the drive that holds the SYSTEM registry hive. 
 default: "C:"
 - name: HiveLocation
 default: '\\windows\\system32\\config\\system'
 description: "Loction of target hive"
 - name: KeyValue
 default: "/*/Control/ComputerName/ComputerName/ComputerName"
 description: "Loction of target key"
 - name: AllDrives
 description: Search all drives?
 type: bool
 default: Y

sources:
 - query: |
 LET Drive &amp;lt;= pathspec(parse=TargetDrive, path_type="ntfs")
 
 -- get all drives
 LET ntfs_drives = SELECT
 OSPath AS Drive,
 OSPath + HiveLocation AS SystemHive
 FROM glob(globs="/*", accessor="ntfs")
 WHERE log(message="Processing " + SystemHive)
 
 LET RegParse(Drive,SysHivePth) = 
 SELECT Drive, Name, FullPath, url(parse=FullPath).Fragment AS Value, Mtime, Data.value AS Key FROM foreach(
 row={
 SELECT * FROM Drive
 },
 query={
 SELECT *
 FROM glob(
 globs=url(scheme="file",
 path=SysHivePth,
 fragment=KeyValue),
 accessor="raw_reg")
 })

 SELECT * FROM if(condition=AllDrives,
 then={
 SELECT * FROM foreach(
 row={
 SELECT * FROM ntfs_drives
 },
 query={
 SELECT *
 FROM RegParse(
 Drive=Drive,
 SysHivePth=SystemHive)
 })
 },
 else={
 SELECT *
 FROM RegParse(
 Drive=Drive,
 SysHivePth = Drive + HiveLocation)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.CapabilityAccessManager</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.capabilityaccessmanager/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.capabilityaccessmanager/</guid><description>&lt;p&gt;The ConsentStore in CapabilityAccessManager can provide insight to
what resources binaries have had access to, such as the microphone
and webcam. This artefact returns non-Microsoft executables (ie:
entries listed in the &lt;code&gt;NonPackaged&lt;/code&gt; path).&lt;/p&gt;
&lt;p&gt;Additional Resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svch0st.medium.com/can-you-track-processes-accessing-the-camera-and-microphone-7e6885b37072" target="_blank" &gt;https://svch0st.medium.com/can-you-track-processes-accessing-the-camera-and-microphone-7e6885b37072&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thinkdfir.com/2022/01/04/i-can-see-and-hear-you-seeing-and-hearing-me/" target="_blank" &gt;https://thinkdfir.com/2022/01/04/i-can-see-and-hear-you-seeing-and-hearing-me/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tags: #windows #registry&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.CapabilityAccessManager
description: |
 The ConsentStore in CapabilityAccessManager can provide insight to
 what resources binaries have had access to, such as the microphone
 and webcam. This artefact returns non-Microsoft executables (ie:
 entries listed in the `NonPackaged` path).

 Additional Resources:

 * https://svch0st.medium.com/can-you-track-processes-accessing-the-camera-and-microphone-7e6885b37072
 * https://thinkdfir.com/2022/01/04/i-can-see-and-hear-you-seeing-and-hearing-me/

 Tags: #windows #registry

author: Zach Stanford - @svch0st, Phill Moore - @phillmoore
type: CLIENT

parameters:
 - name: KeyList
 description: List of reg locations and descriptions
 type: csv
 default: |
 Glob,Description
 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\*\NonPackaged\*, SoftwareHive
 HKEY_USERS\*\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\*\NonPackaged\*, UserHive
sources:
 - queries:
 - |

 SELECT * FROM foreach(
 row=KeyList,
 query={
 SELECT Description as SourceLocation,
 path_split(path=FullPath)[-3] as Accessed,
 regex_replace(source=basename(path=FullPath), re="#", replace="/") as Program,
 {SELECT timestamp(winfiletime=atoi(string=Data.value)) FROM glob(globs=FullPath+'\\LastUsedTimeStart', accessor="reg")} as LastUsedTimeStart,
 {SELECT timestamp(winfiletime=atoi(string=Data.value)) FROM glob(globs=FullPath+'\\LastUsedTimeStop', accessor="reg")} as LastUsedTimeStop,
 dirname(path=FullPath) as KeyPath
 FROM glob(globs=Glob, accessor="reg")
 Where NOT Program = "Value"
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.COMAutoApprovalList</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.comautoapprovallist/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.comautoapprovallist/</guid><description>&lt;p&gt;This artifact will return COM objects that auto-elevate and bypass UAC (these could potentially be used by adversaries/malware to elevate privileges), and cross-reference the class ID with a name where able.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.COMAutoApprovalList
author: Wes Lambert - @therealwlambert
description: |
 This artifact will return COM objects that auto-elevate and bypass UAC (these could potentially be used by adversaries/malware to elevate privileges), and cross-reference the class ID with a name where able.

reference: 
 - https://twitter.com/d4rksystem/status/1562507028337131520?s=20&amp;amp;t=3k45RhMaSRvLr6kNc0fdKg
 - https://swapcontext.blogspot.com/2020/11/uac-bypasses-from-comautoapprovallist.html 

parameters:
 - name: KeyGlob
 default: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UAC\COMAutoApprovalList\**
 - name: ClsidGlob
 default: HKLM\SOFTWARE\Classes\CLSID\

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

 query: |
 SELECT {
 SELECT Data.value 
 FROM stat(filename=ClsidGlob + OSPath.Basename + "\\@",
 accessor="registry")
 } AS Name,
 Data.value AS Enabled,
 OSPath.Basename AS GUID,
 OSPath AS ApprovalKey,
 Mtime
 FROM glob(globs=KeyGlob, accessor="registry") ORDER BY Mtime DESC

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.CortexEDRDisabled</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.disabledcortexxdr/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.disabledcortexxdr/</guid><description>&lt;p&gt;This artifact will attempt to identify Cortex EDR that has been disabled via regkey&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.CortexEDRDisabled
author: Rhys Jenkins @Rhysistance
description: |
 This artifact will attempt to identify Cortex EDR that has been disabled via regkey
reference:
 - https://mrd0x.com/cortex-xdr-analysis-and-bypass/

parameters:
 - name: KeyGlob
 default: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CryptSvc\Parameters\ServiceDll

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

 query: |
 SELECT Name,Data.value as DllName,Fqdn FROM glob(globs=KeyGlob, accessor="reg") WHERE NOT DllName =~ "cryptsvc\.dll"

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.CVE_2021_40444</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/cve_2021_40444/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/cve_2021_40444/</guid><description>&lt;p&gt;This artifact will enable both application and removal of the
reccomended mitigation for CVE-2021-40444.&lt;/p&gt;
&lt;p&gt;Disabling the installation of all ActiveX controls in Internet
Explorer mitigates this attack. This can be accomplished for all
sites by updating the registry. Previously-installed ActiveX
controls will continue to run, but do not expose this
vulnerability.&lt;/p&gt;
&lt;p&gt;To disable installing ActiveX controls in Internet Explorer in all
zones&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0]
&amp;quot;1001&amp;quot;=dword:00000003
&amp;quot;1004&amp;quot;=dword:00000003

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1]
&amp;quot;1001&amp;quot;=dword:00000003
&amp;quot;1004&amp;quot;=dword:00000003

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2]
&amp;quot;1001&amp;quot;=dword:00000003
&amp;quot;1004&amp;quot;=dword:00000003

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3]
&amp;quot;1001&amp;quot;=dword:00000003
&amp;quot;1004&amp;quot;=dword:00000003
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets the &lt;code&gt;URLACTION_DOWNLOAD_SIGNED_ACTIVEX&lt;/code&gt; (0x1001) and
&lt;code&gt;URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX&lt;/code&gt; (0x1004) to &lt;code&gt;DISABLED&lt;/code&gt; (3) for all
internet zones for 64-bit and 32-bit processes. New ActiveX controls will
not be installed. Previously-installed ActiveX controls will continue to run.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: if both AddMitigation and DeleteMitigation is selected
DeleteMitigation will take preference. Reboot may be required.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.CVE_2021_40444
author: Matt Green - @mgreen27
description: |
 This artifact will enable both application and removal of the
 reccomended mitigation for CVE-2021-40444.

 Disabling the installation of all ActiveX controls in Internet
 Explorer mitigates this attack. This can be accomplished for all
 sites by updating the registry. Previously-installed ActiveX
 controls will continue to run, but do not expose this
 vulnerability.

 To disable installing ActiveX controls in Internet Explorer in all
 zones

 ```
 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0]
 "1001"=dword:00000003
 "1004"=dword:00000003

 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1]
 "1001"=dword:00000003
 "1004"=dword:00000003

 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2]
 "1001"=dword:00000003
 "1004"=dword:00000003

 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3]
 "1001"=dword:00000003
 "1004"=dword:00000003
 ```

 This sets the `URLACTION_DOWNLOAD_SIGNED_ACTIVEX` (0x1001) and
 `URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX` (0x1004) to `DISABLED` (3) for all
 internet zones for 64-bit and 32-bit processes. New ActiveX controls will
 not be installed. Previously-installed ActiveX controls will continue to run.

 **NOTE**: if both AddMitigation and DeleteMitigation is selected
 DeleteMitigation will take preference. Reboot may be required.

reference:
 - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444

type: CLIENT

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: SearchRegistryGlob
 default: HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/{0,1,2,3}/*
 - name: AddMitigation
 type: bool
 description: Add registry key mitigations for CVE-2021-40444.
 - name: DeleteMitigation
 type: bool
 description: Remove registry key mitigations for CVE-2021-40444.

sources:
 - query: |
 -- set registry values
 LET setvalues = SELECT
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/0/1001/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/0/1004/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/1/1001/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/1/1004/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/2/1001/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/2/1004/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/3/1001/',
 type='DWORD',value=3,create='Y'),
 reg_set_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/3/1004/',
 type='DWORD',value=3,create='Y')
 FROM scope()

 LET rmvalues = SELECT
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/0/1001/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/0/1004/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/1/1001/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/1/1004/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/2/1001/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/2/1004/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/3/1001/'),
 reg_rm_value(path='HKEY_LOCAL_MACHINE/SOFTWARE/Policies/Microsoft/Windows/CurrentVersion/Internet Settings/Zones/3/1004/')
 FROM scope()

 LET values &amp;lt;= SELECT *
 FROM if(condition=DeleteMitigation,
 then= rmvalues,
 else=if(condition=AddMitigation,
 then=setvalues))

 -- output rows add some description on applied settings.
 SELECT
 timestamp(string=Mtime) as ModifiedTime,
 FullPath as KeyPath,
 Data.value as Value,
 if(condition= FullPath=~'1001$',
 then='URLACTION_DOWNLOAD_SIGNED_ACTIVEX (0x1001) - mitigation to DISABLED (3)',
 else= if(condition= FullPath=~'1004$',
 then='URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX (0x1004) - mitigation to DISABLED (3)',
 else= 'UNKNOWN')) as Description
 FROM glob(globs=SearchRegistryGlob, accessor='registry')
 WHERE Data.type = 'DWORD'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.DefenderConfig</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/defenderconfig/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/defenderconfig/</guid><description>&lt;p&gt;Thit artifact enables extracting Windows Defender configuration from
SOFTWARE registry hive.&lt;/p&gt;
&lt;p&gt;Availible parameters enable filtering on RegKey, KeyName or KeyValue.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;KeyRegex - Regex for string in registry key. For example we could use
Exclusions\Process for process exclusions&lt;/li&gt;
&lt;li&gt;NameRegex - Regex for KeyName. For example we could use process.exe
for a process in exclusions or specific setting name of interest.&lt;/li&gt;
&lt;li&gt;ValueRegex - Regex for KeyValue.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.DefenderConfig
author: Matt Green - @mgreen27
description: |
 Thit artifact enables extracting Windows Defender configuration from 
 SOFTWARE registry hive.
 
 Availible parameters enable filtering on RegKey, KeyName or KeyValue.
 
 1. KeyRegex - Regex for string in registry key. For example we could use 
 Exclusions\\Process for process exclusions
 2. NameRegex - Regex for KeyName. For example we could use process.exe 
 for a process in exclusions or specific setting name of interest.
 3. ValueRegex - Regex for KeyValue.
 
type: CLIENT

parameters:
 - name: TargetKey
 default: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\**
 - name: KeyRegex
 default: .
 description: Regex for string in registry key. For example we could use Exclusions\\Process for process exclusions
 type: regex
 - name: NameRegex
 default: .
 description: Regex for KeyName. For example we could use process.exe for a process in exclusions or specific setting.
 type: regex
 - name: ValueRegex
 default: .
 description: Regex for KeyValue.
 type: regex

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

 query: |
 SELECT 
 Mtime as LastWriteTime,
 OSPath.dirname as RegKey,
 OSPath.basename as KeyName,
 Data.value as KeyValue,
 Data.type as KeyType
 FROM glob(globs=TargetKey, accessor="reg")
 WHERE NOT KeyType = 'key'
 AND RegKey=~ KeyRegex AND KeyName=~NameRegex AND KeyValue=~ValueRegex
 ORDER BY RegKey

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.Domain</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.domainname/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.domainname/</guid><description>&lt;p&gt;Checks the configured domain name on each endpoint&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.Domain
description: Checks the configured domain name on each endpoint
author: Angry-bender

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

parameters:
 - name: DomainHive
 default: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Domain
sources:
 - queries:
 - |
 SELECT
 ModTime,
 OSPath.Dirname as registry_key,
 OSPath.Basename as registry_name,
 Data.value as registry_value
 FROM glob(globs=DomainHive, accessor="registry")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.HiddenUsers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/hiddenusers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/hiddenusers/</guid><description>&lt;p&gt;Find hidden user accounts through registry values on the filesystem.&lt;/p&gt;
&lt;p&gt;In Windows, adversaries may hide user accounts via settings in the Registry.
For example, an adversary may add a value to the Windows Registry
(via Reg or other means) that will hide the user &amp;ldquo;test&amp;rdquo; from
the Windows login screen:&lt;/p&gt;
&lt;p&gt;reg.exe ADD &amp;lsquo;HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList&amp;rsquo; /v test /t REG_DWORD /d 0 /f.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ATT&amp;amp;CK tactic: Defense Evasion, Hide Artifacts: Hidden Users&lt;/li&gt;
&lt;li&gt;ATT&amp;amp;CK technique: T1564.002&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.HiddenUsers
description: |
 Find hidden user accounts through registry values on the filesystem.

 In Windows, adversaries may hide user accounts via settings in the Registry. 
 For example, an adversary may add a value to the Windows Registry 
 (via Reg or other means) that will hide the user "test" from 
 the Windows login screen: 
 
 reg.exe ADD 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList' /v test /t REG_DWORD /d 0 /f.

 * ATT&amp;amp;CK tactic: Defense Evasion, Hide Artifacts: Hidden Users
 * ATT&amp;amp;CK technique: T1564.002

reference:
 - https://attack.mitre.org/techniques/T1564/002/
 - https://github.com/Res260/conti_202202_leak_procedures/blob/main/12_using_anydesk.txt
 
type: CLIENT

author: Eduardo Mattos - @eduardfir

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: SearchRegistryGlob
 default: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\Userlist\**
 description: Use a glob to define the keys that will be searched.

sources:
 - query: |
 SELECT Name,
 FullPath,
 Data,
 Sys,
 ModTime as Modified
 FROM glob(globs=SearchRegistryGlob, accessor='registry')

column_types:
 - name: Modified
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.HVCI</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/hvci/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/hvci/</guid><description>&lt;p&gt;This artifact will return the Enabled KeyValue in the Hypervisor-protected Code
Integrity (HVCI) registry path. An adversary may set the Enabled key to 0
if they intend to manipulate UEFI boot process.&lt;/p&gt;
&lt;p&gt;The artifact will group by KeyName, KeyValue and KeyType to account for
multiple control sets.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.HVCI
author: Matt Green - @mgreen27
description: |
 This artifact will return the Enabled KeyValue in the Hypervisor-protected Code 
 Integrity (HVCI) registry path. An adversary may set the Enabled key to 0 
 if they intend to manipulate UEFI boot process.
 
 The artifact will group by KeyName, KeyValue and KeyType to account for 
 multiple control sets.

reference:
 - https://www.microsoft.com/en-us/security/blog/2023/04/11/guidance-for-investigating-attacks-using-cve-2022-21894-the-blacklotus-campaign/
 - https://learn.microsoft.com/en-us/windows/security/hardware-security/enable-virtualization-based-protection-of-code-integrity

parameters:
 - name: KeyGlob
 default: HKEY_LOCAL_MACHINE\SYSTEM\*ControlSet*\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity\**
 - name: OnlyShowZero
 type: bool
 description: If this is set, the results will only show KeyValues = 0

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

 query: |
 SELECT 
 Mtime, 
 OSPath,
 Data.type as KeyType,
 Name as KeyName,
 Data.value as KeyValue
 FROM glob(globs=KeyGlob, accessor="registry")
 WHERE KeyName = 'Enabled'
 AND if(condition= OnlyShowZero,
 then= KeyValue = 0,
 else= True )
 GROUP BY KeyName, KeyValue, KeyType

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.NetshHelperDLLs</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.netshhelperdlls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.netshhelperdlls/</guid><description>&lt;h1 id="enumerate-all-netsh-helper-dlls"&gt;Enumerate all NetSh Helper DLLs&lt;/h1&gt;
&lt;p&gt;Inspired by this &lt;a href="https://twitter.com/SecurePeacock/status/1532011932315680769?s=20&amp;amp;t=IFbej-qpkF6IB7ycewE31w" target="_blank" &gt;tweet&lt;/a&gt;
,
this artifact enumerates all NetSh Helper DLLs to provide
opportunities to find outliers and potential persistence mechanisms
tied to &lt;a href="https://lolbas-project.github.io/lolbas/Binaries/Netsh/" target="_blank" &gt;netsh.exe&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I have run this hunt across 6K+ systems and identified the most common entries and provided
the &lt;code&gt;excludeCommon&lt;/code&gt; option to exclude these. In very large environments there will likely still be FPs,
but they should be far and few.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://attack.mitre.org/techniques/T1546/007/" target="_blank" &gt;https://attack.mitre.org/techniques/T1546/007/&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://lolbas-project.github.io/lolbas/Binaries/Netsh/" target="_blank" &gt;https://lolbas-project.github.io/lolbas/Binaries/Netsh/&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.NetshHelperDLLs
description: |
 # Enumerate all NetSh Helper DLLs

 Inspired by this [tweet](https://twitter.com/SecurePeacock/status/1532011932315680769?s=20&amp;amp;t=IFbej-qpkF6IB7ycewE31w),
 this artifact enumerates all NetSh Helper DLLs to provide
 opportunities to find outliers and potential persistence mechanisms 
 tied to [netsh.exe](https://lolbas-project.github.io/lolbas/Binaries/Netsh/)

 I have run this hunt across 6K+ systems and identified the most common entries and provided
 the `excludeCommon` option to exclude these. In very large environments there will likely still be FPs, 
 but they should be far and few.

 References:

 - https://attack.mitre.org/techniques/T1546/007/

 - https://lolbas-project.github.io/lolbas/Binaries/Netsh/


parameters:
 - name: SearchRegistryGlob
 default: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NetSh\**
 description: Use a glob to define the files that will be searched.
 - name: excludeCommon
 description: "Exclude common well-known entries."
 type: bool

author: Eric Capuano - @eric_capuano

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

sources:
 - query: |
 LET filteredResults &amp;lt;= 
 SELECT Name, FullPath, Data.value AS HelperDLL, ModTime as Modified
 FROM glob(globs=SearchRegistryGlob, accessor='registry')
 // filter out entries found consistently across 1000s of systems in the wild
 WHERE NOT (Name = "2" AND HelperDLL = "ifmon.dll")
 AND NOT (Name = "4" AND HelperDLL = "rasmontr.dll")
 AND NOT (Name = "WcnNetsh" AND HelperDLL = "WcnNetsh.dll")
 AND NOT (Name = "authfwcfg" AND HelperDLL = "authfwcfg.dll")
 AND NOT (Name = "dhcpclient" AND HelperDLL = "dhcpcmonitor.dll")
 AND NOT (Name = "dot3cfg" AND HelperDLL = "dot3cfg.dll")
 AND NOT (Name = "fwcfg" AND HelperDLL = "fwcfg.dll")
 AND NOT (Name = "hnetmon" AND HelperDLL = "hnetmon.dll")
 AND NOT (Name = "napmontr" AND HelperDLL = "napmontr.dll")
 AND NOT (Name = "netiohlp" AND HelperDLL = "netiohlp.dll")
 AND NOT (Name = "nettrace" AND HelperDLL = "nettrace.dll")
 AND NOT (Name = "nshhttp" AND HelperDLL = "nshhttp.dll")
 AND NOT (Name = "nshipsec" AND HelperDLL = "nshipsec.dll")
 AND NOT (Name = "nshwfp" AND HelperDLL = "nshwfp.dll")
 AND NOT (Name = "p2pnetsh" AND HelperDLL = "p2pnetsh.dll")
 AND NOT (Name = "peerdistsh" AND HelperDLL = "peerdistsh.dll")
 AND NOT (Name = "rpc" AND HelperDLL = "rpcnsh.dll")
 AND NOT (Name = "whhelper" AND HelperDLL = "whhelper.dll")
 AND NOT (Name = "wlancfg" AND HelperDLL = "wlancfg.dll")
 AND NOT (Name = "wshelper" AND HelperDLL = "wshelper.dll")
 AND NOT (Name = "wwancfg" AND HelperDLL = "wwancfg.dll")

 LET Results &amp;lt;= 
 SELECT Name, FullPath, Data.value AS HelperDLL, ModTime as Modified
 FROM glob(globs=SearchRegistryGlob, accessor='registry')

 SELECT *
 FROM if(condition=excludeCommon,
 then={ SELECT * FROM filteredResults},
 else={ SELECT * FROM Results})

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.PrintNightmare</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.printnightmare/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.printnightmare/</guid><description>&lt;p&gt;CVE-2021-34527 or Windows Print Spooler Remote Code Execution Vulnerability&lt;/p&gt;
&lt;p&gt;A remote code execution vulnerability exists when the Windows Print Spooler service improperly performs privileged file operations. An attacker who successfully exploited this vulnerability could run arbitrary code with SYSTEM privileges. An attacker could then install programs; view, change, or delete data; or create new accounts with full user rights.&lt;/p&gt;
&lt;p&gt;According to Microsoft, this vulnerability can only be exploited if the “NoWarningNoElevationOnInstall” key in the registry is set to 1.&lt;/p&gt;
&lt;p&gt;The artifact scans the device registry to check if the beforementioned key exists or not; if it is undefined or doesn’t exist, then the system is not vulnerable to the PrintNightmare. Otherwise, the system is considered to be vulnerable to exploitation.&lt;/p&gt;
&lt;p&gt;This vulnerability can be exploited using the Evil Printer attack.&lt;/p&gt;
&lt;p&gt;Changing the registry values from 1 to 0 or Disabling the spooler when it&amp;rsquo;s not in use is recommended as the next step after applying the patch.
The following VQL query looks for the registry values to find a registry key named “NoWarningNoElevationOnInstall”.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527" target="_blank" &gt;https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Diving-Into-Spooler-Discovering-Lpe-And-Rce-Vulnerabilities-In-Windows-Printer.pdf" target="_blank" &gt;https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Diving-Into-Spooler-Discovering-Lpe-And-Rce-Vulnerabilities-In-Windows-Printer.pdf&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2021-34527" target="_blank" &gt;https://nvd.nist.gov/vuln/detail/CVE-2021-34527&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.PrintNightmare
description: |
 CVE-2021-34527 or Windows Print Spooler Remote Code Execution Vulnerability
 
 A remote code execution vulnerability exists when the Windows Print Spooler service improperly performs privileged file operations. An attacker who successfully exploited this vulnerability could run arbitrary code with SYSTEM privileges. An attacker could then install programs; view, change, or delete data; or create new accounts with full user rights.
 
 According to Microsoft, this vulnerability can only be exploited if the “NoWarningNoElevationOnInstall” key in the registry is set to 1. 
 
 The artifact scans the device registry to check if the beforementioned key exists or not; if it is undefined or doesn’t exist, then the system is not vulnerable to the PrintNightmare. Otherwise, the system is considered to be vulnerable to exploitation.
 
 This vulnerability can be exploited using the Evil Printer attack.
 
 Changing the registry values from 1 to 0 or Disabling the spooler when it's not in use is recommended as the next step after applying the patch.
 The following VQL query looks for the registry values to find a registry key named “NoWarningNoElevationOnInstall”.

 
 References:
 
 https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527

 https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Diving-Into-Spooler-Discovering-Lpe-And-Rce-Vulnerabilities-In-Windows-Printer.pdf

 https://nvd.nist.gov/vuln/detail/CVE-2021-34527

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

author: Daksh Gajjar - @dakshgajjar

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

parameters:
 - name: SearchRegistryGlob
 default: \HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint\**
 description: Having NoWarningNoElevationOnInstall set to 1 makes your system vulnerable by design

sources:
 - query: |
 SELECT Name as KeyName,
 FullPath,
 Data.type as KeyType, 
 Data.value as KeyValue,
 Sys,
 ModTime as Modified
 FROM glob(globs=SearchRegistryGlob, accessor='registry')
 
 WHERE KeyType = "DWORD"
 AND KeyName =~ "NoWarningNoElevationOnInstall"
 
column_types:
 - name: Modified
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.ScheduledTasks</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/scheduledtasks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/scheduledtasks/</guid><description>&lt;p&gt;This artefact will collect Scheduled task information from the registry without
relying on the existance of an XML file in C:\Windows\System32\Tasks.&lt;/p&gt;
&lt;p&gt;The artifact will attempt to find relevant XML data if exists.
There is also an option to show only tasks missing a Security Descriptor.&lt;/p&gt;
&lt;p&gt;TODO: cleanup, write test and add to main repo&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.ScheduledTasks
author: Matt Green - @mgreen27
description: |
 This artefact will collect Scheduled task information from the registry without 
 relying on the existance of an XML file in C:\\Windows\\System32\\Tasks.
 
 The artifact will attempt to find relevant XML data if exists.
 There is also an option to show only tasks missing a Security Descriptor.
 
 TODO: cleanup, write test and add to main repo
 
reference:
 - https://www.youtube.com/watch?v=ZQeWgTP4PaY
 
type: CLIENT

parameters:
 - name: OnlyShowNullSD
 type: bool
 description: only show entries with null security descriptor

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

 query: | 
 LET xml &amp;lt;= SELECT *, 
 regex_replace(source=OSPath,re='''^C:\\Windows\\System32\\Tasks''',replace='') as Path 
 FROM Artifact.Windows.System.TaskScheduler()
 
 LET tree &amp;lt;= SELECT Id,SD,Index
 FROM read_reg_key(globs="HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Schedule/TaskCache/Tree/**", accessor="reg")
 
 LET find_xml(path) = SELECT OSPath, Command, Arguments, ComHandler, UserId, _XML
 FROM xml WHERE Path = path
 
 LET tree_sd(id) = SELECT Id,SD,Index
 FROM tree WHERE Id = id
 
 LET tasks = SELECT 
 basename(path=Key.FileInfo.FullPath) as TaskID,
 Key.FileInfo.ModTime as Mtime,
 Path,
 Hash,
 Version,
 SecurityDescriptor,
 Source,
 Author,
 Description,
 URI,
 Triggers,
 Actions,
 DynamicInfo,
 if(condition=Schema, 
 then=format(format='0x%x',args=Schema),
 else='') as Schema,
 Date,
 Key.FileInfo.FullPath as OSPath,
 find_xml(path=Path)[0] as XmlEntry
 FROM read_reg_key(globs="HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Schedule/TaskCache/Tasks/**", accessor="reg")
 
 SELECT 
 TaskID,Mtime,Path,Hash,Version,
 SecurityDescriptor,
 tree_sd(id=TaskID)[0].SD as TreeSD,
 Source, Author, Description,URI,Triggers, Actions, DynamicInfo,
 Schema,Date,
 OSPath,
 XmlEntry
 FROM tasks
 WHERE NOT if(condition= OnlyShowNullSD,
 then= TreeSD,
 else= False )
 
column_types:
 - name: Hash
 type: hex
 - name: Triggers
 type: hex
 - name: DynamicInfo
 type: hex
 - name: TreeSD
 type: hex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Registry.TaskCache.HiddenTasks</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.taskcache.hiddentasks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.registry.taskcache.hiddentasks/</guid><description>&lt;p&gt;This artefact will highlight any scheduled tasks missing the Security Descriptor (SD) value in the task cache. Without this value, the task is hidden from common query methods.&lt;/p&gt;
&lt;p&gt;Once a task is identified with the SD value missing, the arefact tries to pull additional information from the registry and XML file for the task.&lt;/p&gt;
&lt;p&gt;An example of this technique is used by the Tarrask malware.&lt;/p&gt;
&lt;p&gt;Reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/" target="_blank" &gt;https://www.microsoft.com/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Registry.TaskCache.HiddenTasks
author: Zach Stanford - @svch0st
description: |
 This artefact will highlight any scheduled tasks missing the Security Descriptor (SD) value in the task cache. Without this value, the task is hidden from common query methods. 
 
 Once a task is identified with the SD value missing, the arefact tries to pull additional information from the registry and XML file for the task. 
 
 An example of this technique is used by the Tarrask malware.
 
 Reference:
 - https://www.microsoft.com/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/
 
precondition: SELECT OS From info() where OS = 'windows'

sources:
 - query: | 
 Select * from foreach(row={ 
 SELECT *,
 FROM read_reg_key(globs='HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Schedule/TaskCache/Tree/**', accessor="reg")
 Where SD = null
 },
 query={
 SELECT
 Date,
 Key.FullPath,
 Path, 
 {SELECT * FROM Artifact.Windows.System.TaskScheduler(TasksPath="C:\\Windows\\System32\\Tasks"+Path)} as TaskXML, 
 basename(path=Key.FullPath) as TaskID
 FROM read_reg_key(globs='HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Schedule/TaskCache/Tasks/*', accessor="reg")
 WHERE TaskID = Id
 })


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Remediation.Glob</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/globremediation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/globremediation/</guid><description>&lt;p&gt;This artifact uses glob to remove a file or folder.&lt;br&gt;
To recursively target a folder: &lt;code&gt;C:\folder\path{,\**}&lt;/code&gt;&lt;br&gt;
To target multiple folders: &lt;code&gt;C:\{folder2\path2{,\**},folder\path{,\**}}&lt;/code&gt;
however advised to just run 2 collections&amp;hellip;&lt;/p&gt;
&lt;p&gt;WARNING: There has been a bug in older versions of Velociraptor that &lt;code&gt;\**&lt;/code&gt;
glob path will select all files. PLEASE SCOPE FIRST and use appropriate targeting.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Remediation.Glob
author: Matt Green - @mgreen27
description: |
 This artifact uses glob to remove a file or folder. 
 To recursively target a folder: ```C:\folder\path{,\**}``` 
 To target multiple folders: ```C:\{folder2\path2{,\**},folder\path{,\**}}``` 
 however advised to just run 2 collections... 
 
 WARNING: There has been a bug in older versions of Velociraptor that ```\**```
 glob path will select all files. PLEASE SCOPE FIRST and use appropriate targeting.
 
type: CLIENT

parameters:
 - name: TargetGlob
 default: C:\Path\to\File
 - name: NoDir
 description: Do not scope folders
 type: bool
 - name: ReallyDoIt
 description: When selected will really remove!
 type: bool

sources:
 - query: |
 LET targets = SELECT * FROM glob(globs=TargetGlob)
 WHERE NOT if(condition=NoDir,
 then= IsDir,
 else= FALSE)
 ORDER BY OSPath DESC -- need to order by path to ensure recursive delete works.
 
 LET delete_targets = SELECT *, rm(filename=OSPath) as Removed FROM targets

 SELECT OSPath,Removed,Size,Mtime,Ctime,Btime,IsDir,IsLink
 FROM if(condition=ReallyDoIt,
 then= delete_targets,
 else= { SELECT *, FALSE as Removed FROM targets } )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Remediation.KillProcess</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/killprocess/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/killprocess/</guid><description>&lt;p&gt;Quick and dirty monitoring artifact to kill a process by Image Name.
We monitor the Microsoft-Windows-Kernel-Process ETW provider and leverage
taskkill to kill the process.&lt;/p&gt;
&lt;p&gt;There are no guardrails on this artifact please be VERY careful adding new entries.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Remediation.KillProcess
author: Matt Green - @mgreen27
description: |
 Quick and dirty monitoring artifact to kill a process by Image Name.
 We monitor the Microsoft-Windows-Kernel-Process ETW provider and leverage 
 taskkill to kill the process.
 
 There are no guardrails on this artifact please be VERY careful adding new entries.

type: CLIENT_EVENT

parameters:
 - name: ProcessToKill
 type: csv
 default: |
 ImageRegex,Description
 \\folder\\folder2\\file\.exe$,Example target image
 \\psexesvc\.exe$,Default psexec executable on target machine.
 \\calc\.exe$,Test fast running process: start &amp;gt; run calc.exe
 \\calculator\.exe$,Test killing calc.exe alias (modern Windows calc.exe)
 

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

 query: |
 LET name_regex = join(array=ProcessToKill.ImageRegex,sep='|')
 LET watch_processes = SELECT System.TimeStamp AS CreateTime,
 EventData.ImageName AS ImageName,
 int(int=EventData.ProcessID) AS Pid,
 EventData.MandatoryLabel AS MandatoryLabel,
 EventData.ProcessTokenElevationType AS ProcessTokenElevationType,
 EventData.ProcessTokenIsElevated AS TokenIsElevated
 FROM watch_etw(guid="{22fb2cd6-0e7b-422b-a0c7-2fad1fd0e716}", any=0x10)
 WHERE System.ID = 1 AND ImageName =~ name_regex
 
 SELECT *, pskill(pid=Pid) as TaskKill
 FROM watch_processes

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Remediation.PrintSpooler</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/printspoolerremediation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/printspoolerremediation/</guid><description>&lt;p&gt;This artifact will enable mitigation of PrintSpooler exploitation
used by PrintNightmare - CVE-2021-34527 and CVE-2021-1675.&lt;/p&gt;
&lt;p&gt;There are two selectable mitigations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;disabling the print spooler service.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler\Start = 4 (service disabled).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;disable remote registration of the spool service.
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RegisterSpoolerRemoteRpcEndPoint = 2 (RegisterSpoolerRemoteRpcEndPoint disables).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: ChangeServiceStartup will set to disable, not stop the
printspool service. Its always reccomended to use group policy to
deploy these settings.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Remediation.PrintSpooler
author: Matt Green - @mgreen27
description: |
 This artifact will enable mitigation of PrintSpooler exploitation
 used by PrintNightmare - CVE-2021-34527 and CVE-2021-1675.

 There are two selectable mitigations:

 - disabling the print spooler service.
 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler\Start = 4 (service disabled).

 - disable remote registration of the spool service.
 HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RegisterSpoolerRemoteRpcEndPoint = 2 (RegisterSpoolerRemoteRpcEndPoint disables).

 NOTE: ChangeServiceStartup will set to disable, not stop the
 printspool service. Its always reccomended to use group policy to
 deploy these settings.


type: CLIENT

parameters:
 - name: TargetGlobs
 type: csv
 default: |
 Target,Description,Potential Values
 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler\Start,Print spooler service startup,"0 = Boot, 1 = System, 2 = Automatic, 3 = Manual, 4 = Disabled"
 HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RegisterSpoolerRemoteRpcEndPoint,Print spooler RemoteRpcEndPoint registration,"Enabled = 1, Disabled = 2"
 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Policies\Microsoft\Windows NT\Printers\RegisterSpoolerRemoteRpcEndPoint,Print spooler RemoteRpcEndPoint registration WOW6432Node,"Enabled = 1, Disabled = 2"
 - name: MitigateServiceStartup
 type: bool
 - name: MitigateRegisterSpoolerRemoteRpcEndPoint
 type: bool

sources:
 - query: |
 -- remediation template
 LET execute_reg(key,name,value) = SELECT * FROM execve(argv=['reg','add',key,'/v',name,'/t','REG_DWORD','/d',value,'/f'])
 LET Arch = SELECT PROCESSOR_ARCHITECTURE FROM environ()

 LET remediation &amp;lt;= SELECT * FROM chain(
 a=if(condition=MitigateServiceStartup,
 then = execute_reg(key='HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Spooler',name='Start',value=4)),
 b= if(condition=MitigateRegisterSpoolerRemoteRpcEndPoint,
 then= execute_reg(key='HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\Printers',name='RegisterSpoolerRemoteRpcEndPoint',value=2)),
 c= if(condition=MitigateRegisterSpoolerRemoteRpcEndPoint,
 then= if(condition= Arch.PROCESSOR_ARCHITECTURE[0]='AMD64',
 then= execute_reg(key='HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Policies\\Microsoft\\Windows NT\\Printers',name='RegisterSpoolerRemoteRpcEndPoint',value=2)))
 )

 SELECT * FROM foreach(row=TargetGlobs,
 query={
 SELECT
 Description,
 `Potential Values`,
 mtime as ModifiedTime,FullPath,
 basename(path=FullPath) as KeyName,
 Data.type as KeyType,
 Data.value as KeyValue
 FROM glob(globs=Target, accessor="reg")
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Remediation.Process</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/processremediation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/processremediation/</guid><description>&lt;p&gt;This artifact enables killing a process by Name, Path or PID.&lt;/p&gt;
&lt;p&gt;WARNING: This is dangerous content as there are no guardrails.
Scope remediation first then ReallyDoIt to kill process.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Remediation.Process
author: Matt Green - @mgreen27
description: |
 This artifact enables killing a process by Name, Path or PID.
 
 WARNING: This is dangerous content as there are no guardrails. 
 Scope remediation first then ReallyDoIt to kill process.
 
type: CLIENT
parameters:
 - name: ProcessNameRegex
 default: ^malware.exe$
 type: regex
 - name: ProcessPathRegex
 default: .
 type: regex
 - name: ProcessCliRegex
 default: .
 type: regex
 - name: PidRegex
 default: .
 type: regex
 - name: ReallyDoIt
 description: When selected will really remove!
 type: bool 


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

 query: |
 -- find velociraptor process
 LET me = SELECT Pid FROM pslist(pid=getpid())

 -- find all processes and add filters
 LET targets = SELECT Name as ProcessName, Exe, CommandLine, Pid
 FROM pslist()
 WHERE TRUE
 AND Name =~ ProcessNameRegex
 AND Exe =~ ProcessPathRegex
 AND CommandLine =~ ProcessCliRegex
 AND format(format="%d", args=Pid) =~ PidRegex
 AND NOT Pid in me.Pid
 AND NOT upcase(string=Exe) in whitelist.Path
 
 SELECT * , 
 if( condition = ReallyDoIt,
 then = pskill(pid=Pid),
 else = False 
 ) as Killed
 FROM targets

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Remediation.Registry</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/registryremediation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/registryremediation/</guid><description>&lt;p&gt;This artifact uses glob to remove a registry key.&lt;/p&gt;
&lt;p&gt;TypeRegex allows targeting of key or value. For service remediation key, for
run key remediation SZ or .&lt;/p&gt;
&lt;p&gt;WARNING: PLEASE SCOPE FIRST and use appropriate targeting.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Remediation.Registry
author: Matt Green - @mgreen27
description: |
 This artifact uses glob to remove a registry key.
 
 TypeRegex allows targeting of key or value. For service remediation key, for 
 run key remediation SZ or . 
 
 WARNING: PLEASE SCOPE FIRST and use appropriate targeting.
 
type: CLIENT

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: TargetRegistryGlob
 default: HKEY_LOCAL_MACHINE\SYSTEM\{CurrentControlSet,ControlSet*}\Services\ServiceName
 description: Use a glob to define the keys that will be targetted.
 - name: TypeRegex
 default: key
 description: Regex for Registry type. Usually key or SZ or .
 - name: ReallyDoIt
 description: When selected will really remove!
 type: bool

sources:
 - query: |
 SELECT OSPath, 
 Name,
 Data.type as Type,
 Data.value as Value,
 Mtime as Modified,
 if(condition=ReallyDoIt,
 then= if(condition= Data.type = 'key',
 then= reg_rm_key(path=OSPath),
 else= reg_rm_value(path=OSPath)),
 else= FALSE ) as Deleted
 FROM glob(globs=TargetRegistryGlob, accessor='registry')
 WHERE Type =~ TypeRegex
 
column_types:
 - name: Modified
 type: timestamp

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Scanner.Yara.Parsed</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.yara.yara64/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.detection.yara.yara64/</guid><description>&lt;p&gt;Instructions: Upload a yara signature file (signature file must be named yara.yas) and yara64.exe in a single zip file called yara.zip.
This artifact is an alternative way to scan processes, or recursively scan the C:\ with a yara file containing multiple yara rules, utilizing the official yara tool.&lt;/p&gt;
&lt;p&gt;This artifact will drop the yara.zip file onto the client in a temporary directory, unzip the binary and yara file,
and then iterate through every running process or file on disk. Finally, it will delete the temporary directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Scanner.Yara.Parsed
author: Dennis Yarizadeh + Chris Jones - Check Point Incident Response Team
description: |
 Instructions: Upload a yara signature file (signature file must be named yara.yas) and yara64.exe in a single zip file called yara.zip.
 This artifact is an alternative way to scan processes, or recursively scan the C:\ with a yara file containing multiple yara rules, utilizing the official yara tool. 
 
 This artifact will drop the yara.zip file onto the client in a temporary directory, unzip the binary and yara file, 
 and then iterate through every running process or file on disk. Finally, it will delete the temporary directory. 
 
tools:
 - name: yaraexecutable
 url: https://github.com/VirusTotal/yara/releases/download/v4.3.2/yara-4.3.2-2150-win64.zip
 
parameters:
 - name: ScanType
 description: "Are we scanning Processes?"
 type: bool
 default: Y
 
 - name: ThreadLimit
 description: "How many threads to utilise?"
 type: string
 default: "2"
 
sources:
 - query: |

 LET processes = SELECT * FROM pslist()
 
 LET TmpDir &amp;lt;= tempdir()

 LET YaraExePath &amp;lt;= SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="yaraexecutable", IsExecutable=FALSE, TemporaryOnly=TRUE)

 LET FetchYara &amp;lt;= SELECT * FROM unzip(filename=YaraExePath.FullPath, output_directory=TmpDir)

 -- Set EXE
 LET YaraExe &amp;lt;= TmpDir + '\\yara64.exe'

 -- Set Yara file
 Let YaraFile &amp;lt;= TmpDir + '\\yara.yas'
 
 -- Scan with Yara File
 LET Execute &amp;lt;= SELECT * FROM if (condition=ScanType, then={SELECT * FROM foreach(row=processes,
 query={
 SELECT Name, Pid, Ppid, Stdout FROM execve(argv=[YaraExe, YaraFile, Pid, "-p", ThreadLimit])
 })},
 
 else = { 
 SELECT Stdout FROM execve(argv=[YaraExe, YaraFile, "-r", "C:\\", "-g", "-p", ThreadLimit])})
 
 --Read Data
 LET Query = SELECT Stdout FROM Execute
 
 LET ParseLines = SELECT * FROM parse_lines(filename=Query.Stdout, accessor="data")
 
 LET YaraGrok = "%{WORD:category} \\[\\] %{GREEDYDATA:file_path}"
 
 LET ParsedData = SELECT grok(grok=YaraGrok, data=Line) AS Parsed FROM ParseLines
 
 SELECT Parsed.category AS Category, Parsed.file_path AS `File Path` FROM ParsedData

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Services.Hijacking</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.services.hijacking/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.services.hijacking/</guid><description>&lt;p&gt;Service Executable Hijacking is a misconfiguration flaw, where a service runs an executable which has
overly permissive permissions on it (for example: &amp;ldquo;Full Control&amp;rdquo; permissions to &amp;ldquo;Authenticated Users&amp;rdquo;).
If a service runs under the security context of a user with high permissions (such as: NT Authority\SYSTEM),
and an attacker with low privileges is able to modify the executable that service is running (such as
replacing it with their own) - the service could run that executable with high privileges.&lt;/p&gt;
&lt;p&gt;This hunt finds all Windows services which are vulnerable to service executable hijacking.
It does so in the following manner:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enumerate all services, and extract the full path of their executables.&lt;/li&gt;
&lt;li&gt;Run an external Powershell script to enumerate the ACLs of those executables.&lt;/li&gt;
&lt;li&gt;Display all relevant information regarding found vulnerable services.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;#services #hijacking&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Services.Hijacking
description: |
 Service Executable Hijacking is a misconfiguration flaw, where a service runs an executable which has 
 overly permissive permissions on it (for example: "Full Control" permissions to "Authenticated Users").
 If a service runs under the security context of a user with high permissions (such as: NT Authority\SYSTEM), 
 and an attacker with low privileges is able to modify the executable that service is running (such as 
 replacing it with their own) - the service could run that executable with high privileges.
 
 This hunt finds all Windows services which are vulnerable to service executable hijacking. 
 It does so in the following manner:
 1. Enumerate all services, and extract the full path of their executables.
 2. Run an external Powershell script to enumerate the ACLs of those executables.
 3. Display all relevant information regarding found vulnerable services.
 
 #services #hijacking

author: "Yaron King - @Sam0rai"

type: CLIENT

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

 query: |
 LET services = SELECT *
 FROM Artifact.Windows.System.Services()

 LET Script &amp;lt;= tempfile(data='''
 $glob = $args[0]
 $pathsArray = $glob -split ";"
 $aclArray = @()
 foreach($filePath in $pathsArray) {
 foreach($acl in (Get-Acl $filePath).Access) {
 $obj = new-object PSObject -Property @{
 FilePath = $filePath
 IdentityReference = $acl.IdentityReference.Value
 FileSystemRights = $acl.FileSystemRights
 IsInherited = $acl.IsInherited
 InheritanceFlags = $acl.InheritanceFlags
 PropagationFlags = $acl.PropagationFlags
 }
 $aclArray += $obj
 }
 }
 $aclArray | ConvertTo-Json
 ''', extension=".ps1")
 
 Let servicesPath = Select AbsoluteExePath, count() AS Count
 FROM services
 GROUP BY AbsoluteExePath
 
 LET ExecutableACLs = SELECT * FROM foreach(
 row={
 SELECT Stdout FROM execve(argv=["Powershell", "-ExecutionPolicy",
 "bypass", "-file", Script, join(array=servicesPath.AbsoluteExePath, sep=";")], length=1000000)
 }, query={
 SELECT * FROM parse_json_array(data=Stdout)
 })
 
 // Dictionary of hard-coded File System Rights index numbers to human-readable strings
 LET FileSystemRightsDict = dict(
 `2032127` = "Full Control",
 `1180063` = "Read, Write",
 `1245631` = "Change",
 `1180095` = "ReadAndExecute, Write",
 `268435456` = "FullControl (Sub Only)")

 LET ExecutableACLs_Filtered = SELECT FilePath, IdentityReference, get(item=FileSystemRightsDict, member=str(str=FileSystemRights)) AS Permissions, FileSystemRights, IsInherited, InheritanceFlags, PropagationFlags
 FROM ExecutableACLs
 WHERE (
 IdentityReference != "BUILTIN\\Administrators" and
 IdentityReference != "NT AUTHORITY\\SYSTEM" and
 IdentityReference != "NT SERVICE\\TrustedInstaller"
 ) 
 and (
 FileSystemRights = 2032127 or -- NTFS permission "Full Control" 
 FileSystemRights = 1180063 or -- NTFS permission "Read, Write"
 FileSystemRights = 1245631 or -- NTFS permission "Change"
 FileSystemRights = 1180095 or -- NTFS permission "ReadAndExecute, Write"
 FileSystemRights = 268435456 -- NTFS permission "FullControl (Sub Only)" 
 )
 
 SELECT * FROM foreach(
 row={SELECT * FROM ExecutableACLs_Filtered},
 query={
 SELECT Name, DisplayName, State, Status, StartMode, PathName, AbsoluteExePath as Command, UserAccount, Permissions, IdentityReference as UserWithPermissions, Created
 FROM services
 WHERE AbsoluteExePath = FilePath
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Ssh.AuthorizedKeys</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.ssh.authorizedkeys/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.ssh.authorizedkeys/</guid><description>&lt;p&gt;Find and parse ssh authorized keys files on Windows running OpenSSH service.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Ssh.AuthorizedKeys
author: Ján Trenčanský - j91321@infosec.exchange
description: |
 Find and parse ssh authorized keys files on Windows running OpenSSH service.

reference:
 - https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement?source=recommendations

parameters:
 - name: userSshKeyFiles
 default: '.ssh\authorized_keys*'
 description: Glob of authorized_keys file relative to a user's home directory.

 - name: adminSshKeyFiles
 default: 'administrators_authorized_keys*'
 description: Glob of administrator_authorized_keys

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

type: CLIENT
sources:
 - name: User Keys
 query: |
 LET authorized_keys = SELECT * from foreach(
 row={
 SELECT Uid, Name, Directory from Artifact.Windows.Sys.Users()
 },
 query={
 SELECT OSPath, Mtime, Ctime, Uid
 FROM glob(root=Directory, globs=userSshKeyFiles)
 })
 
 SELECT * from foreach(
 row=authorized_keys,
 query={
 SELECT Uid, OSPath, Key, Comment, Mtime
 FROM split_records(
 filenames=OSPath, regex=" +", columns=["Type", "Key", "Comment"])
 WHERE Type =~ "ssh"
 })
 
 - name: Admin Keys
 query: |
 LET administrators_authorized_keys = SELECT OSPath, Mtime, Ctime, Uid FROM glob(root='C:\\ProgramData\\ssh\\', globs=adminSshKeyFiles)
 SELECT * from foreach(
 row=administrators_authorized_keys,
 query={
 SELECT Uid, OSPath, Key, Comment, Mtime
 FROM split_records(
 filenames=OSPath, regex=" +", columns=["Type", "Key", "Comment"])
 WHERE Type =~ "ssh"
 })
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Sys.BitLocker</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sys.bitlocker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sys.bitlocker/</guid><description>&lt;p&gt;This artifact gets all Bitlocker volumes using PowerShell, including the recovery password.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Sys.BitLocker
author: Zane Gittins
description: |
 This artifact gets all Bitlocker volumes using PowerShell, including the recovery password.

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

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

 query: |
 LET PowershellScript = '''$Results = @()
 $BitlockerVolumes = Get-BitLockerVolume
 $BitlockerVolumes |
 ForEach-Object {
 $RecoveryKey = [string]($_.KeyProtector).RecoveryPassword
 # Only add results with valid recovery keys.
 if ($RecoveryKey.Length -gt 5) {
 $_ | Add-Member -MemberType NoteProperty -Name "RecoveryPassword" -Value $RecoveryKey
 $Results += $_
 }
 }
 
 return ConvertTo-Json -InputObject @($Results)
 '''
 SELECT * FROM foreach(
 row={
 SELECT Stdout FROM execve(argv=["Powershell", "-ExecutionPolicy",
 "unrestricted", "-c", PowershellScript], length=1000000)
 }, query={
 SELECT * FROM parse_json_array(data=Stdout)
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Sys.LoggedInUsers</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sys.loggedinusers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sys.loggedinusers/</guid><description>&lt;p&gt;Get all currently logged in users via wmi.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Sys.LoggedInUsers
author: Zane Gittins
description: |
 Get all currently logged in users via wmi.

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT
type: CLIENT

parameters:
 - name: UserNameRegex
 default: .
 type: string
 description: Filter by username.
 - name: DomainRegex
 default: .
 type: string
 description: Filter by domain.
 - name: LogonTypeRegex
 default: .
 type: string
 description: Filter by logon type. For example, 10 for remote.

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

 query: |
 // Helper functions
 LET _X(X) = parse_string_with_regex(regex="(^.+)(-\\d+)$", string=X)
 LET NormalizeTime(X) = format(
 format="%s%03g00",
 args=[_X(X=X).g1, int(int=_X(X=X).g2) / 60])
 LET ParseTime(X) = timestamp(
 string=NormalizeTime(X=X),
 format="20060102150405.999999-0700")
 LET ExtractDomain(X) = parse_string_with_regex(
 string=X,
 regex=['Domain=\\"(.*?)\\"']).g1
 LET ExtractLogonName(X) = parse_string_with_regex(
 string=X,
 regex=['Name=\\"(.*)\\"']).g1
 LET ExtractLogonID(X) = parse_string_with_regex(
 string=X,
 regex=['LogonId=\\"([0-9]+)\\"']).g1
 LET FormatTime(Time) = timestamp(
 string=regex_replace(source=Time, replace="-0", re="-"),
 format=TimeFormat)
 LET CurrentlyLoggedIn &amp;lt;= SELECT ExtractDomain(X=Antecedent) AS Domain,
 ExtractLogonName(X=Antecedent) AS LogonName,
 ExtractLogonID(X=Dependent) AS CurrentLogonId
 FROM wmi(query="SELECT * FROM win32_loggedonuser", namespace="ROOT/CIMV2")
 WHERE LogonName =~ UserNameRegex
 // WMI Queries
 LET Sessions &amp;lt;= SELECT *
 FROM wmi(query="SELECT * FROM Win32_LogonSession", namespace="ROOT/CIMV2")
 LET Processes &amp;lt;= SELECT 
 ExtractLogonID(X=Antecedent) AS LogonID,
 count() AS ProcessCount
 FROM wmi(query="SELECT * from Win32_SessionProcess", namespace="ROOT/CIMV2")
 GROUP BY LogonID
 LET CurrentSessions = SELECT *, {
 SELECT *
 FROM CurrentlyLoggedIn
 WHERE LogonID = CurrentLogonId
 AND Domain =~ DomainRegex
 AND LogonType =~ LogonTypeRegex
 } AS LoginInfo,
 {
 SELECT *
 FROM Sessions
 WHERE LogonID = LogonId
 } AS SessionInfo
 FROM Processes
 // Final query 
 SELECT 
 ParseTime(X=SessionInfo.StartTime) AS Timestamp,
 LoginInfo.LogonName AS LogonName,
 LoginInfo.Domain AS Domain,
 ProcessCount,
 SessionInfo.LogonType AS LogonType,
 SessionInfo.LogonId AS LogonID,
 SessionInfo.AuthenticationPackage AS AuthenticationPackage
 FROM CurrentSessions
 WHERE LogonName =~ UserNameRegex
 AND Domain =~ DomainRegex
 AND LogonType =~ LogonTypeRegex
 ORDER BY Timestamp DESC

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Sysinternals.PSShutdown</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sysinternals.psshutdown/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.sysinternals.psshutdown/</guid><description>&lt;p&gt;PsShutdown is a command-line utility similar to the shutdown utility from the Windows 2000 Resource Kit, but with the ability to do much more. In addition to supporting the same options for shutting down or rebooting the local or a remote computer, PsShutdown can logoff the console user or lock the console (locking requires Windows 2000 or higher). PsShutdown requires no manual installation of client software.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Sysinternals.PSShutdown
description: |
 PsShutdown is a command-line utility similar to the shutdown utility from the Windows 2000 Resource Kit, but with the ability to do much more. In addition to supporting the same options for shutting down or rebooting the local or a remote computer, PsShutdown can logoff the console user or lock the console (locking requires Windows 2000 or higher). PsShutdown requires no manual installation of client software.
author: Ian Boje

# Can be CLIENT, CLIENT_EVENT, SERVER, SERVER_EVENT or NOTEBOOK
type: CLIENT

parameters:
 - name: Action
 default: Reboot
 type: choices
 choices:
 - Abort
 - Suspend
 - Hybernate
 - Poweroff
 - Lock
 - Logoff console user
 - Reboot
 - Shutdown without poweroff
 - Turn off monitor
 - name: time
 default: 30
 description: -t Can be either seconds, or 24 hour clock
 - name: abortable
 type: bool
 description: -c Allows user to cancel shutdown 
 default: Y
 - name: force
 type: bool
 description: -f Forces all running applications to exit during the shutdown instead of giving them a chance to gracefully save their data.
 - name: message
 description: -m This option lets you specify a message to display to logged-on users when a shutdown countdown commences.
 - name: msgtime
 description: -v Display message for the specified number of seconds before the shutdown. If set to 0, no dialog will be displayed.

tools:
 - name: PSShutdown64
 url: https://live.sysinternals.com/tools/psshutdown64.exe
 serve_locally: true
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'

 query: |
 LET PSShutdown64bin &amp;lt;= select * from Artifact.Generic.Utils.FetchBinary(ToolName="PSShutdown64")
 
 LET ActionArg &amp;lt;= "-r" -- Default if nothing matches
 LET ActionArg &amp;lt;= if(condition=Action="Suspend", then="-d", else=ActionArg)
 LET ActionArg &amp;lt;= if(condition=Action="Hybernate", then="-h", else=ActionArg)
 LET ActionArg &amp;lt;= if(condition=Action="Poweroff", then="-k", else=ActionArg)
 LET ActionArg &amp;lt;= if(condition=Action="Logoff console user", then="-o", else=ActionArg)
 LET ActionArg &amp;lt;= if(condition=Action="Reboot", then="-r", else=ActionArg)
 LET ActionArg &amp;lt;= if(condition=Action="Shutdown without poweroff", then="-s", else=ActionArg)
 
 
 LET args &amp;lt;= (
 PSShutdown64bin[0].OSPath,
 "-accepteula",
 ActionArg,
 "-t",
 time,
 if(condition=message, then="-m", else=""),
 if(condition=message, then=message, else=""),
 if(condition=abortable, then="-c", else=""),
 if(condition=force, then="-f", else=""),
 if(condition=msgtime, then="-v", else=""),
 if(condition=msgtime, then=msgtime, else="")
 )
 
 -- abort -a deletes all other switches
 LET args &amp;lt;= if(condition=Action="Abort", then=(PSShutdown64bin[0].OSPath, "-a"), else=args)
 -- so does lock -l
 LET args &amp;lt;= if(condition=Action="Lock", then=(PSShutdown64bin[0].OSPath, "-l"), else=args)
 -- monitor shutdown too 
 LET args &amp;lt;= if(condition=Action="Turn off monitor", then=(PSShutdown64bin[0].OSPath, "-x"), else=args)
 
 LET args &amp;lt;= filter(list=args, regex=".+")
 
 SELECT *, args as command FROM execve(argv=args)
 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Sysinternals.SysmonArchive</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonarchive/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sysmonarchive/</guid><description>&lt;p&gt;If configured, Sysmon EID 23: FileDelete enables archiving file deletes on
disk. The challenges of this configuration is management of the archive
folder which can grow to be significant size and use up disk space.&lt;/p&gt;
&lt;p&gt;This artifact enables management of the archive, listing files and removing
old files over a configured maximum.&lt;/p&gt;
&lt;p&gt;For monitoring: Use in combination with Windows.Events.SysmonArchive&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Sysinternals.SysmonArchive
author: Matt Green - @mgreen27
description: |
 If configured, Sysmon EID 23: FileDelete enables archiving file deletes on 
 disk. The challenges of this configuration is management of the archive 
 folder which can grow to be significant size and use up disk space. 
 
 This artifact enables management of the archive, listing files and removing 
 old files over a configured maximum.
 
 For monitoring: Use in combination with Windows.Events.SysmonArchive
 
reference:
 - https://github.com/trustedsec/SysmonCommunityGuide/blob/master/chapters/file-delete.md
 - https://isc.sans.edu/diary/Sysmon+and+File+Deletion/26084
 
parameters:
 - name: SysmonArchiveGlob
 description: Glob to target configured Sysmon archive folder contents.
 default: C:\Sysmon\*
 - name: ArchiveSize
 description: Desired size of archive in bytes. Default is ~1GB.
 default: 1000000000
 type: int64
 - name: DeleteFiles
 description: When selected will delete older files outside configured archive size.
 type: bool
 - name: ShowAll
 description: When selected will show all files in Sysmon archive folder.
 type: bool

sources:
 - query: |
 LET files = SELECT Ctime,OSPath,Size
 FROM glob(globs=SysmonArchiveGlob,accessor='ntfs')
 WHERE NOT IsDir AND NOT IsLink
 ORDER BY Ctime DESC
 
 LET calc_sum = SELECT *, sum(item=Size) as TotalSize
 FROM files
 
 SELECT Ctime, OSPath,Size,TotalSize,
 if(condition= TotalSize &amp;gt; ArchiveSize,
 then= if(condition= DeleteFiles, then=rm(filename=OSPath), else='To delete'),
 else= 'Not to delete') as Delete
 FROM calc_sum
 WHERE if(condition= ShowAll,
 then= TRUE,
 else= TotalSize &amp;gt; ArchiveSize) 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.AccessControlList</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.accesscontrollist/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.accesscontrollist/</guid><description>&lt;p&gt;This artifact displays the access control lists of files.&lt;/p&gt;
&lt;p&gt;Note: This artifact uses Powershell to gather the information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.AccessControlList
description: |
 This artifact displays the access control lists of files.

 Note: This artifact uses Powershell to gather the information.

type: CLIENT

parameters:
 - name: Glob
 description: A search expression that will be passed to Powershell
 default: C:\Windows\System32\Config\s*
 - name: ACLFilter
 description: Only show files with ACLs that match this regex.
 default: BUILTIN\\Users.+Allow

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

 query: |
 LET Script &amp;lt;= tempfile(data='''
 $glob = $args[0]
 Get-Acl $glob | select Path, Owner, Group, AccessToString | convertto-json
 ''', extension=".ps1")

 LET Results = SELECT parse_json_array(data=Stdout) AS Rows
 FROM execve(argv=["powershell", "-executionpolicy",
 "bypass", "-file", Script, Glob], length=100000)

 SELECT * FROM foreach(row=Results.Rows,
 query={
 SELECT parse_string_with_regex(string=Path, regex="FileSystem::(.+)").g1 AS Path,
 Owner, Group, split(string=AccessToString, sep="\n") AS ACLS
 FROM _value
 })
 WHERE ACLS =~ ACLFilter

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.AppCompatPCA</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.appcompatpca/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.appcompatpca/</guid><description>&lt;p&gt;Parse the Program Compatibility Assistant launch dictionary for executable launch times.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.AppCompatPCA
description: |
 Parse the Program Compatibility Assistant launch dictionary for executable launch times.

author: Eric Capuano - @eric_capuano@infosec.exchange

reference:
 - https://aboutdfir.com/new-windows-11-pro-22h2-evidence-of-execution-artifact/

type: CLIENT
parameters:
 - name: FileGlob
 default: C:\Windows\appcompat\pca\PcaAppLaunchDic.txt
 - name: ExecutableRegex
 description: "Regex of EXE of interest."
 default: .
 - name: SearchVSS
 description: "Add VSS into query."
 type: bool

sources:
 - query: |

 -- expand provided glob into a list of paths on the file system (fs)
 LET fspaths &amp;lt;= SELECT FullPath FROM glob(globs=expand(path=FileGlob))

 -- function returning list of VSS paths corresponding to path
 LET vsspaths(path) = SELECT FullPath
 FROM Artifact.Windows.Search.VSS(SearchFilesGlob=path)

 LET parse_log(FullPath) = SELECT FullPath,
 parse_string_with_regex(
 string=Line,
 regex="^(?P&amp;lt;ExePath&amp;gt;[^|]+)\\|" +
 "(?P&amp;lt;LastExecuted&amp;gt;.*)") as Record
 FROM parse_lines(filename=FullPath)
 WHERE Line
 AND Record.ExePath =~ ExecutableRegex

 LET logsearch(PathList) = SELECT * FROM foreach(
 row=PathList,
 query={
 SELECT *
 FROM parse_log(FullPath=FullPath)
 })

 LET include_vss = SELECT * FROM foreach(row=fspaths,
 query={
 SELECT *
 FROM logsearch(PathList={
 SELECT FullPath FROM vsspaths(path=FullPath)
 })
 GROUP BY Record
 })

 LET exclude_vss = SELECT * FROM logsearch(PathList={SELECT FullPath FROM fspaths})

 SELECT
 Record.ExePath as ExePath,
 Record.LastExecuted as LastExecuted,
 FullPath
 FROM if(condition=SearchVSS,
 then=include_vss,
 else=exclude_vss)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.AutoLoggerDiagtrackListener</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/autologgerdiagtracklistener/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/autologgerdiagtracklistener/</guid><description>&lt;p&gt;AutoLogger-Diagtrack-Listener.etl is a potential source of evidence of
execution and other system diagnostic data.&lt;/p&gt;
&lt;p&gt;If AutoLogger-Diagtrack-Listener.etl exists, we use the built-in tracerpt to
parse and extract each XML record as a row.&lt;/p&gt;
&lt;p&gt;NOTE: A good workflow is running Windows.Search.FileFinder or Yara.Glob
targeting strings of interest, then running AutoLoggerDiagtrackListener to
parse hits.&lt;/p&gt;
&lt;p&gt;ETL Globs: &lt;br&gt;
&lt;code&gt;C:/ProgramData/Microsoft/Diagnosis/ETLLogs/**/*.etl&lt;/code&gt;&lt;br&gt;
&lt;code&gt;C:/Windows/System32/LogFiles/**/*.etl&lt;/code&gt;&lt;br&gt;
&lt;code&gt;C:/Windows/System32/WDI/**/*.etl&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.AutoLoggerDiagtrackListener
author: Matt Green - @mgreen27
description: |
 AutoLogger-Diagtrack-Listener.etl is a potential source of evidence of 
 execution and other system diagnostic data.
 
 If AutoLogger-Diagtrack-Listener.etl exists, we use the built-in tracerpt to 
 parse and extract each XML record as a row.
 
 NOTE: A good workflow is running Windows.Search.FileFinder or Yara.Glob 
 targeting strings of interest, then running AutoLoggerDiagtrackListener to 
 parse hits.
 
 ETL Globs: 
 `C:/ProgramData/Microsoft/Diagnosis/ETLLogs/**/*.etl` 
 `C:/Windows/System32/LogFiles/**/*.etl` 
 `C:/Windows/System32/WDI/**/*.etl` 

reference:
 - https://www.fortinet.com/blog/threat-research/uncovering-hidden-forensic-evidence-in-windows-mystery-of-autologger
 
type: CLIENT

parameters:
 - name: TargetGlob
 default: C:\\ProgramData\\Microsoft\\Diagnosis\\ETLLogs\\AutoLogger\\AutoLogger-Diagtrack-Listener.etl
 - name: EventNameRegex
 default: .
 description: Regex to filter on EventName - E.g ProcessStarted
 - name: EventDataRegex
 default: .
 description: Regex to filter rows returned on EventData

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

 query: |
 LET out_folder &amp;lt;= tempdir(remove_last=true)
 
 LET target_files = SELECT
 OSPath,
 Size,
 Mtime,
 Btime,
 path_join(components=[out_folder, str(str=count()) + "parsed_etl.xml"],
 path_type='windows') AS ParsedOutput
 FROM glob(globs=TargetGlob)
 
 LET parse_etl(path, out) = SELECT *
 FROM execve(argv=['cmd.exe', '/c', 'tracerpt', path, '-o', out, '-y'])
 
 LET run_parser &amp;lt;= SELECT *
 FROM foreach(row=target_files,
 query={
 SELECT OSPath,
 ParsedOutput,
 *
 FROM parse_etl(path=OSPath, out=ParsedOutput)
 WHERE Stdout =~ 'The command completed successfully.'
 })
 
 LET event_records = SELECT *
 FROM foreach(row=run_parser,
 query={
 SELECT parse_xml(accessor='data', file=Record) AS Parsed,
 OSPath
 FROM parse_records_with_regex(file=ParsedOutput,
 regex='(?s)(?P&amp;lt;Record&amp;gt;&amp;lt;Event .*?&amp;lt;/Event&amp;gt;)')
 })
 
 SELECT
 Parsed.Event.System.TimeCreated.AttrSystemTime AS EventTime,
 Parsed.Event.System.Provider.AttrName AS Provider,
 Parsed.Event.RenderingInfo.Task || Parsed.Event.RenderingInfo.Opcode AS EventName,
 Parsed.Event.System.Execution.AttrProcessID AS SourcePid,
 Parsed.Event.System.EventID AS EventID,
 if(
 condition=Parsed.Event.EventData.Data,
 then=to_dict(
 item={
 SELECT
 AttrName AS _key,
 `#text` AS _value
 FROM Parsed.Event.EventData.Data
 }),
 else=Parsed.Event.EventData) AS EventData,
 OSPath
 FROM event_records
 WHERE EventName =~ EventNameRegex
 AND EventData =~ EventDataRegex

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.BinaryVersion</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/binaryversion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/binaryversion/</guid><description>&lt;p&gt;This artifact will search the MFT for any matching filenames and return
binary details. This artifact can be used to find all instances of a
binary on disk so its great for scoping both legititimate and illegitimate
files.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.BinaryVersion
author: "Matt Green - @mgreen27"
description: |
 This artifact will search the MFT for any matching filenames and return
 binary details. This artifact can be used to find all instances of a 
 binary on disk so its great for scoping both legititimate and illegitimate 
 files.

parameters:
 - name: TargetLibrary
 default: 'kernel32.dll'
 description: regex of target library filename e.g file.dll or ^(file.dll|file2.exe)$
 - name: TargetDrive
 default: 'C:\'
 - name: TargetAllDrives
 type: bool
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'

 query: |
 LET hits = SELECT FileName, OSPath,
 dict(
 LastModified0x10=LastModified0x10,
 LastAccess0x10=LastAccess0x10,
 LastRecordChange0x10=LastRecordChange0x10,
 Created0x10=Created0x10
 ) as SI_Timestamps,
 dict(
 LastModified0x30=LastModified0x30,
 LastAccess0x30=LastAccess0x30,
 LastRecordChange0x30=LastRecordChange0x30,
 Created0x30=Created0x30
 ) as FN_Timestamps,
 SI_Lt_FN, uSecZeros,
 parse_pe(file=OSPath) as PE,
 authenticode(filename=OSPath) as Authenticode,
 InUse,
 FileSize
 FROM Artifact.Windows.NTFS.MFT(MFTDrive=TargetDrive,
 AllDrives=TargetAllDrives,
 FileRegex=TargetLibrary)

 SELECT *,
 InUse as MFTAllocated,
 hash(path=OSPath) as Hash,
 PE,
 Authenticode
 FROM hits
 WHERE PE OR Authenticode OR MFTAllocated = 'false'

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.IsClrProcess</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/isclrprocess/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/isclrprocess/</guid><description>&lt;p&gt;Identify running processes that host the .NET Common Language Runtime (CLR) and
highlight suspicious processes where CLR visibility may be reduced, downgraded,
or disabled.&lt;/p&gt;
&lt;p&gt;Capablities include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CLR capable process discovery by finding &lt;code&gt;mscoree.dll&lt;/code&gt; import&lt;/li&gt;
&lt;li&gt;Brief CLR Rundown ETW collection to determine events active&lt;/li&gt;
&lt;li&gt;Runs Mem2Disk targetting commonly CLR patched DLLs&lt;/li&gt;
&lt;li&gt;Checks COMPlus_ETWEnabled environment variable&lt;/li&gt;
&lt;li&gt;Collects CLR.dll VersionInformation&lt;/li&gt;
&lt;li&gt;CommandLine visibility&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: for Mem2Disk capability, the artifact expects the imported name: Windows.Memory.Mem2Disk.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.IsClrProcess
author: Matt Green - @mgreen27
description: |
 Identify running processes that host the .NET Common Language Runtime (CLR) and
 highlight suspicious processes where CLR visibility may be reduced, downgraded, 
 or disabled.

 Capablities include:
 - CLR capable process discovery by finding `mscoree.dll` import
 - Brief CLR Rundown ETW collection to determine events active
 - Runs Mem2Disk targetting commonly CLR patched DLLs
 - Checks COMPlus_ETWEnabled environment variable
 - Collects CLR.dll VersionInformation
 - CommandLine visibility

 NOTE: for Mem2Disk capability, the artifact expects the imported name: Windows.Memory.Mem2Disk.
 
parameters:
- name: ProcessRegex
 default: .
 type: regex
- name: PidRegex
 default: .
 type: regex
- name: ExePathRegex
 default: .
 type: regex
- name: CommandLineRegex
 default: .
 type: regex
- name: UsernameRegex
 default: .
 type: regex
- name: CheckForPatches
 type: bool
- name: ModuleRegEx
 default: \\(clr|amsi|ntdll|kernel32|Mp0av.dll|wldap32)\.dll$
 type: regex

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

 query: |
 LET clr_processes &amp;lt;= SELECT Pid, Ppid, TokenIsElevated, Name, Exe, CommandLine,Username,
 parse_pe(file=Exe) as PEInfo
 FROM pslist()
 WHERE Name =~ ProcessRegex
 AND Pid =~ PidRegex
 AND Exe =~ ExePathRegex
 AND CommandLine =~ CommandLineRegex
 AND Username =~ UsernameRegex
 AND ( PEInfo.Imports =~ 'mscoree' 
 OR PEInfo.Directories.DotNet_Directory )
 
 LET clr_details &amp;lt;= SELECT
 System.ProcessID AS ProcessID,
 dict(
 ClrInstanceID=EventData.ClrInstanceID,
 ClrVersion=format(
 format='%s.%s.%s.%s',
 args=[
 EventData.VMMajorVersion, 
 EventData.VMMinorVersion,
 EventData.VMBuildNumber, 
 EventData.VMQfeNumber]),
 RuntimeDllPath=EventData.RuntimeDllPath
 ) as ClrDetails
 FROM watch_etw(description="CLR Rundown Provider",
 guid="{A669021C-C450-4609-A035-5AF59AF4DF18}",
 any=0x40,
 timeout=20 )
 WHERE ProcessID =~ join(array=clr_processes.Pid,sep='|')
 AND System.ID = 187 
 
 LET find_clr(pid) = SELECT * FROM clr_details WHERE ProcessID = pid
 
 LET results &amp;lt;= SELECT *, 
 find_clr(pid=Pid).ClrDetails as ClrDetails
 FROM clr_processes
 
 LET find_dll(pid,modulename) = SELECT dict(ModulePath=ExePath) + parse_pe(file=ExePath).VersionInformation as VersionInformation
 FROM modules(pid=Pid)
 WHERE lowcase(string=ModuleName) = lowcase(string=modulename)
 
 
 LET find_functions(pid) = SELECT regex_replace(
 source=split(string=Functions,sep_string='+')[0],
 re='''\!0x.+$''',
 replace="!0xHexAddr"
 ) as Functions
 FROM flatten(query={ 
 SELECT Differences.Func As Functions 
 FROM Artifact.Windows.Memory.Mem2Disk(
 PidFilter="^" + pid + "$",
 ModuleRegEx=ModuleRegEx 
 )
 })
 GROUP BY Functions
 LET find_modules(pid) = SELECT Path 
 FROM Artifact.Windows.Memory.Mem2Disk(
 PidFilter="^" + pid + "$",
 ModuleRegEx=ModuleRegEx 
 )
 GROUP BY Path
 
 LET check_complus(pid) = SELECT 
 if(condition = Env.COMPlus_ETWEnabled="0",
 then = TRUE,
 else = FALSE ) as EnvDisabled
 FROM Artifact.Windows.Memory.ProcessInfo(PidRegex=pid)

 
 SELECT 
 Pid, Ppid, Name, Exe, CommandLine,
 Username, TokenIsElevated,
 filter(list=PEInfo.Imports,regex='mscoree')[0] as MscoreeImport,
 if(condition=ClrDetails,
 then=ClrDetails[0],
 else='ETW disabled or Potential downgraded CLR') as Functions,
 find_dll(pid=Pid,modulename="clr.dll")[0].VersionInformation as CLRmodule,
 if(condition= version(function="describe_address") != NULL,
 then= find_functions(pid=str(str=Pid)).Functions,
 else= find_modules(pid=str(str=Pid)).Path 
 ) as PotentialPatches,
 check_complus(pid=str(str=Pid))[0].EnvDisabled as EnvDisabled
 FROM results

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.PowerEfficiencyDiagnostics</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/powerefficiencydiagnostics/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/powerefficiencydiagnostics/</guid><description>&lt;p&gt;This artifact parses the XML Energy Reports from the Power Efficiency
Diagnostics feature of Windows, returning the processes which had high
CPU usage, including which&lt;/p&gt;
&lt;p&gt;Some tools utilized by threat actors will generate high CPU usage and so
are recorded in these reports.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.PowerEfficiencyDiagnostics
author: "Eduardo Mattos - @eduardfir"
description: |
 This artifact parses the XML Energy Reports from the Power Efficiency 
 Diagnostics feature of Windows, returning the processes which had high 
 CPU usage, including which 
 
 Some tools utilized by threat actors will generate high CPU usage and so 
 are recorded in these reports.

reference:
 - https://twitter.com/rj_chap/status/1502354627903123458
 
parameters:
 - name: TargetGlob
 default: C:\ProgramData\Microsoft\Windows\Power Efficiency Diagnostics\*.xml

sources:
 - query: |
 -- select XML reports
 LET Targets &amp;lt;= SELECT FullPath, Mtime as FileMtime FROM glob(globs=TargetGlob)

 -- parse XML reports and return specific CPU Usage entries
 LET SigProcUtil &amp;lt;= SELECT 
 parse_xml(file=FullPath).EnergyReport.Troubleshooter[5].AnalysisLog.LogEntry.Details.Detail as LogDetail,
 FullPath,
 FileMtime
 FROM Targets
 
 -- iterate through nested entries and return relevant fields
 SELECT 
 { SELECT get(item=_value, field="Value") as Value from foreach(row=LogDetailEntry) 
 WHERE _value.Name = "Process Name"
 } as ProcessName, 
 { SELECT get(item=_value, field="Value") as Value from foreach(row=LogDetailEntry) 
 WHERE _value.Name = "PID"
 } as PID,
 { SELECT get(item=_value, field="Value") as Value from foreach(row=LogDetailEntry) 
 WHERE _value.Name = "Average Utilization (%)"
 } as AvgUtilization,
 { SELECT get(item=_value, field="Value") as Value from foreach(row=LogDetailEntry) 
 WHERE _value.Name = "Module"
 } as Modules,
 FullPath,
 FileMtime
 FROM foreach(row=SigProcUtil, 
 query= {
 SELECT _value as LogDetailEntry, FullPath, FileMtime FROM foreach(row=SigProcUtil[0].LogDetail) 
 })
 WHERE ProcessName

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.Powershell.ISEAutoSave</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/iseautosave/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/iseautosave/</guid><description>&lt;p&gt;This artifact hunts for Powershell ISE autosave files and extracts ISE user
config.&lt;/p&gt;
&lt;p&gt;Powershell ISE generates auto-save files for if the editor crashes.&lt;br&gt;
user.config holds ISE session metadata including a MRU for the relevant user.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.Powershell.ISEAutoSave
description: |
 This artifact hunts for Powershell ISE autosave files and extracts ISE user 
 config.
 
 Powershell ISE generates auto-save files for if the editor crashes. 
 user.config holds ISE session metadata including a MRU for the relevant user. 
 
type: CLIENT

parameters:
 - name: AutoSaveFiles
 default: C:\Users\*\AppData\*\Microsoft_Corporation\Powershell_ISE.exe*\*\AutoSaveFiles\*.ps1
 description: ISE Autosave file glob
 - name: UserConfig
 default: C:\Users\*\AppData\*\Microsoft_Corporation\Powershell_ISE.exe*\*\user.config
 description: ISE user config file glob
 - name: ContentRegex
 default: .
 description: Content regex to hunt for in ISEAutoSave files
 - name: ContentWhitelist
 default:
 description: Content whitelist to exclude from results in ISEAutoSave files
 

sources:
 - precondition: SELECT OS From info() where OS = 'windows'
 query: |
 LET files = SELECT OSPath, Size, Mtime, Btime, Ctime, Atime
 FROM glob(globs=AutoSaveFiles)
 
 SELECT 
 OSPath, Size, Mtime, Btime, Ctime, Atime,
 read_file(filename=OSPath) as Content
 FROM foreach(row=files)
 WHERE Content =~ ContentRegex
 AND NOT if(condition=ContentWhitelist,
 then= Content =~ ContentWhitelist,
 else= False )


 - name: UserConfig
 query: |
 LET files = SELECT OSPath, Size, Mtime, Btime, Ctime, Atime
 FROM glob(globs=UserConfig)
 
 SELECT 
 OSPath, Size, Mtime, Btime, Ctime, Atime,
 parse_xml(file=Data,accessor='data').configuration.userSettings.UserSettings.setting[5].value.ArrayOfString.string as MRU,
 parse_xml(file=Data,accessor='data').configuration as Configuration,
 Data as RawXml
 FROM foreach(row=files, query={
 SELECT *, OSPath, Size, Mtime, Btime, Ctime, Atime 
 FROM read_file(filenames=OSPath)
 WHERE OSPath =~ 'user.config$'
 })

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.PrinterDriver</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/printerdriver/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/printerdriver/</guid><description>&lt;p&gt;This artifact will enumerate installed PrintDrivers using the
Win32_PrinterDriver wmi class and parse each DriverPath, ConfigFile
and DataFile.&lt;/p&gt;
&lt;p&gt;Hunt by searching for untrusted binaries or suspicious removed
binararies for evidence of previous exploitation.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.PrinterDriver
author: Matt Green - @mgreen27
description: |
 This artifact will enumerate installed PrintDrivers using the
 Win32_PrinterDriver wmi class and parse each DriverPath, ConfigFile
 and DataFile.

 Hunt by searching for untrusted binaries or suspicious removed
 binararies for evidence of previous exploitation.

type: CLIENT

sources:
 - query: |
 LET Win32_PrinterDrivers = SELECT
 split(string=Name, sep=',')[0] as Name,
 SupportedPlatform,
 Version,
 DriverPath,
 ConfigFile,
 DataFile
 FROM wmi(query='SELECT * FROM Win32_PrinterDriver',namespace='root/CIMV2')

 SELECT * FROM Win32_PrinterDrivers

 - name: BinaryCheck
 query: |
 SELECT
 lowcase(string=Binary) as Binary,
 array(a1={
 SELECT Name FROM Win32_PrinterDrivers
 WHERE ( DriverPath = Binary OR ConfigFile = Binary OR DataFile = Binary )
 }) as DriverNames,
 hash(path=Binary) as Hash,
 parse_pe(file=Binary) as PE,
 authenticode(filename=Binary) as Authenticode
 FROM chain(
 a={
 SELECT Name, DriverPath as Binary, 'DriverPath' as Type
 FROM Win32_PrinterDrivers
 },
 b={
 SELECT Name as DriverName, ConfigFile as Binary, 'ConfigFile' as Type
 FROM Win32_PrinterDrivers
 },
 c={
 SELECT Name as DriverName, DataFile as Binary, 'DataFile' as Type
 FROM Win32_PrinterDrivers
 })
 GROUP BY lowcase(string=Binary)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.Recall.AllWindowEvents</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.recall.allwindowevents/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.recall.allwindowevents/</guid><description>&lt;p&gt;This artefact will read and correlate several tables to do with Microsoft Recall.&lt;/p&gt;
&lt;p&gt;The main database is held here:
C:\Users\*\AppData\Local\CoreAIPlatform.00\UKP{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ukg.db&lt;/p&gt;
&lt;p&gt;This artefact will join multiple tables together to enrich the Window Capture events of recall.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.Recall.AllWindowEvents
author: |
 Zach Stanford @svch0st
description: |
 This artefact will read and correlate several tables to do with Microsoft Recall.
 
 The main database is held here:
 C:\Users\\*\AppData\Local\CoreAIPlatform.00\UKP\{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ukg.db
 
 This artefact will join multiple tables together to enrich the Window Capture events of recall. 

 
parameters:
 - name: ukgPath
 default: /AppData/Local/CoreAIPlatform.00/UKP/*/ukg.db
 - name: SQLiteQuery
 default: |
 SELECT WindowCapture.TimeStamp, WindowCapture.Name as EventName, WindowCapture.WindowTitle as WindowTitle, App.Name as AppName, App.Path as AppProcess FROM WindowCapture LEFT JOIN (SELECT WindowId as wid, AppId FROM WindowCapture LEFT JOIN WindowCaptureAppRelation ON Id=WindowCaptureId WHERE WindowId is not NULL and AppId is not NULL GROUP BY WindowId, AppId ORDER BY WindowId) WindowApp ON WindowCapture.WindowId=WindowApp.wid LEFT JOIN App ON App.Id=WindowApp.AppId ORDER BY TimeStamp
 - name: userRegex
 default: .
 type: regex

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

sources:
 - query: |
 LET db_files = SELECT * from foreach(
 row={
 SELECT Uid, Name AS User, Directory+ukgPath as globPath,
 expand(path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name =~ userRegex
 },
 query={
 SELECT User, OSPath, Mtime, HomeDirectory
 FROM glob(globs=globPath)
 })

 SELECT timestamp(epoch=TimeStamp) as Timestamp,
 EventName,
 WindowTitle,
 AppName,
 AppProcess
 FROM foreach(row=db_files,
 query={
 SELECT *,OSPath
 FROM sqlite(
 file=OSPath,
 query=SQLiteQuery)
 })


&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.Recall.WindowCaptureEvent</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.recall.windowcaptureevent/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.recall.windowcaptureevent/</guid><description>&lt;p&gt;This artefact will read and correlate several tables to do with Microsoft Recall.&lt;/p&gt;
&lt;p&gt;The main database is held here:
C:\Users\*\AppData\Local\CoreAIPlatform.00\UKP{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ukg.db&lt;/p&gt;
&lt;p&gt;With the images stored:
C:\Users\&lt;em&gt;\AppData\Local\CoreAIPlatform.00\UKP{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ImageStore\&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To view the snapshot images easily from the notebook output, right click and open image in a new tab.&lt;/p&gt;
&lt;p&gt;NOTE: There are many other very useful events in the database, this arefact just looks at the Capture Creation events.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.Recall.WindowCaptureEvent
author: |
 Zach Stanford @svch0st
description: |
 This artefact will read and correlate several tables to do with Microsoft Recall.
 
 The main database is held here:
 C:\Users\\*\AppData\Local\CoreAIPlatform.00\UKP\{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ukg.db
 
 With the images stored:
 C:\Users\\*\AppData\Local\CoreAIPlatform.00\UKP\{DA73A0DB-DDF4-4A81-9506-CCB5DE8B0F14}\ImageStore\\*
 
 To view the snapshot images easily from the notebook output, right click and open image in a new tab. 

 
 NOTE: There are many other very useful events in the database, this arefact just looks at the Capture Creation events. 
 
parameters:
 - name: ukgPath
 default: /AppData/Local/CoreAIPlatform.00/UKP/*/ukg.db
 - name: SQLiteQuery
 default: |
 SELECT WindowCapture.TimeStamp as TimeStamp, WindowCapture.Name as EventName, WindowCapture.WindowTitle as WindowTitle, WindowCapture.WindowId as WindowId, App.Path as Process, WindowCaptureTextIndex_content.c2 as OcrText, ImageToken FROM WindowCaptureTextIndex_content INNER JOIN WindowCapture ON WindowCapture.Id == WindowCaptureTextIndex_content.c0 INNER JOIN WindowCaptureAppRelation ON WindowCaptureAppRelation.WindowCaptureId == WindowCaptureTextIndex_content.c0 INNER JOIN App ON App.Id == WindowCaptureAppRelation.AppId WHERE WindowCapture.Name == "WindowCaptureEvent" AND OcrText IS NOT NULL

 - name: userRegex
 default: .
 type: regex

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

sources:
 - query: |
 LET db_files = SELECT * from foreach(
 row={
 SELECT Uid, Name AS User, Directory+ukgPath as globPath,
 expand(path=Directory) AS HomeDirectory
 FROM Artifact.Windows.Sys.Users()
 WHERE Name =~ userRegex
 },
 query={
 SELECT User, OSPath, Mtime, HomeDirectory
 FROM glob(globs=globPath)
 })

 SELECT timestamp(epoch=TimeStamp) as Timestamp,
 EventName,
 WindowTitle,
 WindowId,
 Process,
 OcrText,
 upload(file=regex_replace(source=OSPath,re="ukg\.db",replace="ImageStore\\"+ImageToken)) AS Capture
 FROM foreach(row=db_files,
 query={
 SELECT *,OSPath
 FROM sqlite(
 file=OSPath,
 query=SQLiteQuery)
 })

column_types:
- name: Capture
 type: preview_upload

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.Services.SliverPsexec</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.services.sliverpsexec/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.services.sliverpsexec/</guid><description>&lt;p&gt;This pack detects various artefacts left behind by default configurations of the C2 framework Sliver PsExec module&lt;/p&gt;
&lt;p&gt;Reference: &lt;a href="https://www.microsoft.com/security/blog/2022/08/24/looking-for-the-sliver-lining-hunting-for-emerging-command-and-control-frameworks/" target="_blank" &gt;https://www.microsoft.com/security/blog/2022/08/24/looking-for-the-sliver-lining-hunting-for-emerging-command-and-control-frameworks/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.Services.SliverPsexec
description: |
 This pack detects various artefacts left behind by default configurations of the C2 framework Sliver PsExec module
 
 Reference: https://www.microsoft.com/security/blog/2022/08/24/looking-for-the-sliver-lining-hunting-for-emerging-command-and-control-frameworks/
author: Zach Stanford - @svch0st
precondition:
 SELECT OS from info() where OS = "windows"

sources:
 - name: Sliver PsExec - Services Registry Key
 query: |
 SELECT * FROM Artifact.Windows.System.Services() 
 WHERE Name =~ "^Sliver" or 
 DisplayName =~ "^Sliver" or 
 Description =~ "Sliver implant" or 
 PathName =~ ":\\\\Windows\\\\Temp\\\\[a-zA-Z0-9]{10}\\.exe"

 - name: Sliver PsExec - Service Installed Event Log
 query: |
 SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(PathRegex="System.evtx",IdRegex="^7045$")
 WHERE EventData.ServiceName =~ "^Sliver$" or 
 EventData.ImagePath =~ ":\\\\Windows\\\\Temp\\\\[a-zA-Z0-9]{10}\\.exe"



&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.WindowsErrorReporting</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.windowserrorreporting/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.windowserrorreporting/</guid><description>&lt;p&gt;Parses several Windows Error Reporting (WER) files that contain information about crashed programs.&lt;/p&gt;
&lt;p&gt;This can include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;evidence historical malware execution that have crashed,&lt;/li&gt;
&lt;li&gt;unstable executables after being injected into, and&lt;/li&gt;
&lt;li&gt;loaded DLLs by other executables (eg rundll32.exe and regsvr32.exe)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After Windows 10, Report.wer files in the ProgramData directory also contain a SHA1 hash (similar to Amcache) which can assist investigators tracking down processes that have since been deleted.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.WindowsErrorReporting
author: Zach Stanford - @svch0st
description: |
 Parses several Windows Error Reporting (WER) files that contain information about crashed programs. 
 
 This can include:
 
 * evidence historical malware execution that have crashed,
 * unstable executables after being injected into, and 
 * loaded DLLs by other executables (eg rundll32.exe and regsvr32.exe)

 After Windows 10, Report.wer files in the ProgramData directory also contain a SHA1 hash (similar to Amcache) which can assist investigators tracking down processes that have since been deleted.

reference: 
 - http://0xdabbad00.com/wp-content/uploads/2014/01/notes_on_wer.pdf
 - https://medium.com/dfir-dudes/amcache-is-not-alone-using-wer-files-to-hunt-evil-86bdfdb216d7

type: CLIENT

sources:
 - name: AppCrashReport
 query: |

 LET files = SELECT OSPath FROM glob(globs=["C:/Users/*/AppData/Local/Microsoft/Windows/WER/*/*/Report.wer",
 "C:/ProgramData/Microsoft/Windows/WER/*/*/Report.wer"])
 
 LET parsed_reports = SELECT * FROM foreach(row=files,
 query={
 SELECT OSPath,
 to_dict(item={
 SELECT _key,_value 
 FROM parse_records_with_regex(file=utf16(string=read_file(filename=OSPath)),
 accessor="data",
 regex="(?P&amp;lt;_key&amp;gt;.*)=(?P&amp;lt;_value&amp;gt;.*)\r\n")
 }
 ) as Report
 FROM scope()
 })
 
 SELECT timestamp(winfiletime=int(int=Report.EventTime)) as timestamp,
 Report.EventType,
 Report.FriendlyEventName,
 Report.AppName,
 Report.AppPath,
 Report.ApplicationIdentity,
 if(condition=Report.TargetAppId=~'^W', -- Appears non-microsoft apps that have a hash only start with "W".
 then=strip(string=split(sep='!',string=Report.TargetAppId)[1],prefix='0000'), -- Prefix of 0000 similar th hash format in Amcache
 else="No hash information") as SHA1,
 Report.OriginalFilename, 
 Report,
 OSPath as ReportFileName
 FROM parsed_reports
 
 - name: WERInternalMetadata
 query: |
 
 LET files = SELECT OSPath FROM glob(globs=["C:/Users/*/AppData/Local/Microsoft/Windows/WER/*/*/*InternalMetadata.xml",
 "C:/ProgramData/Microsoft/Windows/WER/*/*/*InternalMetadata.xml"])
 
 
 LET parsed_reports = SELECT * FROM foreach(row=files,
 query={
 SELECT OSPath, parse_xml(
 accessor='data',
 file=regex_replace(
 source=utf16(string=Data),
 re='&amp;lt;[?].+?&amp;gt;',
 replace='')) AS XML
 FROM read_file(filenames=OSPath)
 })
 
 SELECT XML.WERReportMetadata.ReportInformation.CreationTime as timestamp,
 XML.WERReportMetadata.ProcessInformation.ImageName as ImageName,
 XML.WERReportMetadata.ProcessInformation.Pid as Pid,
 XML.WERReportMetadata.ProcessInformation.ParentProcess.ProcessInformation.ImageName as ParentImageName,
 XML.WERReportMetadata.ProcessInformation.ParentProcess.ProcessInformation.Pid As ParentPid, 
 XML.WERReportMetadata.ProblemSignatures.EventType as EventType,
 XML.WERReportMetadata.ProblemSignatures.Parameter0 as Parameter0,
 XML,
 OSPath
 FROM parsed_reports

 - name: WERProcessTree
 query: |
 
 LET files = SELECT OSPath FROM glob(globs=["C:/Users/*/AppData/Local/Microsoft/Windows/WER/*/*/*.csv",
 "C:/ProgramData/Microsoft/Windows/WER/*/*/*.csv"])
 
 LET parsed_reports = SELECT * FROM foreach(row=files,
 query={
 SELECT *
 FROM parse_csv(filename=utf16(string=read_file(filename=OSPath)),accessor="data")
 })
 
 SELECT *
 FROM parsed_reports

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.System.WMIProviders</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.wmiproviders/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.system.wmiproviders/</guid><description>&lt;p&gt;List the WMI providers in the system.&lt;/p&gt;
&lt;p&gt;It is possible to laterally move by installing a fake provider in the system, and then calling
it remotely. This artifact enumerates all WMI providers and recovers the binary that runs when
loaded.&lt;/p&gt;
&lt;p&gt;Test using &lt;a href="https://github.com/Cybereason/Invoke-WMILM" target="_blank" &gt;https://github.com/Cybereason/Invoke-WMILM&lt;/a&gt;
 (Will run as SYSTEM)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Invoke-WMILM -Target localhost -Type Provider -Name notepad -Username test -Password test -Command notepad.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.System.WMIProviders
description: |
 List the WMI providers in the system.
 
 It is possible to laterally move by installing a fake provider in the system, and then calling
 it remotely. This artifact enumerates all WMI providers and recovers the binary that runs when 
 loaded.
 
 Test using https://github.com/Cybereason/Invoke-WMILM (Will run as SYSTEM)
 ```
 Invoke-WMILM -Target localhost -Type Provider -Name notepad -Username test -Password test -Command notepad.exe
 ```
 
reference:
 - https://www.cybereason.com/blog/wmi-lateral-movement-win32

type: CLIENT

parameters:
 - name: BinaryIncludeRegex
 default: .
 type: regex 
 - name: BinaryExcludeRegex
 type: regex
 - name: ServerTypeRegex
 type: regex 
 description: Only show these WMI provider types (e.g. LocalServer)

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

 query: |
 LET Hits = SELECT CLSID, Name, {
 SELECT Data.value AS Binary, basename(path=dirname(path=FullPath)) AS ServerType
 FROM glob(globs="/*Server*/@", root='''HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\''' + CLSID, accessor="reg")
 WHERE CLSID
 limit 1
 } AS Details
 FROM wmi(query="Select * from __Win32Provider ")
 
 SELECT CLSID, Name, Details.ServerType AS ServerType, Details.Binary AS BinaryPath
 FROM Hits
 WHERE ServerType =~ ServerTypeRegex
 AND BinaryPath =~ BinaryIncludeRegex
 AND if(condition=BinaryExcludeRegex,
 then=NOT BinaryPath =~ BinaryExcludeRegex,
 else=TRUE)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Timeline.Prefetch.Improved</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.timeline.prefetch.improved/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.timeline.prefetch.improved/</guid><description>&lt;p&gt;NOTE: This is a fixed version of Windows.Timeline.Prefetch which is
available in the release binary after 0.7.0-3.&lt;/p&gt;
&lt;p&gt;Windows keeps a cache of prefetch files. When an executable is run,
the system records properties about the executable to make it faster
to run next time. By parsing this information we are able to
determine when binaries are run in the past. On Windows10 we can see
the last 8 execution times and creation time (9 potential executions).&lt;/p&gt;
&lt;p&gt;This artifact is a timelined output version of the standard Prefetch
artifact. There are several parameter&amp;rsquo;s availible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dateAfter enables search for prefetch evidence after this date.&lt;/li&gt;
&lt;li&gt;dateBefore enables search for prefetch evidence before this date.&lt;/li&gt;
&lt;li&gt;binaryRegex enables to filter on binary name, e.g evil.exe.&lt;/li&gt;
&lt;li&gt;hashRegex enables to filter on prefetch hash.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Timeline.Prefetch.Improved
author: Matt Green - @mgreen27
description: |
 NOTE: This is a fixed version of Windows.Timeline.Prefetch which is
 available in the release binary after 0.7.0-3.

 Windows keeps a cache of prefetch files. When an executable is run,
 the system records properties about the executable to make it faster
 to run next time. By parsing this information we are able to
 determine when binaries are run in the past. On Windows10 we can see
 the last 8 execution times and creation time (9 potential executions).

 This artifact is a timelined output version of the standard Prefetch
 artifact. There are several parameter's availible.
 - dateAfter enables search for prefetch evidence after this date.
 - dateBefore enables search for prefetch evidence before this date.
 - binaryRegex enables to filter on binary name, e.g evil.exe.
 - hashRegex enables to filter on prefetch hash.

reference:
 - https://www.forensicswiki.org/wiki/Prefetch

parameters:
 - name: prefetchGlobs
 default: C:\Windows\Prefetch\*.pf
 - name: dateAfter
 description: "search for events after this date. YYYY-MM-DDTmm:hh:ssZ"
 type: timestamp
 - name: dateBefore
 description: "search for events before this date. YYYY-MM-DDTmm:hh:ssZ"
 type: timestamp
 - name: binaryRegex
 description: "Regex of executable name."
 type: regex
 - name: hashRegex
 description: "Regex of prefetch hash."
 type: regex

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

sources:
 - query: |

 LET hostname &amp;lt;= SELECT Fqdn FROM info()

 SELECT LastRunTimes as event_time,
 hostname.Fqdn[0] as hostname,
 "Prefetch" as parser,
 message,
 OSPath as source,
 Executable as file_name,
 CreationTime as prefetch_ctime,
 ModificationTime as prefetch_mtime,
 FileSize as prefetch_size,
 Hash as prefetch_hash,
 Version as prefetch_version,
 PrefetchFileName as prefetch_file,
 RunCount as prefetch_count
 FROM foreach(
 row={
 SELECT *
 FROM Artifact.Windows.Forensics.Prefetch(
 prefetchGlobs=prefetchGlobs,
 dateAfter=dateAfter,
 dateBefore=dateBefore,
 binaryRegex=binaryRegex,
 hashRegex=hashRegex)
 },
 query={
 SELECT *
 FROM chain(a1={
 SELECT *
 FROM flatten(query={
 SELECT Executable,
 FileSize,
 Hash,
 Version,
 LastRunTimes,
 "Evidence of Execution: " + Executable + format(
 format=" Prefetch run count %v", args=RunCount) as message,
 RunCount,
 OSPath,
 PrefetchFileName,
 CreationTime,
 ModificationTime,
 Binary
 FROM scope()
 })
 }, b1={
 -- One more row for creation time
 SELECT Executable,
 FileSize,
 Hash,
 Version,
 CreationTime AS LastRunTimes,
 "Evidence of Execution (Btime): " + Executable + format(
 format=" Prefetch run count %v", args=RunCount) as message,
 RunCount,
 OSPath,
 PrefetchFileName,
 CreationTime,
 ModificationTime,
 Binary
 FROM scope()
 })
 -- This group by applies on only a single prefetch file to
 -- remove duplication with CreationTime
 GROUP BY LastRunTimes
 })
 ORDER BY event_time

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Triage.HighValueMemory</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.triage.highvaluememory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.triage.highvaluememory/</guid><description>&lt;p&gt;Dump process memory and upload to the server&lt;/p&gt;
&lt;p&gt;Common Archive Utilities: Winrar, Winzip, 7-zip, Winscp, FileZilla&lt;/p&gt;
&lt;p&gt;Common Exfil Utilities: robocopy, rclone, mega*&lt;/p&gt;
&lt;p&gt;Consoles: cmd, powershell&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Triage.HighValueMemory

description: |
 Dump process memory and upload to the server

 Common Archive Utilities: Winrar, Winzip, 7-zip, Winscp, FileZilla

 Common Exfil Utilities: robocopy, rclone, mega*

 Consoles: cmd, powershell

author: "@kevinfosec - liteman"

parameters:
 - name: processRegexCsv
 default: |
 processName
 mega
 winrar
 winzip
 7z
 winscp
 filezilla
 robocopy
 rclone
 notepad
 cmd
 powershell
 type: regex

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

 query: |

 LET processRegexList &amp;lt;= SELECT processName
 FROM parse_csv(filename=processRegexCsv, accessor='data')

 LET processes(processRegex) = SELECT Name as ProcessName,
 CommandLine,
 Pid
 FROM pslist()
 WHERE Name =~ processRegex

 LET processList = SELECT *
 FROM foreach(
 row=processRegexList,
 query={ SELECT * from processes(processRegex=processName) }
 )

 SELECT *
 FROM foreach(
 row=processList,
 query={
 SELECT ProcessName,
 CommandLine,
 Pid,
 FullPath,
 upload(file=FullPath,
 name=format(format="%v_%v",args=[ProcessName,Pid])) as CrashDump
 FROM proc_dump(pid=Pid)
 }
 )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Triage.ScreenConnect</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/screenconnect/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/screenconnect/</guid><description>&lt;p&gt;This artifact extracts useful data for triage of ConnectWise ScreenConnect
CVE-2024-1709 and CVE-2024-1708 impacting versions 23.9.7 and prior.&lt;/p&gt;
&lt;p&gt;This artifact will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Check for Webshells in &lt;code&gt;/App_Extensions/**/*.{aspx,ashx}&lt;/code&gt; path.
Some observed legitimate webapp strings have been excluded.
NOTE: Use WebshellsUSN to find potential exploits that cleanup shells.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Parse &lt;code&gt;C:\Program Files\ScreenConnect\App_data\User.Xml&lt;/code&gt; file.
Usually this file is set during first use and reset during exploit.
Check for timestamp discrepancies and obviously evil usernames/email
(@poc.com).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Parse &lt;code&gt;security.db&lt;/code&gt;.
Add time filter. Results are stacked, check for unusual access patterns
and malicious IPs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;List and upload (optionally) all ScreenConnect files.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Collect additional artifacts as desired for support.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;

name: Windows.Triage.ScreenConnect
author: Matt Green - @mgreen27 - Rapid7 Labs
description: |
 This artifact extracts useful data for triage of ConnectWise ScreenConnect
 CVE-2024-1709 and CVE-2024-1708 impacting versions 23.9.7 and prior.

 This artifact will:

 1. Check for Webshells in ```/App_Extensions/**/*.{aspx,ashx}``` path.
 Some observed legitimate webapp strings have been excluded.
 NOTE: Use WebshellsUSN to find potential exploits that cleanup shells.

 2. Parse ```C:\Program Files\ScreenConnect\App_data\User.Xml``` file.
 Usually this file is set during first use and reset during exploit.
 Check for timestamp discrepancies and obviously evil usernames/email
 (@poc.com).

 3. Parse ```security.db```.
 Add time filter. Results are stacked, check for unusual access patterns
 and malicious IPs.

 4. List and upload (optionally) all ScreenConnect files.

 Collect additional artifacts as desired for support.

reference:
 - https://www.rapid7.com/blog/post/2024/02/20/etr-high-risk-vulnerabilities-in-connectwise-screenconnect/

type: CLIENT

parameters:
 - name: TargetGlob
 default: "C:/Program Files*/**/ScreenConnect/**"
 description: Glob for all files under ScreenConnect program files
 - name: ExcludedWebshellStrings
 description: Excluded webshell strings.
 default: ScreenConnect
 - name: DateAfter
 description: Search for security events after this date
 type: timestamp
 default: "2024-02-20"
 - name: DateBefore
 description: Search for security events before this date
 type: timestamp
 - name: UploadFiles
 description: If selected Upload all ScreenConnect files for review
 type: bool


precondition: SELECT OS From info() where OS = 'windows'
sources:
 - name: Webshells
 query: |
 LET shells = SELECT OSPath, Mtime,Atime,Ctime,Btime
 FROM glob(globs=TargetGlob + "/App_Extensions/**/*.{aspx,ashx}")
 WHERE NOT IsDir

 SELECT * FROM foreach(row=shells, query={
 SELECT
 OSPath,
 dict(
 Mtime=Mtime,
 Atime=Atime,
 Ctime=Ctime,
 Btime=Btime ) as Timestamps,
 read_file(filename=OSPath) as Contents
 FROM scope()
 WHERE NOT if(condition=ExcludedWebshellStrings,
 then= Contents=~ExcludedWebshellStrings,
 else= False )
 })

 - name: WebshellsUsn
 query: |
 SELECT Timestamp,OSPath,Reason,MFTId,Sequence,ParentMFTId,ParentSequence,Usn
 FROM Artifact.Windows.Forensics.Usn(
 FileNameRegex='\.(aspx|ashx)$',
 PathRegex='ScreenConnect.+App_Extensions',
 DateAfter=DateAfter,
 DateBefore=DateBefore )

 - name: UserXml
 query: |
 SELECT
 OSPath,
 dict(
 Mtime=Mtime,
 Atime=Atime,
 Ctime=Ctime,
 Btime=Btime ) as FileTimestamps,
 parse_xml(file=OSPath).Users.User as UserXml
 FROM glob(globs=TargetGlob + '/user.xml')


 - name: SecurityEvents
 query: |
 LET MaxDate &amp;lt;= if(condition= DateBefore, then=DateBefore, else= '2030-01-01')

 LET db = SELECT OSPath, Mtime,Atime,Ctime,Btime
 FROM glob(globs=TargetGlob + '/security.db')

 LET sqlquery = "SELECT * FROM SecurityEvent"

 LET results = SELECT * FROM foreach(row=db,query= {
 SELECT * FROM sqlite(file=OSPath,query=sqlquery)
 WHERE Time &amp;gt; DateAfter AND Time &amp;lt; MaxDate
 })

 SELECT
 EventType,
 OperationResult,
 ip(netaddr4_be=int(
 int=format(format='0x%x',args=NetworkAddress))) AS NetworkAddress,
 UserAgent,
 UserSource,
 UrlReferrer,
 UserName,
 min(item=Time) AS Earliest,
 max(item=Time) AS Latest,
 count() AS Total
 FROM results
 GROUP BY UserAgent, UserSoure, UrlReferrer, UserName

 - name: Files
 query: |
 LET TargetGlobTable = '''
 Glob
 C:/Windows/Temp/ScreenConnect*/**
 C:/Program Files/ScreenConnect*/**
 C:/Program Files (x86)/ScreenConnect*/**
 C:/ProgramData/ScreenConnect*/**
 C:/Users/*/Documents/ConnectWiseControl/**
 '''

 SELECT *
 FROM Artifact.Windows.Search.FileFinder(
 Upload_File=UploadFiles,
 SearchFilesGlobTable=TargetGlobTable )

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Triage.Sysmon</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/sysmontriage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/sysmontriage/</guid><description>&lt;p&gt;This artifact allows collecting Sysmon Events for Triage around a timestamp.&lt;/p&gt;
&lt;p&gt;By default collection will be 600 seconds from the current time and allows
fast triage of a machine with recent telemetry.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Triage.Sysmon
author: Matt Green - @mgreen27
description: |
 This artifact allows collecting Sysmon Events for Triage around a timestamp.
 
 By default collection will be 600 seconds from the current time and allows 
 fast triage of a machine with recent telemetry.
 
type: CLIENT

parameters:
 - name: TargetTime
 description: the timestamp we want to box time around. Default is current time.
 type: timestamp
 - name: TargetTimeBox
 description: the time box in seconds we want around TargetTime.
 default: 600
 type: int
 - name: IdRegex
 description: Regex of Sysmon EventIDs to include. Default is all.
 default: .
 - name: IocRegex
 description: Regex of strings to search for in Sysmon events. Default is any.
 default: .
 - name: FilterRegex
 description: Regex of strings to filter out of results. Default is none.
 
sources:
 - precondition:
 SELECT OS From info() where OS = 'windows'

 query: |
 -- firstly set boxed timebounds
 LET DateAfterTime &amp;lt;= if(condition=TargetTime,
 then=timestamp(epoch=TargetTime.Unix - TargetTimeBox), else=timestamp(epoch=now() - TargetTimeBox))
 LET DateBeforeTime &amp;lt;= if(condition=TargetTime,
 then=timestamp(epoch=TargetTime.Unix + TargetTimeBox), else=timestamp(epoch=now() + TargetTimeBox))
 
 -- run query and output rows
 SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
 EvtxGlob='''%SystemRoot%\System32\Winevt\Logs\*Sysmon*.evtx''',
 ChannelRegex='Sysmon',
 DateAfter= DateAfterTime,
 DateBefore= DateBeforeTime,
 IdRegex=IdRegex,
 IocRegex=IocRegex,
 WhitelistRegex=FilterRegex )

 notebook:
 - type: vql_suggestion
 name: 1. Process event timeline
 template: |
 /*
 ## 1: Process creation
 Comment in fields as needed.
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --EventData.RuleName as RuleName
 --EventData.UtcTime as UtcTime
 --EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.OriginalFileName as OriginalFileName
 --,dict(FileVersion = EventData.FileVersion, Description = EventData.Description, Product = EventData.Product,Company = EventData.Company,OriginalFileName = EventData.OriginalFileName) as VersionInformation
 ,EventData.CommandLine as CommandLine
 --,EventData.CurrentDirectory as CurrentDirectory
 ,EventData.User as User
 --,EventData.LogonGuid as LogonGuid
 --,EventData.LogonId as LogonId
 --,EventData.TerminalSessionId as TerminalSessionId
 --,EventData.IntegrityLevel as IntegrityLevel
 --,parse_string_with_regex(string=EventData.Hashes, regex=["MD5=(?P&amp;lt;MD5&amp;gt;[^,]+)","SHA1=(?P&amp;lt;SHA1&amp;gt;[^,]+)","SHA256=(?P&amp;lt;SHA256&amp;gt;[^,]+)","IMPHASH=(?P&amp;lt;IMPHASH&amp;gt;[^,]+)"] ) as Hash
 --,EventData.ParentProcessGuid as ParentProcessGuid
 ,EventData.ParentProcessId as ParentProcessId
 ,EventData.ParentImage as ParentImage
 ,EventData.ParentCommandLine as ParentCommandLine
 --,EventData.ParentUser as ParentUser
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 1
 
 - type: vql_suggestion
 name: 2 Change file time
 template: |
 /*
 ## 2: A process changed a file creation time
 The change file creation time event is registered when a file creation time is 
 explicitly modified by a process. This event helps tracking the real creation 
 time of a file. Attackers may change the file creation time of a backdoor to 
 make it look like it was installed with the operating system. Note that many 
 processes legitimately change the creation time of a file; it does not 
 necessarily indicate malicious activity.
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --EventData.RuleName as RuleName
 --EventData.UtcTime as UtcTime
 --EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.TargetFilename as TargetFilename
 ,EventData.CreationUtcTime as CreationUtcTime
 ,EventData.PreviousCreationUtcTime as PreviousCreationUtcTime
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 2

 - type: vql_suggestion
 name: 3. Network event timeline
 template: | 
 /*
 ## 3. Network connection
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.Protocol as Protocol
 ,EventData.Initiated as Initiated
 ,EventData.SourceIsIpv6 as SourceIsIpv6
 ,EventData.SourceIp as SourceIp
 ,EventData.SourceHostname as SourceHostname
 ,EventData.SourcePort as SourcePort
 ,EventData.SourcePortName as SourcePortName
 ,EventData.DestinationIsIpv6 as DestinationIsIpv6
 ,EventData.DestinationIp as DestinationIp
 ,EventData.DestinationHostname as DestinationHostname
 ,EventData.DestinationPort as DestinationPort
 ,EventData.DestinationPortName as DestinationPortName
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 3
 
 
 - type: vql_suggestion
 name: 8. CreateRemoteThread
 template: | 
 /*
 ## 8: CreateRemoteThread
 The CreateRemoteThread event detects when a process creates a thread in another 
 process. This technique is used by malware to inject code and hide in other 
 processes. The event indicates the source and target process. It gives 
 information on the code that will be run in the new thread: StartAddress, 
 StartModule and StartFunction. Note that StartModule and StartFunction fields 
 are inferred, they might be empty if the starting address is outside loaded 
 modules or known exported functions.
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.SourceProcessGuid as SourceProcessGuid
 ,EventData.SourceProcessId as SourceProcessId
 ,EventData.SourceImage as SourceImage
 ,EventData.SourceUser as SourceUser
 --,EventData.TargetProcessGuid as TargetProcessGuid
 ,EventData.TargetImage as TargetImage
 ,EventData.TargetUser as TargetUser
 ,EventData.NewThreadId as NewThreadId
 ,EventData.StartAddress as StartAddress
 ,EventData.StartModule as StartModule
 ,EventData.StartFunction as StartFunction
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 8
 
 - type: vql_suggestion
 name: 10. ProcessAccess
 template: | 
 /*
 ## 10: ProcessAccess
 The process accessed event reports when a process opens another process, 
 an operation that’s often followed by information queries or reading 
 and writing the address space of the target process. This enables 
 detection of hacking tools that read the memory contents of processes 
 like Local Security Authority (Lsass.exe) in order to steal credentials 
 for use in Pass-the-Hash attacks. Enabling it can generate significant 
 amounts of logging if there are diagnostic utilities active that 
 repeatedly open processes to query their state, so it generally 
 should only be done so with filters that remove expected accesses.
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.SourceProcessGuid as SourceProcessGuid
 ,EventData.SourceProcessId as SourceProcessId
 ,EventData.SourceThreadId as SourceThreadId
 ,EventData.SourceImage as SourceImage
 ,EventData.SourceUser as SourceUser
 --,EventData.TargetProcessGuid as TargetProcessGuid
 ,EventData.TargetProcessId as TargetProcessId
 ,EventData.TargetImage as TargetImage
 ,EventData.TargetUser as TargetUser
 ,EventData.GrantedAccess as GrantedAccess
 ,EventData.CallTrace as CallTrace
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 10

 - type: vql_suggestion
 name: 11. FileCreate
 template: | 
 /*
 ## 11: FileCreate
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.TargetFilename as TargetFilename
 ,EventData.CreationUtcTime as CreationUtcTime
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 11

 - type: vql_suggestion
 name: 12 13 14. Registry events
 template: | 
 /*
 ## 12, 13, 14: Registry
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.EventType as EventType
 ,EventData.TargetObject as TargetObject
 ,EventData.Details as Details
 ,EventData.NewName as NewName
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID in ( 12, 13, 14 )

 - type: vql_suggestion
 name: 15. FileCreateStreamHash
 template: | 
 /*
 ## 15: FileCreateStreamHash
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.TargetFileName as TargetFileName
 ,EventData.CreationUtcTime as CreationUtcTime
 --,parse_string_with_regex(string=EventData.Hash, regex=["MD5=(?P&amp;lt;MD5&amp;gt;[^,]+)","SHA1=(?P&amp;lt;SHA1&amp;gt;[^,]+)","SHA256=(?P&amp;lt;SHA256&amp;gt;[^,]+)"] ) as Hash
 ,EventData.Hash as Hash
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 15

 - type: vql_suggestion
 name: 17 18. Named Pipes
 template: | 
 /*
 ## 17, 18: Named Pipes
 17: Pipe created
 18: Pipe connected
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.EventType as EventType
 ,EventData.PipeName as PipeName
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID in ( 17,18 )
 
 
 /*
 
 - type: vql_suggestion
 name: 19 20 21. WMI Eventing
 template: | 
 ## 19,20,21: WMI Eventing
 19: WmiEventFilter activity detected. 
 20: WmiEventConsumer activity detected. 
 21: WmiEventConsumerToFilter activity detected. 
 
 Note: some fields for each event will be null. 
 Comment in and out relevant fields.
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.EventType as EventType
 ,EventData.Operation as Operation
 ,EventData.EventNamespace as EventNamespace
 ,EventData.Name as Name
 ,EventData.Query as Query
 ,EventData.Type as Type
 ,EventData.Destination as Destination
 ,EventData.Consumer as Consumer
 ,EventData.Filter as Filter
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID in ( 19,20,21 )

 - type: vql_suggestion
 name: 22. DNS event timeline
 template: | 
 /*
 ## 22: DNSEvent
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.QueryName as QueryName
 ,EventData.QueryStatus as QueryStatus
 ,EventData.QueryResults as QueryResults
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 22

 - type: vql_suggestion
 name: 23. FileDelete
 template: | 
 /*
 ## 23: FileDelete
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.TargetFilename as TargetFilename
 --,parse_string_with_regex(string=EventData.Hashes, regex=["MD5=(?P&amp;lt;MD5&amp;gt;[^,]+)","SHA1=(?P&amp;lt;SHA1&amp;gt;[^,]+)","SHA256=(?P&amp;lt;SHA256&amp;gt;[^,]+)"] ) as Hashes
 ,EventData.Hashes as Hashes
 ,EventData.Archived as Archived
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 23

 - type: vql_suggestion
 name: 24. ClipboardChange
 template: | 
 /*
 ## 24: ClipboardChange
 */
 SELECT EventTime, Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 --,EventData.ProcessGuid as ProcessGuid
 ,EventData.ProcessId as ProcessId
 ,EventData.Image as Image
 ,EventData.User as User
 ,EventData.Session as Session
 ,EventData.ClientInfo as ClientInfo
 --,parse_string_with_regex(string=EventData.Hashes, regex=["MD5=(?P&amp;lt;MD5&amp;gt;[^,]+)","SHA1=(?P&amp;lt;SHA1&amp;gt;[^,]+)","SHA256=(?P&amp;lt;SHA256&amp;gt;[^,]+)"] ) as Hashes
 ,EventData.Hashes as Hashes
 ,EventData.Archived as Archived
 --,EventData
 --,Message
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")
 WHERE EventID = 24

 - type: vql_suggestion
 name: Timesketch format
 template: | 
 SELECT EventTime as datetime
 ,Computer,EventID
 --,Channel,Provider
 --,EventData.RuleName as RuleName
 --,EventData.UtcTime as UtcTime
 ,get(item=dict(
 `1` = 'Process Create',
 `2` = 'File creation time changed',
 `3` = 'Network connection detected',
 `4` = 'Sysmon service state changed',
 `5` = 'Process terminated',
 `6` = 'Driver loaded',
 `7` = 'Image loaded',
 `8` = 'CreateRemoteThread detected',
 `9` = 'RawAccessRead detected',
 `10` = 'Process accessed',
 `11` = 'File created',
 `12` = 'Registry object added or deleted',
 `13` = 'Registry value set',
 `14` = 'Registry object renamed',
 `15` = 'File stream created',
 `16` = 'Sysmon config state changed',
 `17` = 'Pipe Created"',
 `18` = 'Pipe Connected',
 `19` = 'WmiEventFilter activity detected',
 `20` = 'WmiEventConsumer activity detected',
 `21` = 'WmiEventConsumerToFilter activity detected',
 `22` = 'Dns query',
 `23` = 'File Delete archived',
 `24` = 'Clipboard changed',
 `25` = 'Process Tampering',
 `26` = 'File Delete logged',
 `27` = 'File Block Executable',
 `28` = 'File Block Shredding',
 `255` = 'Error'),
 member=str(str=EventID)) as timestamp_desc
 ,Message as message
 --,EventData
 FROM source(artifact="Exchange.Windows.Triage.Sysmon")

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Utils.DefenderExclusion</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/defenderexclusion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/defenderexclusion/</guid><description>&lt;p&gt;&lt;strong&gt;Adds a Microsoft Defender real-time scanning process exclusion for
Velociraptor.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Generally you should not need to use this unless Defender is interfering
with your collections.
This may happen if the collection uses tools or associated files that
trigger Microsoft Defender detections.&lt;/p&gt;
&lt;p&gt;Some initial info is also gathered to aid with troubleshooting.&lt;/p&gt;
&lt;p&gt;The exclusion is checked every minute by default and reapplied if necessary.&lt;/p&gt;
&lt;p&gt;As a side-effect the exclusion also makes some collection operations faster,
particularly those that are filesystem-intensive and that use the OS &amp;lsquo;file&amp;rsquo;
accessor.&lt;/p&gt;
&lt;h4 id="notes"&gt;Notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Exclusions &lt;em&gt;do&lt;/em&gt; apply to some Microsoft Defender for Endpoint capabilities,
such as attack surface reduction rules.&lt;/li&gt;
&lt;li&gt;Exclusions &lt;em&gt;do&lt;/em&gt; apply to potentially unwanted apps (PUA) detections as well.&lt;/li&gt;
&lt;li&gt;Exclusions &lt;em&gt;do&lt;/em&gt; apply to some ASR rule exclusions. See &lt;a href="https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-reference#microsoft-defender-antivirus-exclusions-and-asr-rules" target="_blank" &gt;Attack surface
reduction rules reference - Microsoft Defender Antivirus exclusions and ASR
rules&lt;/a&gt;
.&lt;/li&gt;
&lt;li&gt;Excluded files can still trigger Endpoint Detection and Response (EDR)
alerts and other detections. To exclude files broadly, add them to the
Microsoft Defender for Endpoint custom indicators.&lt;/li&gt;
&lt;li&gt;See References below to learn more about Defender exclusions in general.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A more compact version of this artifact is listed below which can be included
in the client configuration, as shown, and run with the
&lt;code&gt;Client.additional_event_artifacts&lt;/code&gt; setting. This will run the artifact
as an event artifact as long as the client is running, starting even before
enrollment. This may be useful if there are specific clients where Defender
is causing problems.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;autoexec:
 artifact_definitions:
 - name: Windows.Utils.DefenderExclusionCompact
 precondition: SELECT OS From info() where OS = &amp;quot;windows&amp;quot;
 parameters:
 - name: CmdApply
 default: &amp;quot;powershell.exe -ExecutionPolicy Unrestricted -encodedCommand&amp;quot;
 sources:
 - query: |
 LET schedule = SELECT * FROM clock(period=60)
 LET HostInfo &amp;lt;= SELECT * FROM info()
 SELECT {
 SELECT *
 FROM execve(
 argv=[commandline_split(command=CmdApply) + base64encode(
 string=utf16_encode(
 string=format(
 format='Add-MpPreference -ExclusionProcess &amp;quot;%v&amp;quot;',
 args=HostInfo[0].Exe)))])
 WHERE log(
 message=&amp;quot;Applied process exclusion: %v&amp;quot;,
 args=HostInfo[0].Exe,
 level=&amp;quot;INFO&amp;quot;)
 }
 FROM schedule
 Client:
 additional_event_artifacts:
 - Windows.Utils.DefenderExclusionCompact
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Utils.DefenderExclusion

author: |
 @predictiple - 2024-08-18

description: |
 **Adds a Microsoft Defender real-time scanning process exclusion for
 Velociraptor.**

 Generally you should not need to use this unless Defender is interfering
 with your collections.
 This may happen if the collection uses tools or associated files that
 trigger Microsoft Defender detections.

 Some initial info is also gathered to aid with troubleshooting.

 The exclusion is checked every minute by default and reapplied if necessary.

 As a side-effect the exclusion also makes some collection operations faster,
 particularly those that are filesystem-intensive and that use the OS 'file'
 accessor.

 #### Notes

 - Exclusions *do* apply to some Microsoft Defender for Endpoint capabilities,
 such as attack surface reduction rules.
 - Exclusions *do* apply to potentially unwanted apps (PUA) detections as well.
 - Exclusions *do* apply to some ASR rule exclusions. See [Attack surface
 reduction rules reference - Microsoft Defender Antivirus exclusions and ASR
 rules](https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-reference#microsoft-defender-antivirus-exclusions-and-asr-rules).
 - Excluded files can still trigger Endpoint Detection and Response (EDR)
 alerts and other detections. To exclude files broadly, add them to the
 Microsoft Defender for Endpoint custom indicators.
 - See References below to learn more about Defender exclusions in general.

 A more compact version of this artifact is listed below which can be included
 in the client configuration, as shown, and run with the
 `Client.additional_event_artifacts` setting. This will run the artifact
 as an event artifact as long as the client is running, starting even before
 enrollment. This may be useful if there are specific clients where Defender
 is causing problems.

 ```yaml
 autoexec:
 artifact_definitions:
 - name: Windows.Utils.DefenderExclusionCompact
 precondition: SELECT OS From info() where OS = "windows"
 parameters:
 - name: CmdApply
 default: "powershell.exe -ExecutionPolicy Unrestricted -encodedCommand"
 sources:
 - query: |
 LET schedule = SELECT * FROM clock(period=60)
 LET HostInfo &amp;lt;= SELECT * FROM info()
 SELECT {
 SELECT *
 FROM execve(
 argv=[commandline_split(command=CmdApply) + base64encode(
 string=utf16_encode(
 string=format(
 format='Add-MpPreference -ExclusionProcess "%v"',
 args=HostInfo[0].Exe)))])
 WHERE log(
 message="Applied process exclusion: %v",
 args=HostInfo[0].Exe,
 level="INFO")
 }
 FROM schedule
 Client:
 additional_event_artifacts:
 - Windows.Utils.DefenderExclusionCompact
 ```

reference:
 - https://learn.microsoft.com/en-us/defender-endpoint/defender-endpoint-antivirus-exclusions
 - https://learn.microsoft.com/en-us/previous-versions/windows/desktop/defender/add-msft-mppreference
 - https://learn.microsoft.com/en-us/defender-endpoint/configure-local-policy-overrides-microsoft-defender-antivirus
 - https://cloudbrothers.info/en/guide-to-defender-exclusions/

type: CLIENT_EVENT

required_permissions:
 - EXECVE

precondition: SELECT OS From info() where OS = "windows"

parameters:

 - name: CmdApply
 default: "powershell.exe -ExecutionPolicy Unrestricted -encodedCommand"

sources:

 - name: InitialExclusions
 query: |
 LET MpPreference &amp;lt;= SELECT *
 FROM wmi(query='SELECT * FROM MSFT_MpPreference',
 namespace='root/microsoft/windows/defender')

 SELECT * FROM column_filter(query=MpPreference, include="Exclusion")

 - name: ApplyExclusion
 query: |
 -- Check on a schedule that the exclusion is still being applied
 LET schedule = SELECT * FROM clock(period=60)

 -- Get the Velociraptor exe location
 LET HostInfo &amp;lt;= SELECT * FROM info()

 -- Checking is not really necessary because adding exclusions is an
 -- idempotent operation but it's useful to see it in the log
 LET ExclusionCheck(VelociExe) =
 SELECT ExclusionProcess
 FROM wmi(query='SELECT * FROM MSFT_MpPreference', namespace='root/microsoft/windows/defender')
 WHERE VelociExe IN ExclusionProcess
 AND log(message="WMI check: %v is excluded", args=ExclusionProcess, dedup=-1, level="INFO")

 LET ExclusionApply(VelociExe) =
 SELECT *
 FROM execve(argv=[commandline_split(command=CmdApply) + base64encode(string=utf16_encode(
 string=format(format='Add-MpPreference -ExclusionProcess "%v"',args=VelociExe)))])
 WHERE log(message="Applied process exclusion: %v", args=VelociExe, dedup=-1, level="INFO")

 SELECT if(condition= NOT ExclusionCheck(VelociExe=HostInfo[0].Exe),
 then={ SELECT ExclusionApply(VelociExe=HostInfo[0].Exe) FROM scope() })
 FROM schedule



&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Veeam.RestorePoints.BackupFiles</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.veeam.restorepoints.backupfiles/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.veeam.restorepoints.backupfiles/</guid><description>&lt;p&gt;Parses the metadata found in Veeam full backup files (&lt;code&gt;.vbk&lt;/code&gt;), Veeam incremental backup files (&lt;code&gt;.vib&lt;/code&gt;) and Veeam reverse incremental backup files (&lt;code&gt;.vrb&lt;/code&gt;) to extract relevant fields for each Restore Point.&lt;/p&gt;
&lt;p&gt;These files are generated by Veeam Backup &amp;amp; Replication during backup jobs. This artifact accepts full backup, incremental backup, and reverse incremental backup files from &lt;strong&gt;unencrypted&lt;/strong&gt; backups of virtual and physical infrastructures.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Veeam.RestorePoints.BackupFiles

description: |
 Parses the metadata found in Veeam full backup files (`.vbk`), Veeam incremental backup files (`.vib`) and Veeam reverse incremental backup files (`.vrb`) to extract relevant fields for each Restore Point.
 
 These files are generated by Veeam Backup &amp;amp; Replication during backup jobs. This artifact accepts full backup, incremental backup, and reverse incremental backup files from **unencrypted** backups of virtual and physical infrastructures.

author: Synacktiv, Maxence Fossat - @cybiosity

type: CLIENT

precondition: SELECT OS FROM info() WHERE OS = 'windows'

parameters:
 - name: BackupRepositories
 description: List of Backup Repositories where ".vbk", ".vib" and ".vrb" files should be looked for.
 type: csv
 default: |
 BackupRepoPath
 C:/BackupRepo1
 D:/BackupRepo2

required_permissions:
 - FILESYSTEM_READ

sources:
 - query: |
 // ============================
 // === Formatting functions ===
 // ============================
 
 // Function to format XML properties
 LET format_properties(Properties) = to_dict(item={ 
 SELECT AttrName AS _key,
 Value AS _value
 FROM Properties
 })

 // Function to format disk_info capacity for HvAuxData
 LET hv_disk_capacity(Disks) = to_dict(item= {
 SELECT disk_info.Attrdisk_id AS _key,
 disk_info.Attrcapacity AS _value
 FROM Disks
 })
 
 // Function to format Disk capacity for DesktopOibAuxData
 LET desktop_disk_capacity(Disks) = to_dict(item= {
 SELECT DevSetupInfo.AttrDevPath AS _key,
 Capacity AS _value
 FROM Disks
 })
 
 // Function to format Disk capacity for COibAuxDataVmware
 LET vmware_disk_capacity(Disks) = to_dict(item= {
 SELECT `Uuid` AS _key,
 Capacity AS _value
 FROM Disks
 })
 
 // Function to format OibFiles
 LET oib_files_size(Files) = to_dict(item= {
 SELECT AttrFileName AS _key,
 AttrSize AS _value
 FROM Files
 })
 
 // Restore Point type
 LET restore_point_type = dict(
 `0`='Full',
 `1`='Increment'
 )
 
 // Backup encryption state
 LET back_enc_state = dict(
 `0`='Unencrypted',
 `2`='Encrypted'
 )
 
 // ========================
 // === Initial parsing ====
 // ========================
 
 LET MetadataStart &amp;lt;= '''
 rule StartOffsetRule {
 strings:
 $start = "&amp;lt;OibSummary&amp;gt;"
 condition: any of them
 }
 '''
 LET MetadataEnd &amp;lt;= '''
 rule EndOffsetRule {
 strings:
 $end = "&amp;lt;/OibSummary&amp;gt;"
 condition: any of them
 }
 '''
 
 // Listing all Storage files in the Backup Repositories
 LET backup_repos = SELECT BackupRepoPath FROM BackupRepositories
 LET backup_files = SELECT * FROM foreach(row=backup_repos,
 query={
 SELECT *
 FROM glob(
 globs=[
 '/**/*.vbk',
 '/**/*.vib',
 '/**/*.vrb'
 ],
 root=BackupRepoPath,
 accessor='file'
 )
 })
 
 // Find last start offset of metadata for each Storage file
 LET start_offsets= SELECT File.FullPath AS FilePath,
 max(item=String.Offset) AS StartOffset
 FROM yara(
 files=backup_files.OSPath,
 rules=MetadataStart,
 start=0,
 end=18446744073709551615,
 number=100
 )
 GROUP BY File.FullPath
 
 // Find end offset for each start offset, extract and parse XML
 LET xml = SELECT parse_xml(
 accessor='data',
 file=read_file(
 filename=BackupFilePath,
 offset=StartOffset,
 length=EndOffset - StartOffset + 13
 )
 ) AS Metadata,
 BackupFilePath
 FROM foreach(row=start_offsets,
 query={
 SELECT File.FullPath AS BackupFilePath,
 StartOffset,
 String.Offset + StartOffset AS EndOffset
 FROM yara(
 files=pathspec(
 DelegateAccessor='file',
 DelegatePath=FilePath,
 Path=str(str=StartOffset)
 ),
 accessor='offset',
 rules=MetadataEnd,
 end=20971520,
 number=1
 )
 })
 WHERE Metadata

 // ========================= 
 // === Objects In Backup ===
 // =========================

 // Extracting interesting fields from OIB, OibFiles, Object, SourceHost, Storage, Point and Backup
 LET oib = SELECT BackupFilePath, 
 Metadata.OibSummary.OIB.AttrDisplayName AS DisplayName,
 Metadata.OibSummary.OIB.AttrVmName AS VMName,
 Metadata.OibSummary.OIB.AttrState AS State,
 Metadata.OibSummary.OIB.AttrType AS Type,
 Metadata.OibSummary.OIB.AttrAlgorithm AS Algorithm,
 Metadata.OibSummary.OIB.AttrHealthStatus AS HealthStatus,
 Metadata.OibSummary.OIB.AttrHasIndex AS HasIndex,
 Metadata.OibSummary.OIB.AttrHasExchange AS HasExchange,
 Metadata.OibSummary.OIB.AttrHasSharePoint AS HasSharePoint,
 Metadata.OibSummary.OIB.AttrHasSql AS HasSQL,
 Metadata.OibSummary.OIB.AttrHasAd AS HasAD,
 Metadata.OibSummary.OIB.AttrHasOracle AS HasOracle,
 Metadata.OibSummary.OIB.AttrHasPostgreSql AS HasPostgreSQL,
 Metadata.OibSummary.OIB.AttrHasVeeamArchiver AS HasVeeamArchiver,
 Metadata.OibSummary.OIB.AttrIsCorrupted AS IsCorrupted,
 Metadata.OibSummary.OIB.AttrIsRecheckCorrupted AS IsRecheckCorrupted,
 Metadata.OibSummary.OIB.AttrIsConsistent AS IsConsistent,
 Metadata.OibSummary.OIB.AttrIsPartialActiveFull AS IsPartialActiveFull,
 Metadata.OibSummary.OIB.AttrProductVersion AS ProductVersion,
 Metadata.OibSummary.OIB.AttrProductVersionFlags AS ProductVersionFlags,
 Metadata.OibSummary.OIB.AttrProductIsRentalLicense AS ProductIsRentalLicense,
 Metadata.OibSummary.SourceHost.AttrName AS HostName,
 Metadata.OibSummary.SourceHost.AttrHostInstanceId AS HostInstanceID,
 Metadata.OibSummary.Backup.AttrJobName AS JobName,
 Metadata.OibSummary.Backup.AttrPolicyName AS PolicyName,
 Metadata.OibSummary.PrevFileName AS PreviousFileInChain,
 back_enc_state[Metadata.OibSummary.Backup.AttrEncryptionState] AS BackupEncryptionState,
 Metadata.OibSummary.OIB.AttrEffectiveMemoryMb AS TempMemory,
 Metadata.OibSummary.Object.AttrViType || 'Physical machine' AS VirtualType,
 Metadata.OibSummary.Object.AttrName AS ExtractName,
 Metadata.OibSummary.Object.AttrObjectId AS ExtractID,
 oib_files_size(Files=Metadata.OibSummary.OibFiles.File) AS ExtractableFilesSize,
 parse_xml(file=Metadata.OibSummary.Storage.AttrPartialPath, accessor='data').Path.Elements AS BackupFile,
 timestamp(string=Metadata.OibSummary.OIB.AttrCreationTimeUtc) AS CreationTimeUTC,
 timestamp(string=Metadata.OibSummary.OIB.AttrCompletionTimeUtc) AS CompletionTimeUTC,
 humanize(bytes=int(int=Metadata.OibSummary.OIB.AttrApproxSize)) AS ApproximateSize,
 split(string=Metadata.OibSummary.Point.AttrNum, sep='\\.')[0] AS RestorePointNumber,
 restore_point_type[Metadata.OibSummary.Point.AttrType] AS RestorePointType,
 parse_xml(file=Metadata.OibSummary.Storage.`#text`, accessor='data').CBackupStats AS Stats,
 parse_xml(file=Metadata.OibSummary.OIB.AttrAuxData, accessor='data').COibAuxData AS AuxData,
 format_properties(
 Properties = parse_xml(file=Metadata.OibSummary.OIB.`#text`, accessor='data').GuestInfo.Property
 ) AS GuestInfo
 FROM xml
 
 // Expanding relevant fields into subfields
 LET expand_oib = SELECT BackupFilePath, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, HostName, HostInstanceID, JobName, PolicyName, PreviousFileInChain, BackupEncryptionState, VirtualType, ExtractName, ExtractID, ExtractableFilesSize, BackupFile, CreationTimeUTC, CompletionTimeUTC, ApproximateSize, RestorePointNumber, RestorePointType,
 format(
 format='%d MiB',
 args = int(int=TempMemory) || int(int=AuxData.DesktopOibAuxData.SystemConfiguration.RAMInfo.AttrTotalSizeMB)
 ) AS Memory,
 hv_disk_capacity(Disks=AuxData.HvAuxData.disks.disk)
 + desktop_disk_capacity(Disks=AuxData.DesktopOibAuxData.Disk)
 + vmware_disk_capacity(Disks=AuxData.COibAuxDataVmware.Disk)
 AS DisksCapacity,
 GuestInfo.GuestOsName AS GuestOSName,
 GuestInfo.GuestOsType AS GuestOSType,
 GuestInfo.DnsName AS GuestDNSName,
 GuestInfo.`Ip` AS GuestIP,
 GuestInfo.ToolsStatus AS GuestToolsStatus,
 GuestInfo.ToolsVersionStatus AS GuestToolsVersionStatus,
 Stats.BackupSize AS BackupSize,
 Stats.DataSize AS DataSize,
 Stats.DedupRatio AS DeduplicationRatio,
 Stats.CompressRatio AS CompressionRatio
 FROM oib
 
 // ===================
 // === Final query ===
 // ===================
 
 SELECT DisplayName,
 CreationTimeUTC,
 CompletionTimeUTC,
 ApproximateSize,
 DisksCapacity,
 RestorePointNumber,
 RestorePointType,
 HostName,
 HostInstanceID,
 BackupFile,
 BackupFilePath,
 ExtractableFilesSize,
 BackupSize,
 DataSize,
 DeduplicationRatio,
 CompressionRatio,
 VirtualType,
 VMName,
 Memory,
 GuestOSName,
 GuestOSType,
 GuestDNSName,
 GuestIP,
 GuestToolsStatus,
 GuestToolsVersionStatus,
 State,
 Type,
 Algorithm,
 HealthStatus,
 HasIndex,
 HasExchange,
 HasSharePoint,
 HasSQL,
 HasAD,
 HasOracle,
 HasPostgreSQL,
 HasVeeamArchiver,
 IsCorrupted,
 IsRecheckCorrupted,
 IsConsistent,
 IsPartialActiveFull,
 ProductVersion,
 ProductVersionFlags,
 ProductIsRentalLicense,
 JobName,
 PolicyName,
 BackupEncryptionState,
 PreviousFileInChain,
 ExtractName,
 ExtractID
 FROM expand_oib

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Veeam.RestorePoints.MetadataFiles</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.veeam.restorepoints.metadatafiles/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.veeam.restorepoints.metadatafiles/</guid><description>&lt;p&gt;Parses the metadata found in Veeam backup chain metadata files (&lt;code&gt;.vbm&lt;/code&gt;) to extract relevant fields for each Restore Point.&lt;/p&gt;
&lt;p&gt;These files are generated by Veeam Backup &amp;amp; Replication during backup jobs. This artifact accepts metadata from &lt;strong&gt;unencrypted&lt;/strong&gt; backups of virtual and physical infrastructures.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Veeam.RestorePoints.MetadataFiles

description: |
 Parses the metadata found in Veeam backup chain metadata files (`.vbm`) to extract relevant fields for each Restore Point.
 
 These files are generated by Veeam Backup &amp;amp; Replication during backup jobs. This artifact accepts metadata from **unencrypted** backups of virtual and physical infrastructures.

author: Synacktiv, Maxence Fossat - @cybiosity

reference:
 - https://www.synacktiv.com/publications/using-veeam-metadata-for-efficient-extraction-of-backup-artefacts-13

type: CLIENT

precondition: SELECT OS FROM info() WHERE OS = 'windows'

parameters:
 - name: BackupRepositories
 description: List of Backup Repositories where ".vbm" files should be looked for.
 type: csv
 default: |
 BackupRepoPath
 C:/BackupRepo1
 D:/BackupRepo2

required_permissions:
 - FILESYSTEM_READ

sources:
 - query: |
 // ============================
 // === Formatting functions ===
 // ============================
 
 // Function to format XML properties
 LET format_properties(Properties) = to_dict(item={ 
 SELECT AttrName AS _key,
 Value AS _value
 FROM Properties
 })

 // Function to format disk_info capacity for HvAuxData
 LET hv_disk_capacity(Disks) = to_dict(item= {
 SELECT disk_info.CHvVmRctIdentifier.AttrFileId AS _key,
 disk_info.Attrcapacity AS _value
 FROM Disks
 })

 // Function to format disk_info sizes for HvAuxData
 LET hv_disk_size(Disks) = to_dict(item= {
 SELECT disk_info.extent.Attrfilename AS _key,
 disk_info.extent.Attrsize AS _value
 FROM Disks
 })
 
 // Function to format CRawDiskInfo sizes for HvAuxData
 LET hv_raw_disk_size(RawDisks) = to_dict(item= {
 SELECT CRawDiskInfo.SourceFileName AS _key,
 CRawDiskInfo.ValidProcessedOffset AS _value
 FROM RawDisks
 })
 
 // Function to format Disk capacity for DesktopOibAuxData
 LET desktop_disk_capacity(Disks) = to_dict(item= {
 SELECT DevSetupInfo.AttrDevPath AS _key,
 Capacity AS _value
 FROM Disks
 })
 
 // Function to format Disk sizes for DesktopOibAuxData
 LET desktop_disk_size(Disks) = to_dict(item= {
 SELECT OriginalDiskUniqueId AS _key,
 Capacity AS _value
 FROM Disks
 })
 
 // Function to format Disk capacity for COibAuxDataVmware
 LET vmware_disk_capacity(Disks) = to_dict(item= {
 SELECT `Uuid` AS _key,
 Capacity AS _value
 FROM Disks
 })
 
 // Function to format Disk sizes for COibAuxDataVmware
 LET vmware_disk_size(Disks) = to_dict(item= {
 SELECT FlatFileName AS _key,
 ValidProcessedOffset AS _value
 FROM Disks
 })
 
 // Restore Point type
 LET restore_point_type = dict(
 `0`='Full',
 `1`='Increment'
 )
 
 // Backup encryption state
 LET back_enc_state = dict(
 `0`='Unencrypted',
 `2`='Encrypted'
 )




 // ========================
 // === Initial parsing ====
 // ========================
 
 // Parsing XML for each Veeam backup chain metadata file
 LET backup_repos = SELECT BackupRepoPath FROM BackupRepositories
 LET xml = SELECT * FROM foreach(row=backup_repos,
 query={
 SELECT Name AS MetadataFile, 
 parse_xml(file=OSPath) AS Metadata
 FROM glob(globs='/**/*.vbm', root=BackupRepoPath, accessor='auto')
 })
 
 // Extracting interesting fields from the parsed metadata
 LET metadata = SELECT MetadataFile,
 Metadata.BackupMeta.BackupMetaInfo.Oibs.OIB AS ObjectsInBackup,
 Metadata.BackupMeta.BackupMetaInfo.Objects.Object AS Objects,
 Metadata.BackupMeta.BackupMetaInfo.Hosts.Host AS Hosts,
 Metadata.BackupMeta.BackupMetaInfo.Storages.Storage AS Storages,
 Metadata.BackupMeta.BackupMetaInfo.Points.Point AS RestorePoints,
 Metadata.BackupMeta.Backup AS Backups
 FROM xml
 

 

 // ========================= 
 // === Objects In Backup ===
 // =========================
 
 // Expanding each Object In Backup (OIB) for each vbm file
 LET oibs = SELECT * FROM foreach(row=metadata,
 query={
 SELECT MetadataFile, Objects, Hosts, Storages, RestorePoints, Backups,
 _value.AttrDisplayName AS DisplayName,
 _value.AttrVmName AS VMName,
 _value.AttrState AS State,
 _value.AttrType AS Type,
 _value.AttrAlgorithm AS Algorithm,
 _value.AttrHealthStatus AS HealthStatus,
 _value.AttrHasIndex AS HasIndex,
 _value.AttrHasExchange AS HasExchange,
 _value.AttrHasSharePoint AS HasSharePoint,
 _value.AttrHasSql AS HasSQL,
 _value.AttrHasAd AS HasAD,
 _value.AttrHasOracle AS HasOracle,
 _value.AttrHasPostgreSql AS HasPostgreSQL,
 _value.AttrHasVeeamArchiver AS HasVeeamArchiver,
 _value.AttrIsCorrupted AS IsCorrupted,
 _value.AttrIsRecheckCorrupted AS IsRecheckCorrupted,
 _value.AttrIsConsistent AS IsConsistent,
 _value.AttrNeedHealthCheckRepair AS NeedHealthCheckRepair,
 _value.AttrIsPartialActiveFull AS IsPartialActiveFull,
 _value.AttrProductVersion AS ProductVersion,
 _value.AttrProductVersionFlags AS ProductVersionFlags,
 _value.AttrProductIsRentalLicense AS ProductIsRentalLicense,
 _value.AttrObjectId AS ObjectID,
 _value.AttrStorageId AS StorageID,
 _value.AttrPointId AS RestorePointID,
 _value.AttrEffectiveMemoryMb AS TempMemory,
 timestamp(string=_value.AttrCreationTimeUtc) AS CreationTimeUTC,
 timestamp(string=_value.AttrCompletionTimeUtc) AS CompletionTimeUTC,
 humanize(bytes=int(int=_value.AttrApproxSize)) AS ApproximateSize,
 parse_xml(file=_value.AttrAuxData, accessor='data').COibAuxData AS AuxData,
 format_properties(
 Properties = parse_xml(file=_value.AttrGuestInfo, accessor='data').GuestInfo.Property
 ) AS GuestInfo
 FROM foreach(row=ObjectsInBackup)
 })
 
 // Correlating OIBs with Objects information
 LET oibs_objects = SELECT * FROM foreach(row=oibs,
 query={
 SELECT MetadataFile, Hosts, Storages, RestorePoints, Backups, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, NeedHealthCheckRepair, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, StorageID, RestorePointID, CreationTimeUTC, CompletionTimeUTC, ApproximateSize,
 format(format='%d MiB',
 args = int(int=TempMemory) || int(int=AuxData.DesktopOibAuxData.SystemConfiguration.RAMInfo.AttrTotalSizeMB))
 AS Memory,
 hv_disk_capacity(Disks=AuxData.HvAuxData.disks.disk)
 + desktop_disk_capacity(Disks=AuxData.DesktopOibAuxData.Disk)
 + vmware_disk_capacity(Disks=AuxData.COibAuxDataVmware.Disk)
 AS DisksCapacity,
 hv_disk_size(Disks=AuxData.HvAuxData.disks.disk)
 + hv_raw_disk_size(RawDisks=AuxData.HvAuxData.raw_disks.CRawDiskBackupObject)
 + desktop_disk_size(Disks=AuxData.DesktopOibAuxData.Disk)
 + vmware_disk_size(Disks=AuxData.COibAuxDataVmware.Disk)
 AS ExtractableFilesSize,
 GuestInfo.GuestOsName AS GuestOSName,
 GuestInfo.GuestOsType AS GuestOSType,
 GuestInfo.DnsName AS GuestDNSName,
 GuestInfo.`Ip` AS GuestIP,
 GuestInfo.ToolsStatus AS GuestToolsStatus,
 GuestInfo.ToolsVersionStatus AS GuestToolsVersionStatus,
 _value.AttrViType || 'Physical machine' AS VirtualType,
 _value.AttrName AS ExtractName,
 _value.AttrObjectId AS ExtractID,
 _value.AttrHostId AS HostID
 FROM foreach(row=Objects) WHERE _value.AttrId = ObjectID
 })
 
 // Correlating OIBs with Hosts information
 LET oibs_hosts = SELECT * FROM foreach(row=oibs_objects,
 query={
 SELECT MetadataFile, Storages, RestorePoints, Backups, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, NeedHealthCheckRepair, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, StorageID, RestorePointID, CreationTimeUTC, CompletionTimeUTC, ApproximateSize, Memory, DisksCapacity, ExtractableFilesSize, GuestOSName, GuestOSType, GuestDNSName, GuestIP, GuestToolsStatus, GuestToolsVersionStatus, VirtualType, ExtractName, ExtractID,
 _value.AttrName AS HostName,
 _value.AttrHostInstanceId AS HostInstanceID
 FROM foreach(row=Hosts) WHERE _value.AttrId = HostID
 })
 
 // Correlating OIBs with Storages information
 LET oibs_storages = SELECT * FROM foreach(row=oibs_hosts,
 query={
 SELECT MetadataFile, RestorePoints, Backups, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, NeedHealthCheckRepair, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, RestorePointID, CreationTimeUTC, CompletionTimeUTC, ApproximateSize, Memory, DisksCapacity, ExtractableFilesSize, GuestOSName, GuestOSType, GuestDNSName, GuestIP, GuestToolsStatus, GuestToolsVersionStatus, VirtualType, ExtractName, ExtractID, HostName, HostInstanceID,
 parse_xml(file=_value.AttrPartialPath, accessor='data').Path.Elements AS BackupFile,
 _value.AttrFilePath AS BackupFilePath,
 parse_xml(file=_value.AttrStats, accessor='data').CBackupStats AS Stats
 FROM foreach(row=Storages) WHERE _value.AttrId = StorageID
 })
 
 // Correlating OIBs with Restore Points information
 LET oibs_points = SELECT * FROM foreach(row=oibs_storages,
 query={
 SELECT MetadataFile, Backups, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, NeedHealthCheckRepair, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, CreationTimeUTC, CompletionTimeUTC, ApproximateSize, Memory, DisksCapacity, ExtractableFilesSize, GuestOSName, GuestOSType, GuestDNSName, GuestIP, GuestToolsStatus, GuestToolsVersionStatus, VirtualType, ExtractName, ExtractID, HostName, HostInstanceID, BackupFile, BackupFilePath,
 Stats.BackupSize AS BackupSize,
 Stats.DataSize AS DataSize,
 Stats.DedupRatio AS DeduplicationRatio,
 Stats.CompressRatio AS CompressionRatio,
 split(string=_value.AttrNum, sep='\\.')[0] AS RestorePointNumber,
 restore_point_type[_value.AttrType] AS RestorePointType,
 _value.AttrBackupId AS BackupID
 FROM foreach(row=RestorePoints) WHERE _value.AttrId = RestorePointID
 })
 
 // Correlating OIBs with Backups information
 LET oibs_backups = SELECT * FROM foreach(row=oibs_points,
 query={
 SELECT MetadataFile, DisplayName, VMName, State, Type, Algorithm, HealthStatus, HasIndex, HasExchange, HasSharePoint, HasSQL, HasAD, HasOracle, HasPostgreSQL, HasVeeamArchiver, IsCorrupted, IsRecheckCorrupted, IsConsistent, NeedHealthCheckRepair, IsPartialActiveFull, ProductVersion, ProductVersionFlags, ProductIsRentalLicense, CreationTimeUTC, CompletionTimeUTC, ApproximateSize, Memory, DisksCapacity, ExtractableFilesSize, GuestOSName, GuestOSType, GuestDNSName, GuestIP, GuestToolsStatus, GuestToolsVersionStatus, VirtualType, ExtractName, ExtractID, HostName, HostInstanceID, BackupFile, BackupFilePath, BackupSize, DataSize, DeduplicationRatio, CompressionRatio, RestorePointNumber, RestorePointType,
 _value.AttrJobName AS JobName,
 _value.AttrPolicyName AS PolicyName,
 _value.AttrDirPath AS BackupDirectory,
 back_enc_state[_value.AttrEncryptionState] AS BackupEncryptionState
 FROM foreach(row=Backups) WHERE _value.AttrId = BackupID
 })

 


 // ===================
 // === Final query ===
 // ===================
 
 SELECT DisplayName,
 CreationTimeUTC,
 CompletionTimeUTC,
 ApproximateSize,
 DisksCapacity,
 RestorePointNumber,
 RestorePointType,
 HostName,
 HostInstanceID,
 BackupFile,
 BackupFilePath,
 ExtractableFilesSize,
 BackupSize,
 DataSize,
 DeduplicationRatio,
 CompressionRatio,
 VirtualType,
 VMName,
 Memory,
 GuestOSName,
 GuestOSType,
 GuestDNSName,
 GuestIP,
 GuestToolsStatus,
 GuestToolsVersionStatus,
 State,
 Type,
 Algorithm,
 HealthStatus,
 HasIndex,
 HasExchange,
 HasSharePoint,
 HasSQL,
 HasAD,
 HasOracle,
 HasPostgreSQL,
 HasVeeamArchiver,
 IsCorrupted,
 IsRecheckCorrupted,
 IsConsistent,
 NeedHealthCheckRepair,
 IsPartialActiveFull,
 ProductVersion,
 ProductVersionFlags,
 ProductIsRentalLicense,
 JobName,
 PolicyName,
 BackupEncryptionState,
 BackupDirectory,
 MetadataFile,
 ExtractName,
 ExtractID
 FROM oibs_backups

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Vhdx.RemapConfigBuilder</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.remapconfigbuilder/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.remapconfigbuilder/</guid><description>&lt;p&gt;Create remapping configuration YAML file(s) to virtually mount&lt;br&gt;
VHDX profiles into virtual Velociraptor clients.&lt;/p&gt;
&lt;p&gt;This artifact is part of the Vhdx Suite. This suite requires to have
the Velociraptor server artifact &lt;code&gt;Windows.Sys.Users&lt;/code&gt; override on the
server to work properly.&lt;/p&gt;
&lt;p&gt;Read the dedicated blog post before using this artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
 name: Windows.Vhdx.RemapConfigBuilder
 description: |
 Create remapping configuration YAML file(s) to virtually mount 
 VHDX profiles into virtual Velociraptor clients.
 
 This artifact is part of the Vhdx Suite. This suite requires to have 
 the Velociraptor server artifact `Windows.Sys.Users` override on the 
 server to work properly.

 Read the dedicated blog post before using this artifact.

 author: Yann Malherbe - @mirwitch

 reference: 
 - https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/

 type: CLIENT

 implied_permissions:
 - FILESYSTEM_WRITE

 parameters:
 - name: vhdxFolderPath
 type: string
 default: "F:\\vhdx\\"
 description: "Directory containing VHDX profile files."

 - name: usernameExtractor
 type: regex
 default: "profile_(?&amp;lt;Username&amp;gt;.*).vhdx"
 description: "Regex used to extract usernames from filenames."

 - name: user
 type: regex
 default: Administrator
 description: "Optional filter to restrict which profiles to process."

 - name: virtualHostname
 type: string
 default: "VHDX"
 description: "Hostname to assign to the virtual clients."

 - name: vhdxOffset
 type: hidden
 default: 1048576
 description: "NTFS start offset inside VHDX."
 
 - name: batchSize
 type: int
 default: 30
 description: "Number of profiles per virtual client." 

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

 query: |
 // Static remapping header
 LET RemappingHeader =''' 
 remappings:
 - type: permissions
 permissions:
 - COLLECT_CLIENT
 - FILESYSTEM_READ
 - FILESYSTEM_WRITE
 - READ_RESULTS
 - MACHINE_STATE
 - SERVER_ADMIN
 - type: impersonation
 os: windows
 hostname: "&amp;lt;VIRTUAL_HOSTNAME&amp;gt;"
 env:
 - key: SystemRoot
 value: C:\Windows
 - key: WinDir
 value: C:\Windows
 disabled_functions:
 - amsi
 - lookupSID
 - token
 disabled_plugins:
 - users
 - certificates
 - handles
 - pslist
 - interfaces
 - modules
 - netstat
 - partitions
 - proc_dump
 - proc_yara
 - vad
 - winobj
 - wmi
 
 - type: shadow
 from:
 accessor: data
 "on":
 accessor: data
 
 - type: shadow
 from:
 accessor: raw_reg
 "on":
 accessor: raw_reg
 
 - type: shadow
 from:
 accessor: zip
 "on":
 accessor: zip
 '''
 
 // Remapping required per user
 LET RemappingUser = '''
 - type: mount
 description: 'NTFS - &amp;lt;USERNAME&amp;gt;'
 from:
 accessor: raw_ntfs
 prefix: |
 {
 "DelegateAccessor": "offset",
 "Delegate": {
 "DelegateAccessor": "vhdx",
 "DelegatePath": "&amp;lt;VHDX_PATH&amp;gt;",
 "Path":"/&amp;lt;VHDX_OFFSET&amp;gt;"
 },
 "Path": "&amp;lt;PROFILE_PATH&amp;gt;"
 }
 "on":
 accessor: ntfs
 prefix: '\\.\C:\Users\&amp;lt;USERNAME&amp;gt;'
 path_type: ntfs
 
 - type: mount
 description: 'File - &amp;lt;USERNAME&amp;gt;'
 from:
 accessor: raw_ntfs
 prefix: |
 {
 "DelegateAccessor": "offset",
 "Delegate": {
 "DelegateAccessor": "vhdx",
 "DelegatePath": "&amp;lt;VHDX_PATH&amp;gt;",
 "Path":"/&amp;lt;VHDX_OFFSET&amp;gt;"
 },
 "Path": "&amp;lt;PROFILE_PATH&amp;gt;"
 }
 "on":
 accessor: file
 prefix: 'C:\Users\&amp;lt;USERNAME&amp;gt;'
 path_type: windows
 
 - type: mount
 description: 'Auto - &amp;lt;USERNAME&amp;gt;'
 from:
 accessor: raw_ntfs
 prefix: |
 {
 "DelegateAccessor": "offset",
 "Delegate": {
 "DelegateAccessor": "vhdx",
 "DelegatePath": "&amp;lt;VHDX_PATH&amp;gt;",
 "Path":"/&amp;lt;VHDX_OFFSET&amp;gt;"
 },
 "Path": "&amp;lt;PROFILE_PATH&amp;gt;"
 }
 "on":
 accessor: auto
 prefix: 'C:\Users\&amp;lt;USERNAME&amp;gt;'
 path_type: windows
 
 - type: mount
 description: 'Registry - &amp;lt;USERNAME&amp;gt; NTUSER.DAT'
 from:
 accessor: raw_reg
 prefix: |-
 {
 "Path": "/",
 "DelegateAccessor": "raw_ntfs",
 "Delegate": {
 "DelegateAccessor":"offset",
 "Delegate": {
 "DelegateAccessor": "vhdx",
 "DelegatePath": "&amp;lt;VHDX_PATH&amp;gt;",
 "Path": "/&amp;lt;VHDX_OFFSET&amp;gt;"
 },
 "Path":"&amp;lt;PROFILE_PATH&amp;gt;/NTUSER.DAT"
 }
 }
 path_type: registry
 "on":
 accessor: registry
 prefix: HKEY_USERS\&amp;lt;USERNAME&amp;gt;
 path_type: registry 
 
 - type: mount
 description: 'Registry - &amp;lt;USERNAME&amp;gt; UsrClass'
 from:
 accessor: raw_reg
 prefix: |-
 {
 "Path": "/",
 "DelegateAccessor": "raw_ntfs",
 "Delegate": {
 "DelegateAccessor":"offset",
 "Delegate": {
 "DelegateAccessor": "vhdx",
 "DelegatePath": "&amp;lt;VHDX_PATH&amp;gt;",
 "Path": "/&amp;lt;VHDX_OFFSET&amp;gt;"
 },
 "Path":"&amp;lt;PROFILE_PATH&amp;gt;/AppData/Local/Microsoft/Windows/UsrClass.dat"
 }
 }
 path_type: registry
 "on":
 accessor: registry
 prefix: HKEY_USERS\&amp;lt;USERNAME&amp;gt;_Classes
 path_type: registry
 '''

 // Get the list of user profiles of interest
 LET userProfilesList = SELECT *,
 parse_string_with_regex(
 string=Name, 
 regex=usernameExtractor
 ) AS userProfile 
 FROM glob(globs=vhdxFolderPath+"/*.vhdx") 
 WHERE userProfile.Username AND userProfile.Username =~ user
 
 
 // Split the user list into batches
 LET userBatch = SELECT rows AS user_batch 
 FROM batch(query={
 SELECT *
 FROM userProfilesList
 }, batch_size=batchSize)


 // Create the header of the remapping file
 LET HeaderRemapping = regex_replace(re="&amp;lt;VIRTUAL_HOSTNAME&amp;gt;", 
 replace=virtualHostname + "_" + firstBatchUser, 
 source=RemappingHeader)
 
 // Create the user sections of the remapping file
 LET UserRemapping = SELECT
 regex_replace(re="&amp;lt;USERNAME&amp;gt;", 
 replace=userProfile.Username, source= 
 regex_replace(re="&amp;lt;PROFILE_PATH&amp;gt;", 
 replace="/Profile", source= 
 regex_replace(re="&amp;lt;VHDX_OFFSET&amp;gt;", 
 replace=vhdxOffset, source=
 regex_replace(re="&amp;lt;VHDX_PATH&amp;gt;", 
 replace=regex_replace(
 re="\\\\", replace="/", source=OSPath), 
 source=RemappingUser)
 ))) AS Content
 FROM scope()
 
 // Iterate on the users part of the bulk
 LET BulkUserRemapping = SELECT * FROM foreach(
 row=user_batch,
 query=UserRemapping
 )
 
 // Write the remapping content in a temp file
 LET tmpFile = tempfile(
 data=HeaderRemapping + BulkUserRemapping.Content, 
 remove_last=TRUE
 )
 
 // Retrieve the directory from the running Velociraptor executable
 LET veloInfo = SELECT Exe FROM info()

 // Get the first user of the batch
 LET firstBatchUser = user_batch[0].userProfile.Username

 // Get the remapping filename
 LET remappingFilename = firstBatchUser + ".yaml"
 
 // Copy the file to the remapping YAML file
 LET copyFile = SELECT copy(
 filename=tmpFile, 
 dest=pathspec(parse=veloInfo[0].Exe).Dirname + "Vhdx" + "Remapping" + remappingFilename,
 create_directories=TRUE) AS CreatedConfig
 FROM scope()



 // Create dedicated YAML file for each batch of users
 SELECT * FROM foreach(row=userBatch, query=copyFile)
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Vhdx.Sys.Users</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.sys.users/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.sys.users/</guid><description>&lt;p&gt;List User accounts by inspecting registry keys. This method is a
reliable indicator for users who have physically logged into the
system and thereby created local profiles.&lt;/p&gt;
&lt;p&gt;This will not include domain users or the output from &lt;code&gt;NetUserEnum&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you should collect the &lt;code&gt;Windows.Sys.AllUsers&lt;/code&gt; artifact to get all
possible users on the system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This artifact should be rename to replace the official
&lt;code&gt;Windows.Sys.Users&lt;/code&gt; allowing to list the users for potential user
profiles from virtual Velociraptor clients.&lt;/p&gt;
&lt;p&gt;Read the dedicated blog post before using this artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Vhdx.Sys.Users
description: |
 List User accounts by inspecting registry keys. This method is a
 reliable indicator for users who have physically logged into the
 system and thereby created local profiles.

 This will not include domain users or the output from `NetUserEnum`
 - you should collect the `Windows.Sys.AllUsers` artifact to get all
 possible users on the system.
 
 This artifact should be rename to replace the official 
 `Windows.Sys.Users` allowing to list the users for potential user 
 profiles from virtual Velociraptor clients.

 Read the dedicated blog post before using this artifact.
 
author: Yann Malherbe - @mirwitch

reference: 
 - https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/

parameters:
 - name: remoteRegKey
 default: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*
 description: "Location of the registry key holding the profile list."

 - name: labelName
 default: "remapped_profile"
 type: string
 description: "Client label that signals the use of VHDX-based enumeration."

imports:
 - Windows.Sys.AllUsers

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

 query: |

 LET GetTimestamp(High, Low) = if(condition=High,
 then=timestamp(winfiletime=High * 4294967296 + Low))

 // lookupSID() may not be available on deaddisk analysis
 LET Standard = SELECT split(string=Key.OSPath.Basename, sep="-")[-1] as Uid,
 "" AS Gid,
 LookupSIDCache(SID=Key.OSPath.Basename || "") AS Name,
 Key.OSPath as Description,
 ProfileImagePath as Directory,
 Key.OSPath.Basename as UUID,
 Key.Mtime as Mtime,
 {
 SELECT Mtime
 FROM stat(filename=expand(path=ProfileImagePath))
 } AS HomedirMtime,
 dict(ProfileLoadTime=GetTimestamp(
 High=LocalProfileLoadTimeHigh, Low=LocalProfileLoadTimeLow),
 ProfileUnloadTime=GetTimestamp(
 High=LocalProfileUnloadTimeHigh, Low=LocalProfileUnloadTimeLow)
 ) AS Data
 FROM read_reg_key(globs=remoteRegKey, accessor="registry")
 
 // User list for VHDX profiles emulating the Standard one
 LET UserProfile = SELECT
 OSPath.Components[-2] AS Uid,
 OSPath.Dirname AS Directory,
 OSPath.Components[-2] AS UUID,
 OSPath.Components[-2] AS Name,
 "" AS Gid,
 Mtime,
 Mtime AS HomedirMtime,
 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\" + OSPath.Components[-2] AS Description
 FROM glob(globs="C:/Users/*/NTUSER.DAT")
 
 // Get the labels of the agent 
 LET agent_config = SELECT labels FROM config

 // Take the appropriate user list method
 SELECT * FROM if(condition=agent_config.labels=~labelName, then=UserProfile, else=Standard)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Vhdx.VirtualClientRemover</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.virtualclientremover/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.virtualclientremover/</guid><description>&lt;p&gt;Kill the Velociraptor agent used for the VHDX profiles virtual host.&lt;/p&gt;
&lt;p&gt;This artifact is part of the Vhdx Suite. This suite requires to
have the custom &lt;code&gt;Windows.Sys.Users&lt;/code&gt; override the server to work properly.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Vhdx.VirtualClientRemover
description: |
 Kill the Velociraptor agent used for the VHDX profiles virtual host. 
 
 This artifact is part of the Vhdx Suite. This suite requires to 
 have the custom `Windows.Sys.Users` override the server to work properly.

author: Yann Malherbe - @mirwitch

reference: 
 - https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/

type: CLIENT

implied_permissions:
 - EXECVE
 - FILESYSTEM_WRITE
 
parameters:
 - name: RemappingFile
 type: string
 default: "\\\\Vhdx\\\\Remapping\\\\"
 description: "Specific remapping file or directory to target."
 
 - name: RemoveConfiguration
 description: "If enabled, deletes Vhdx folder and its subfolders."
 type: bool
 
 - name: ReallyKillProcess
 description: "If enabled, terminates running Velociraptor processes."
 type: bool

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

 query: |
 
 LET targets = SELECT Name as ProcessName, Exe, CommandLine, Pid 
 FROM Artifact.Windows.System.Pslist(ProcessRegex="Velociraptor", CommandLineRegex=RemappingFile)
 
 LET kill_targets = SELECT * FROM foreach(
 row= targets,
 query={
 SELECT ProcessName,Exe,CommandLine,Pid,
 dict(ReturnCode=ReturnCode,Complete=Complete,Stdout=Stdout,Stderr=Stderr) as Execve,
 if(condition= Stdout=~'^SUCCESS',
 then= TRUE,
 else= FALSE) as Killed
 FROM execve(
 argv=["taskkill", "/PID", Pid, "/T", "/F"])
 })
 
 
 
 // Retrieve the directory from the running Velociraptor executable
 LET veloInfo = SELECT Exe FROM info()
 LET veloExe = SELECT * FROM glob(globs=veloInfo.Exe)
 LET vhdxFolder = SELECT * FROM glob(globs=strip(string=veloExe.OSPath.Dirname.String, suffix=" ") + '\\Vhdx{,\\**}') ORDER BY OSPath DESC
 
 
 LET deleteVhdxFolder = SELECT *, rm(filename=OSPath) as Removed 
 FROM vhdxFolder 
 WHERE log(message="Removing " + OSPath)
 
 LET RemoveConfiguration &amp;lt;= SELECT * FROM if(condition=RemoveConfiguration,
 then=deleteVhdxFolder, 
 else= {SELECT *, FALSE as Deleted FROM vhdxFolder})
 
 SELECT * 
 FROM if(condition=ReallyKillProcess,
 then= kill_targets,
 else= { SELECT *, FALSE as Killed FROM targets } )
 
 
 

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.Vhdx.VirtualClientRunner</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.virtualclientrunner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/windows.vhdx.virtualclientrunner/</guid><description>&lt;p&gt;Run the Velociraptor agent using the remapping configuration created. This
agent allow to virtually map the VHDX profiles into virtual Velociraptor agents.&lt;/p&gt;
&lt;p&gt;Two ways to execute agents exist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using native VQL using workers that will be kill once the max execution
time is reached.&lt;/li&gt;
&lt;li&gt;Leveraging PowerShell &lt;code&gt;Start-Process&lt;/code&gt; cmdlet allowing to run the agents
in the background and independant from the running artifact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no persistence mechanism to keep the process running after reboot.
The artifact need to be re-run to have the virtual Velociraptor agents back.&lt;/p&gt;
&lt;p&gt;This artifact is part of the Vhdx Suite. This suite requires to have
the &lt;code&gt;Windows.Sys.Users&lt;/code&gt; override on the server to work properly.&lt;/p&gt;
&lt;p&gt;Read the dedicated blog post before using this artifact.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.Vhdx.VirtualClientRunner
description: |
 Run the Velociraptor agent using the remapping configuration created. This 
 agent allow to virtually map the VHDX profiles into virtual Velociraptor agents.
 
 Two ways to execute agents exist:
 - Using native VQL using workers that will be kill once the max execution 
 time is reached.
 - Leveraging PowerShell `Start-Process` cmdlet allowing to run the agents
 in the background and independant from the running artifact.
 
 There is no persistence mechanism to keep the process running after reboot. 
 The artifact need to be re-run to have the virtual Velociraptor agents back.
 
 This artifact is part of the Vhdx Suite. This suite requires to have 
 the `Windows.Sys.Users` override on the server to work properly.

 Read the dedicated blog post before using this artifact.

author: Yann Malherbe - @mirwitch

reference: 
 - https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/

type: CLIENT

implied_permissions:
 - EXECVE
 - FILESYSTEM_WRITE

parameters:
 - name: customLabel
 type: string
 default: "remapped_profile"
 description: "Label to assign to virtual clients (must match label used in Windows.Sys.Users)"
 
 - name: remappingFile
 type: regex
 default: "."
 description: "One or more remapping YAML files to launch."
 
 - name: workers
 type: int
 default: 100
 description: "Number of workers for the native VQL runner."
 
 - name: PowerShellRunner
 type: bool
 default: FALSE
 description: "Choose to run the agent using PowerShell Start-Process cmdlet."

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

 query: |
 // Retrieve the directory from the running Velociraptor executable
 LET veloInfo = SELECT Exe FROM info()
 LET veloFolderPath = pathspec(parse=veloInfo[0].Exe).Dirname
 
 // Create Writeback directory
 LET copyFile &amp;lt;= SELECT copy(
 filename="",
 accessor="data",
 dest=veloFolderPath + "\\Vhdx\\Writeback\\empty", 
 create_directories=TRUE) 
 FROM scope()

 // Extract username from filename
 LET GetUsername(Filename) = regex_replace(source=Filename, re="\\.yaml", replace="")
 
 // Get the config file paths 
 LET configFiles = SELECT OSPath.String AS RemappingFile,
 "C:\\Windows\\Temp\\velociraptor_Vhdx_Buffer_" + GetUsername(Filename=Name) + ".bin" AS LocalBufferPath,
 veloFolderPath.Path + "\\Vhdx\\Writeback\\Vhdx_" + GetUsername(Filename=Name) + ".yaml" AS WritebackFilename
 FROM glob(globs=veloFolderPath + "\\Vhdx\\Remapping\\*") 
 WHERE Name =~ remappingFile


 // Run the agent using PowerShell Start-Process cmdlet
 LET powerShellAgentRunner = SELECT RemappingFile, Complete, ReturnCode, Stdout, Stderr FROM execve(argv=[
 "powershell", 
 "-ExecutionPolicy", "Bypass", 
 "-NoProfile", 
 "-Command", 
 "Start-Process -FilePath '"+ veloInfo[0].Exe +"' -ArgumentList '--config client.config.yaml --config.client-writeback-windows=\"" + WritebackFilename + "\" --config.client-local-buffer-filename-windows=\"" + LocalBufferPath + "\" --remap \"" + RemappingFile + "\" --config.client-labels=" + customLabel + " client' -WorkingDirectory '" + veloFolderPath.Path + "' -WindowStyle Hidden"
 ])

 // Run the agent using the native VQL
 LET agentRunner = SELECT *
 FROM execve(argv=[veloInfo[0].Exe, 
 "--remap", RemappingFile, 
 "--config", "client.config.yaml", 
 "--config.client-writeback-linux", WritebackFilename,
 "--config.client-writeback-windows", WritebackFilename,
 "--config.client-writeback-darwin", WritebackFilename,
 "--config.client-local-buffer-filename-windows", LocalBufferPath,
 "--config.client-labels", customLabel, 
 "-v", "client"],
 cwd=veloFolderPath,
 sep="\n") 
 
 
 // Run the agent for each remapping file using PowerShell Start-Process cmdlet
 LET powerShellAgentRunners = SELECT * FROM foreach(
 row=configFiles,
 query=powerShellAgentRunner
 ) WHERE log(message="Running agent using PowerShell Start-Process cmdlet for " + RemappingFile)

 // Run the agent using the native Velociraptor binary
 LET agentRunners = SELECT * FROM foreach(
 row=configFiles,
 query=agentRunner,
 async=TRUE,
 workers=workers
 )
 
 // Run the virtual Velociraptor agent via PowerShell or native VQL 
 SELECT * FROM if(condition=PowerShellRunner, then=powerShellAgentRunners, else=agentRunners)

&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Windows.WinSCP.Passwords</title><link>https://docs.velociraptor.app/exchange/artifacts/pages/custom.windows.winscp.passwords/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.velociraptor.app/exchange/artifacts/pages/custom.windows.winscp.passwords/</guid><description>&lt;p&gt;Extract WinSCP obfuscated saved passwords from registry.
Further information regarding deobfuscation can be found here: &lt;a href="https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/" target="_blank" &gt;https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/&lt;/a&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;
name: Windows.WinSCP.Passwords
author: "Yaron King - @Sam0rai"
description: |
 Extract WinSCP obfuscated saved passwords from registry.
 Further information regarding deobfuscation can be found here: https://www.xmcyber.com/blog/extracting-encrypted-credentials-from-common-tools-2/

type: CLIENT

precondition:
 SELECT * FROM info() where OS = 'windows'

parameters:
 - name: SearchRegistryGlob
 default: HKEY_USERS\\S-1-5-21-*\\Software\\Martin Prikryl\\WinSCP 2\\Sessions\\*\\password
 description: Use a glob to define the registry path to search for saved passwords.

sources:
 - query: |
 SELECT Data.value as ObfuscatedPassword, FullPath, ModTime
 FROM glob(globs=SearchRegistryGlob, accessor='reg')

&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>