mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
119 lines
6.4 KiB
YAML
119 lines
6.4 KiB
YAML
name: Hunting for Log4Shell
|
|
id: 158b68fa-5d1a-11ec-aac8-acde48001122
|
|
version: 1
|
|
date: '2021-12-14'
|
|
author: Michael Haag, Splunk
|
|
type: Hunting
|
|
datamodel:
|
|
- Web
|
|
description: 'The following hunting query assists with quickly assessing CVE-2021-44228,
|
|
or Log4Shell, activity mapped to the Web Datamodel. This is a combination query
|
|
attempting to identify, score and dashboard. Because the Log4Shell vulnerability
|
|
requires the string to be in the logs, this will work to identify the activity anywhere
|
|
in the HTTP headers using _raw. Modify the first line to use the same pattern matching
|
|
against other log sources. Scoring is based on a simple rubric of 0-5. 5 being the
|
|
best match, and less than 5 meant to identify additional patterns that will equate
|
|
to a higher total score. \
|
|
|
|
The first jndi match identifies the standard pattern of `{jndi:` \
|
|
|
|
jndi_fastmatch is meant to identify any jndi in the logs. The score is set low and
|
|
is meant to be the "base" score used later. \
|
|
|
|
jndi_proto is a protocol match that identifies `jndi` and one of `ldap, ldaps, rmi,
|
|
dns, nis, iiop, corba, nds, http, https.` \
|
|
|
|
all_match is a very well written regex by https://gist.github.com/Schvenn that identifies
|
|
nearly all patterns of this attack behavior. \
|
|
|
|
env works to identify environment variables in the header, meant to capture `AWS_ACCESS_KEY_ID`,
|
|
`AWS_SECRET_ACCESS_KEY` and `env`. \
|
|
|
|
uri_detect is string match looking for the common uri paths currently being scanned/abused
|
|
in the wild. \
|
|
|
|
keywords matches on enumerated values that, like `$ctx:loginId`, that may be found
|
|
in the header used by the adversary. \
|
|
|
|
lookup matching is meant to catch some basic obfuscation that has been identified
|
|
using upper, lower and date. \
|
|
|
|
Scoring will then occur based on any findings. The base score is meant to be 2 ,
|
|
created by jndi_fastmatch. Everything else is meant to increase that score. \
|
|
|
|
Finally, a simple table is created to show the scoring and the _raw field. Sort
|
|
based on score or columns of interest.'
|
|
search: '| from datamodel Web.Web | eval jndi=if(match(_raw, "(\{|%7B)[jJnNdDiI]{4}:"),4,0)
|
|
| eval jndi_fastmatch=if(match(_raw, "[jJnNdDiI]{4}"),2,0) | eval jndi_proto=if(match(_raw,"(?i)jndi:(ldap[s]?|rmi|dns|nis|iiop|corba|nds|http|https):"),5,0)
|
|
| eval all_match = if(match(_raw, "(?i)(%(25){0,}20|\s)*(%(25){0,}24|\$)(%(25){0,}20|\s)*(%(25){0,}7B|{)(%(25){0,}20|\s)*(%(25){0,}(6A|4A)|J)(%(25){0,}(6E|4E)|N)(%(25){0,}(64|44)|D)(%(25){0,}(69|49)|I)(%(25){0,}20|\s)*(%(25){0,}3A|:)[\w\%]+(%(25){1,}3A|:)(%(25){1,}2F|\/)[^\n]+"),5,0)
|
|
| eval env_var = if(match(_raw, "env:") OR match(_raw, "env:AWS_ACCESS_KEY_ID")
|
|
OR match(_raw, "env:AWS_SECRET_ACCESS_KEY"),5,0) | eval uridetect = if(match(_raw,
|
|
"(?i)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"),4,0)
|
|
| eval keywords = if(match(_raw,"(?i)\$\{ctx\:loginId\}|\$\{map\:type\}|\$\{filename\}|\$\{date\:MM-dd-yyyy\}|\$\{docker\:containerId\}|\$\{docker\:containerName\}|\$\{docker\:imageName\}|\$\{env\:USER\}|\$\{event\:Marker\}|\$\{mdc\:UserId\}|\$\{java\:runtime\}|\$\{java\:vm\}|\$\{java\:os\}|\$\{jndi\:logging/context-name\}|\$\{hostName\}|\$\{docker\:containerId\}|\$\{k8s\:accountName\}|\$\{k8s\:clusterName\}|\$\{k8s\:containerId\}|\$\{k8s\:containerName\}|\$\{k8s\:host\}|\$\{k8s\:labels.app\}|\$\{k8s\:labels.podTemplateHash\}|\$\{k8s\:masterUrl\}|\$\{k8s\:namespaceId\}|\$\{k8s\:namespaceName\}|\$\{k8s\:podId\}|\$\{k8s\:podIp\}|\$\{k8s\:podName\}|\$\{k8s\:imageId\}|\$\{k8s\:imageName\}|\$\{log4j\:configLocation\}|\$\{log4j\:configParentLocation\}|\$\{spring\:spring.application.name\}|\$\{main\:myString\}|\$\{main\:0\}|\$\{main\:1\}|\$\{main\:2\}|\$\{main\:3\}|\$\{main\:4\}|\$\{main\:bar\}|\$\{name\}|\$\{marker\}|\$\{marker\:name\}|\$\{spring\:profiles.active[0]|\$\{sys\:logPath\}|\$\{web\:rootDir\}|\$\{sys\:user.name\}"),4,0)
|
|
| eval obf = if(match(_raw, "(\$|%24)[^ /]*({|%7b)[^ /]*(j|%6a)[^ /]*(n|%6e)[^ /]*(d|%64)[^
|
|
/]*(i|%69)[^ /]*(:|%3a)[^ /]*(:|%3a)[^ /]*(/|%2f)"),5,0) | eval lookups = if(match(_raw,
|
|
"(?i)({|%7b)(main|sys|k8s|spring|lower|upper|env|date|sd)"),4,0) | addtotals fieldname=Score,
|
|
jndi, jndi_proto, env_var, uridetect, all_match, jndi_fastmatch, keywords, obf,
|
|
lookups | where Score > 2 | stats values(Score) by jndi, jndi_proto, env_var, uridetect,
|
|
all_match, jndi_fastmatch, keywords, lookups, obf, _raw | `hunting_for_log4shell_filter`'
|
|
how_to_implement: Out of the box, the Web datamodel is required to be pre-filled.
|
|
However, tested was performed against raw httpd access logs. Change the first line
|
|
to any dataset to pass the regex's against.
|
|
known_false_positives: It is highly possible you will find false positives, however,
|
|
the base score is set to 2 for _any_ jndi found in raw logs. tune and change as
|
|
needed, include any filtering.
|
|
references:
|
|
- https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72
|
|
- https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b#gistcomment-3994449
|
|
- https://regex101.com/r/OSrm0q/1/
|
|
- https://github.com/Neo23x0/signature-base/blob/master/yara/expl_log4j_cve_2021_44228.yar
|
|
- https://news.sophos.com/en-us/2021/12/12/log4shell-hell-anatomy-of-an-exploit-outbreak/
|
|
- https://gist.github.com/MHaggis/1899b8554f38c8692a9fb0ceba60b44c
|
|
- https://twitter.com/sasi2103/status/1469764719850442760?s=20
|
|
tags:
|
|
analytic_story:
|
|
- Log4Shell CVE-2021-44228
|
|
- CISA AA22-320A
|
|
asset_type: Web Server
|
|
confidence: 50
|
|
context:
|
|
- Scope:Network
|
|
cve:
|
|
- CVE-2021-44228
|
|
dataset:
|
|
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/log4shell-nginx.log
|
|
impact: 80
|
|
kill_chain_phases:
|
|
- Exploitation
|
|
message: Hunting for Log4Shell exploitation has occurred.
|
|
mitre_attack_id:
|
|
- T1190
|
|
observable:
|
|
- name: dest
|
|
type: Hostname
|
|
role:
|
|
- Victim
|
|
- name: http_method
|
|
type: Other
|
|
role:
|
|
- Other
|
|
- name: src
|
|
type: Other
|
|
role:
|
|
- Other
|
|
product:
|
|
- Splunk Enterprise
|
|
- Splunk Enterprise Security
|
|
- Splunk Cloud
|
|
required_fields:
|
|
- _time
|
|
- Web.http_method
|
|
- Web.url
|
|
- Web.url_length
|
|
- Web.src
|
|
- Web.dest
|
|
- Web.http_user_agent
|
|
- _raw
|
|
risk_score: 40
|
|
security_domain: network
|