SonicWall Endpoint Security Cheat Sheet for Threat Hunting

SonicWall Endpoint Security Cheat Sheet for Threat Hunting

Process Execution Operations

Process/Start* Process/End* Process/ParentIdSpoofing* Thread/RemoteThread* Image/Load*
ProcessID ProcessID ProcessID ProcessID ProcessID
ParentProcessID ParentProcessID ParentProcessID InjectorProcessID ImageChecksum
ImageName UserName ImageName ThreadID TimeDateStamp*
CommandLine CommandLine Spoofed_ParentProcessID ImageMD5
UserName UserName ImageSHA1
ProcessGUID PackageFullName ImageSHA256
ParentProcessGUID CreationFlags FileName
PackageFullName
CreationFlags
Creation_timestamp

* donates a nested query

File and Registry Operations

FileIo/Write* FileIo/FileRename* FileIo/FileDelete* Registry/Create* Registry/SetValue*
ProcessID ProcessID ProcessID ProcessID ProcessID
FilePath FileObject FilePath KeyName KeyName
IOSize FileOldPath* FileKey Registry/Create* KeyHandle
IOFlags FileNewPath* ValueName
FileObject Data

Networking Operations

TcpIp/ConnectIPV4 TcpIp/ConnectIPV6 WinHTTP/Log WinInet/Log
ProcessID ProcessID ProcessID ProcessID
SourceAddress DestAddress URI URL
SourcePort DestPort Verb Verb
DestAddress RequestHeaders
DestPort ResponseHeaders

PowerShell Operations

PowerShell/Command Execution
ProcessID HostApplication ScriptName ShellID
ContextInfo EngineVersion CommandPath UserData
HostName RunspaceID SequenceNumber Payload
HostVersion CommandName User
HostID CommandType ConnectedUser

Direct Items

Direct Items
EndpointID EventTime ProcessID ProcessUserName
OS AccountName ParentProcessID CommandLine
Hostname TenantName ImageName ProcessGUID
AgentVersion GroupName ImagePath ParentProcessGUID
TrackID Events ImageSHA256

Miscellaneous Operations

SecurityAudit/CredentialValidation DOTNET/ModuleLoad
ProcessID CommandLine ProcessID
ParentProcessID PackageName ModuleILPath
UserName TargetUserName ModuleNativePath
ProcessGUID Workstation
ParentProcessGUID Status
Creation_timestamp

Query Creation Essentials

There are two kinds of queries:

  • Direct Query
  • Nested Query
  1. Direct query items can be called without expanding nested ‘Events’ data.
  2. When expanding ‘Events’ data, additional columns must be designated for output to separate the JSON record. All subfields do not need to be added for the query to run, but if the fields aren’t designated, they will not be displayed in results.
  3. Start query with ProdV1 (data table) unless using a ‘let’ statement.
Direct Query Example Nested Query Example
Prodv1 ProdV1
|where EndpointID == “e115190832445” |mv-expand Action = parse_json(Events)
|where ImageName has “powershell.exe”

|extend EventName = tostring(Action.EventName)

, Key = tostring(Action.KeyName)
, Value = tostring(Action.ValueName)

The command ‘mv-expand’ allows the nested items in ‘Events’ to be read by ‘parse_json’ and assigned via ‘Action’. Then, columns are added via ‘extend’ to break the results up respectively.

|where EventName startswith “Registry”
|project ProcessID, ImageName, EventName, EventTime, Key, Value

When using “project”, those will be the only columns shown in the results. Ensure you have all necessary and/or relevant fields listed.

Join Query Creation Examples

When running queries, multiple statements can be run and joined into a single table result. Here is an example of a query that shows parent processes which make network connections, along with the geolocation data for each IP address.

let trackInfo =

The first query statement ‘trackInfo’ pulls the events where processes start.

ProdV1
| mv-expand Action = parse_json(Events)
| extend EventName = tostring(Action.EventName) , ProcessID = tostring(Action.ProcessID) , Timestamp = tostring(Action.Creation_timestamp)
| where EventName has "Process/Start"
| project EndpointID, TrackID, ProcessID, EventName, Timestamp;
let geoInfo =

The ‘geoInfo’ statement pulls addresses and sources geolocation data using the KQL ‘geo_info_from_ip_address’ function.

ProdV1
| mv-expand Action = parse_json(Events)
| extend EventName = tostring(Action.EventName)
, ProcessID = tostring(Action.ProcessID)
, Timestamp = tostring(Action.Creation_timestamp)
, DestAddress = tostring(Action.DestAddress)
, DestPort = tostring(Action.DestPort)
, SourceAddress = tostring(Action.SourceAddress)
, SourcePort = tostring(Action.SourcePort)
, DestCountry = geo_info_from_ip_address(tostring(Action.DestAddress)).country
, DestState = geo_info_from_ip_address(tostring(Action.DestAddress)).state
, Latitude = geo_info_from_ip_address(tostring(Action.DestAddress)).latitude
, Longitude = geo_info_from_ip_address(tostring(Action.DestAddress)).longitude

| where EventName has "TcpIp"

| join kind=inner (trackInfo) on ProcessID;

These two statements will be tied together based on the ProcessID and put into a new ‘geoInfo’ table.

geoInfo
| summarize arg_max(EventTime, *) by EventTime
| project EndpointID, ProcessID, ImageName, EventName, DestAddress, DestPort, SourceAddress, SourcePort, DestCountry

Direct Keyword Queries

Name Query
Recent Events (No Filters) | limit 10/50/100
Application Events | where ImageName == “<application.exe>”
Endpoint Events | where EndpointID == “<endpoint id>”
Command or String | where CommandLine has “<string>”
Process File Path | where ImagePath == “<path>” OR| where ImagePath has_any (“AppData”, “Temp”)
Events w/ Specific Agent Version(s) | where AgentVersion == “1.0.4” OR| where AgentVersion has_any (“1.0.4”, “1.0.15”)
List Distinct Items (Endpoints, Events, etc) | distinct <keyword>
Find Specific Process | where ProcessID == “5492”
Find All Events In a Process | where TrackID == “<TrackID>”
Operating Systems | distinct OS OR| where OS startswith “Windows”
Processes Run By Specific User | where ProcessUserName == “<username>”
Lookup Tenant | where TenantName == “<tenant>”
Lookup Group | where GroupName == “<group>”
Lookup Account | where AccountName == “<account>”
Track Events By ProcessGUID | where ProcessGUID == “<guid>”
Track Events By ParentProcessGUID | where ParentProcessGUID == “<parentGUID>”
SHA256 (Main Process Executable) | where ImageSHA256 == “<SHA256>”
Backup - Network Share(s) Disabled | where ImageName in (“cmd.exe”, “net.exe”, “net1.exe”) and CommandLine has_any (“memserv”, “mssql”, “pg-ctl”, “sql”)
Backup - Shadow Volume Delete | where ImageName == "vssadmin.exe" and CommandLine has tolower("Delete", "Shadows", "//All//Quiet")
Find Registry Processes on an Endpoint | where EndpointID == “d19ijuvdffd3f2” and ImageName has_any (“reg.exe”, “regsvr32.exe”)
Persistence (Basic) | where CommandLine has_any (“\CurrentVersion\Run”, “\CurrentVersion\Group Policy\Scripts”)
PowerShell Events (Basic) | where ImageName has_any (“powershell”, “psexec”)
PowerShell Hidden/Encoded Events | where ImageName has “powershell” and CommandLine has_any (“-e”, “-ec”, “-en”, -”enc”, “-enco”“hidden”, “http”, “iex”, “SilentlyContinue”, “Start-Process -WindowStyle Hidden”)
System Reconnaissance (Basic) | where ImageName == “cmd.exe” and CommandLine has_any (“systeminfo”, “ipconfig”, “netstat”, “arp -a”)
System Reconnaissance (net) | where CommandLine has “net” and CommandLine has_any (“computer”, “config”, “group”, “localgroup”, “user”)
System Reconnaissance (netsh) | where CommandLine has “netsh” and CommandLine has_any (“add”, “advfirewall”, “alias”, “delete”, “exec”, “firewall”)
WevUtil Extraction | where ImageName == "wevtutil.exe" and CommandLine has_any("TokenElevationTypeFull", "cl", "qe")

Nested Keyword Queries

When accessing nested items, you are parsing through the raw JSON data that is not immediately filtered through to the basic queries. This includes things like process start/end, libraries loaded, threads started, network traffic details, etc.

Here is an example query to show TCP/IP traffic:

let TCP/IP traffic =
ProdV1
| mv-expand Action = parse_json(Events)
| extend EventName = tostring(Action.EventName)
, ProcessID = tostring(Action.ProcessID)
, SourceAddress = tostring(Action.SourceAddress)
, SourcePort = tostring(Action.SourcePort)
, DestAddress = tostring(Action.DestAddress
, DestPort = tostring(Action.DestPort)
| where EventName startswith "TcpIp/Connect"
| project ProcessID, ImageName, EventName, SourceAddress, SourcePort, DestAddress, DestPort

This will give the Process ID, Process Name, and addresses related.

This is not a packet capture.

Reformat has no queries to the right.

When creating queries with these fields, keep in mind that some records will be blank or missing, depending on the context of the JSON log and what was received. In the above example, one could add fields like ‘URI’, ‘URL’, ‘Verb’, ‘RequestHeaders’, and ‘ResponseHeaders’. However, these fields return empty entries unless looking at WinHTTP/Log and WinInet/Log events (adding ‘and where EventName endswith “Log” after “TcpIp/Connect”’).

Name Query
List Nested Event Types | distinct EventNames
Registry Key Creation

| where EventName == “Registry/Create”

| project EventName, KeyValue

Registry Value Write

| where EventName == “Registry/SetValue”

| project EventName, KeyName, ValueName, Data

File Write

| where EventName == “FileIo/Write”

| project EventName, FilePath, FileObject

File Delete

| where EventName == “FileIo/FileDelete”

| project EventName, FilePath

File Rename

| where EventName == “FileIo/FileRename”

| project EventName, OldFilePath, NewFilePath

Remote Thread Creation

| where EventName == “Thread/RemoteThread”

| project EventName, InjectorProcessID, ThreadID

API Library Load | where EventName == “Image/Load” and FileName == “ntdll.dll”
DotNet Use | where EventName == “DOTNET/ModuleLoad”
PowerShell Script | where EventName == “Powershell/Script Execution”
PowerShell Commands | where EventName == “Powershell/Command Execution”
HTTP Log

| where EventName == “WinHTTP/Log”

| project EventName, URI, Verb

INET Log

| where EventName == “WinInet/Log”

| project EventName, URL, Verb