Hunter Blue's day started like everyday with researching the cyber security news for new Threat Huntings tasks to find malicious traces on customer datalakes.
You should investigate the initial Entry and Execution to search through the logs with these IoCs / IoAs to find the right artifacts for Threat Hunting.
1.1) Information Links and Research
2.) Indicators of Compromise
Indicators of compromise
Type
Value
Notes / usage
SHA256
SHA256
SHA256
SHA256
URL (webhook)
Filename / Workflow
GitHub repo name
Tool abuse indicator
2.1) Executions from Threat Actor - Steps
worm executes during the post-install phase
2.2) Indicators of Compromise - Executions
3.) Initial Access
4.) Finding through Threat Hunting
We hunted through the Datalake logs in the whole infrastructure and yes you guess it right we found a malicious execution not related to legit admin tasks
5.) Mitigation
6.) Detection and Hunting
6.1) Sigma Rules
6.2) Linux Commandline Hunting
6.3) Hunting Queries Microsoft Defender XDR
6.4) Hunting Queries Palo Cortex XDR
6.5) Hunting Queries Tanium EDR
6.6) Hunting Queries Crowdstrike XDR
7.) Conclusion and Learning for a Hunter Blue
The NPM incident reveals Supply chain attacks are increasing in frequency. It is more important than ever to monitor third-party packages for malicious activity. Since malicious code can be hidden in many different ways, using runtime threat detection is critical to catching these attack
its definitely necessary to check during Hunting or Initial Triage how Malware was staged
-> showcasing how fruitful Compromise Assessment Hunting and Time Line Analysis can be and should be used in such cases -> it is essential.
##
###HUNT03 - MAL-Domain01-Hunting
#######// Description: This query will check for Domain, DNS, Queryevents, Network Events, URL Infos in Mails and URL Click Events requesting suspicious Domains.
let domainList = dynamic(["webhook.site"]);
union
(
IdentityQueryEvents
| where QueryTarget has_any(domainList)
| project Timestamp, Domain = QueryTarget, SourceTable = "IdentityQueryEvents"
),
(
DeviceNetworkEvents
| where RemoteUrl has_any(domainList) or LocalIP has_any(domainList) or RemoteIP has_any(domainList)
| project Timestamp,DeviceName, InitiatingProcessAccountName ,Domain = RemoteUrl, SourceTable = "DeviceNetworkEvents", InitiatingProcessCommandLine, InitiatingProcessFileName, InitiatingProcessParentFileName
),
(
DeviceNetworkInfo
| extend DnsAddresses = parse_json(DnsAddresses), ConnectedNetworks = parse_json(ConnectedNetworks)
| mv-expand DnsAddresses, ConnectedNetworks
| where DnsAddresses has_any(domainList) or ConnectedNetworks.Name has_any(domainList)
| project Timestamp, Domain = coalesce(DnsAddresses, ConnectedNetworks.Name), SourceTable = "DeviceNetworkInfo"
),
(
EmailUrlInfo
| where UrlDomain has_any(domainList)
| project Timestamp, Domain = UrlDomain, SourceTable = "EmailUrlInfo"
),
(
UrlClickEvents
| where Url has_any(domainList)
| project Timestamp, Domain = Url, SourceTable = "UrlClickEvents"
)
###CIM-HUNT04 - C2 communication
//Find devices that may have communicated with
let domainList = dynamic(["webhook.site"]);
union
(
DnsEvents
| where QueryType has_any(domainList) or Name has_any(domainList)
//or QueryType matches regex @"^.*\.devtunnels\.ms$" or Name matches regex @"^.*\.devtunnels\.ms$"
| project TimeGenerated, Domain = QueryType, SourceTable = "DnsEvents"
),
(
IdentityQueryEvents
| where QueryTarget has_any(domainList)
//or QueryType matches regex @"^.*\.devtunnels\.ms$"
| project Timestamp, Domain = QueryTarget, SourceTable = "IdentityQueryEvents"
),
(
DeviceNetworkEvents
| where RemoteUrl has_any(domainList)
//or RemoteUrl matches regex @"^.*\.devtunnels\.ms$"
| project Timestamp, Domain = RemoteUrl, SourceTable = "DeviceNetworkEvents"
),
(
DeviceNetworkInfo
| extend DnsAddresses = parse_json(DnsAddresses), ConnectedNetworks = parse_json(ConnectedNetworks)
| mv-expand DnsAddresses, ConnectedNetworks
| where DnsAddresses has_any(domainList) or ConnectedNetworks.Name has_any(domainList)
//or DnsAddresses matches regex @"^.*\.devtunnels\.ms$" or ConnectedNetworks .Name matches regex @"^.*\.devtunnels\.ms$"
| project Timestamp, Domain = coalesce(DnsAddresses, ConnectedNetworks.Name), SourceTable = "DeviceNetworkInfo"
),
(
VMConnection
| extend RemoteDnsQuestions = parse_json(RemoteDnsQuestions), RemoteDnsCanonicalNames = parse_json(RemoteDnsCanonicalNames)
| mv-expand RemoteDnsQuestions, RemoteDnsCanonicalNames
| where RemoteDnsQuestions has_any(domainList) or RemoteDnsCanonicalNames has_any(domainList)
//or RemoteDnsQuestions matches regex @"^.*\.devtunnels\.ms$" or RemoteDnsCanonicalNames matches regex @"^.*\.devtunnels\.ms$"
| project TimeGenerated, Domain = coalesce(RemoteDnsQuestions, RemoteDnsCanonicalNames), SourceTable = "VMConnection"
),
(
W3CIISLog
| where csHost has_any(domainList) or csReferer has_any(domainList)
//or csHost matches regex @"^.*\.devtunnels\.ms$" or csReferer matches regex @"^.*\.devtunnels\.ms$"
| project TimeGenerated, Domain = coalesce(csHost, csReferer), SourceTable = "W3CIISLog"
),
(
EmailUrlInfo
| where UrlDomain has_any(domainList)
//or UrlDomain matches regex @"^.*\.devtunnels\.ms$"
| project Timestamp, Domain = UrlDomain, SourceTable = "EmailUrlInfo"
),
(
UrlClickEvents
| where Url has_any(domainList)
//or Url matches regex @"^.*\.devtunnels\.ms$"
| project Timestamp, Domain = Url, SourceTable = "UrlClickEvents"
)
| order by TimeGenerated desc
###CIM-HUNT05 - Files with known malicious hashes (file events)
DeviceFileEvents
| where Timestamp > ago(30d)
| where SHA256 in (
"46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09",
"b74caeaa75e077c99f7d44f46daaf9796a3be43ecf24f2a1fd381844669da777",
"dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c",
"4b2399646573bb737c4969563303d8ee2e9ddbd1b271f1ca9e35ea78062538db"
)
| project Timestamp, DeviceName, InitiatingProcessAccountName, action_file_name=FileName, FolderPath, SHA256
| order by Timestamp desc
###CIM-HUNT06 - Detect downloads or network requests to the webhook.site IOC
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl has "webhook.site" and RemoteUrl has "bb8ca5f6-4175-45d2-b042-fc9ebb8170b7"
| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP
| order by Timestamp desc
###CIM-HUNT07 - Detection of the malicious workflow filename (shai-hulud-workflow.yml)
DeviceFileEvents
| where Timestamp > ago(30d)
| where FileName == "shai-hulud-workflow.yml"
| project Timestamp, DeviceName, InitiatingProcessAccountName, FileName, FolderPath, InitiatingProcessCommandLine
| order by Timestamp desc
###CIM-HUNT08 - Hunt for trufflehog use (process telemetry)
DeviceProcessEvents
| where Timestamp > ago(30d)
| where ProcessCommandLine has_cs "trufflehog" or FileName has_cs "trufflehog"
| project Timestamp, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
| order by Timestamp desc
###CIM-HUNT09 - Hunt for trufflehog use (process telemetry)
DeviceProcessEvents
| where Timestamp > ago(30d)
| where ProcessCommandLine has_all ("chmod", "+x", "trufflehog", "tinycolor", "node_modules", "node") or
ProcessCommandLine has_all ("chmod", "+x", "trufflehog") or
ProcessCommandLine has_all ("node", "bundle.js", "sh -c")
| project Timestamp, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
| order by Timestamp desc
###HUNT01 - Description: Reports indicate only Linux+Mac is targeted due to an os.platform() check, ensure agent coverage on these devices
dataset = endpoints
| filter endpoint_status in (ENUM.CONNECTED, ENUM.DISCONNECTED)
| comp count() by platform
###HUNT02 - Description: Check for connections to any webhook.site domains in raw NGFW URL logs. Optional filter for specific URI observed in use by threat actor.
dataset = panw_ngfw_url_raw
| filter lowercase(url_domain) contains "webhook.site"
| alter susp_uri = if(uri contains "bb8ca5f6-4175-45d2-b042-fc9ebb8170b7")
// Optional filter:
// | filter susp_uri = true
| fields url_domain, uri, susp_uri, *
###HUNT03 - Description: Check for connections to any webhook.site domains in XDR telemetry. Optional filter for specific URI observed in use by threat actor.
dataset = xdr_data
| filter event_type = STORY
| filter lowercase(dst_action_external_hostname) contains "webhook.site" or lowercase(dns_query_name) contains "webhook.site"
//| alter susp_uri = if(uri contains "bb8ca5f6-4175-45d2-b042-fc9ebb8170b7")
//| fields agent_hostname, dst_action_external_hostname, dns_query_name, action_external_hostname, action_network_dns_domains
###HUNT04 - Description: Detect malicious YAML file
dataset = xdr_data
| filter event_type = FILE and action_file_name = "shai-hulud-workflow.yml" and agent_os_type in (ENUM.AGENT_OS_MAC, ENUM.AGENT_OS_LINUX)
| fields agent_hostname, actor_effective_username, action_file_name, action_file_path, actor_process_image_name, actor_process_command_line
###HUNT05 - Detects Trufflehog usage. Legitimate tool abused by threat actor for secrets discovery. False positives may occur if there is legitimate use.
dataset = xdr_data
| filter event_type = PROCESS and lowercase(action_process_image_command_line) contains "trufflehog"
| fields agent_hostname, actor_effective_username, actor_process_command_line, action_process_image_command_line
###HUNT06 - Description: Detect malicious bundle.js file
config case_sensitive = false
| dataset = xdr_data
| filter event_type = FILE and action_file_sha256 = "46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09"
| fields agent_hostname, action_file_name, action_file_path, event_type, event_sub_type, actor_process_image_name, actor_process_command_line
dataset = xdr_data
| filter event_type = FILE and action_file_name = "bundle.js" and agent_os_type in (ENUM.AGENT_OS_MAC, ENUM.AGENT_OS_LINUX)
| fields agent_hostname, actor_effective_username, action_file_name, action_file_path, actor_process_image_name, actor_process_command_line
###HUNT07 - VER2-Compromised Packages
// Hunt for recently compromised npm packages: https://www.ox.security/blog/npm-packages-compromised/ & https://www.aikido.dev/blog/s1ngularity-nx-attackers-strike-again
dataset = xdr_data
//| filter event_type = PROCESS and lowercase(action_process_image_command_line) in
| filter event_type = FILE and lowercase(action_file_path) in
()
###HUNT06 - Description: Detect malicious bundle.js file, trufflehog
Get Trace Executed Processes[unlimited,1758288047852|1758291646852,0,0,99,0,"","",".*(trufflehog).*","","",""] from all machines
Get Trace Executed Processes[unlimited,1758288047852|1758291646852,0,0,99,0,"","",".*(bundle.js).*","","",""] from all machines
Get Trace Executed Processes[unlimited,1758288047852|1758291646852,0,0,99,0,"","",".*(bundle\.js|trufflehog|tinycolor|node\_modules|chmod|sh -c).*","","",""] from all machines
###HUNT03 - MAL-Domain01-Hunting - Webhook Site
#######// Description: This query will check for Domain, DNS, Queryevents, Network Events, URL Infos in Mails and URL Click Events requesting suspicious Domains.
Get Trace DNS Queries[unlimited,1758287446087|1758291045087,1,0,100,0,"","",".*(webhook.site).*","",""] from all machines