ID | Technique | Tactic |
---|---|---|
T1190 | Exploit Public-Facing Application | Initial Access |
T1133 | External Remote Services | Initial Access |
Detection: Hunting for Log4Shell
Description
The following analytic detects potential exploitation attempts of the Log4Shell vulnerability (CVE-2021-44228) by analyzing HTTP headers for specific patterns. It leverages the Web Datamodel and evaluates various indicators such as the presence of {jndi:
, environment variables, and common URI paths. This detection is significant as Log4Shell allows remote code execution, posing a severe threat to systems. If confirmed malicious, attackers could gain unauthorized access, execute arbitrary code, and potentially compromise sensitive data, leading to extensive damage and data breaches.
Search
1
2| from datamodel Web.Web
3| eval jndi=if(match(_raw, "(\{
4|%7B)[jJnNdDiI]{4}:"),4,0)
5| eval jndi_fastmatch=if(match(_raw, "[jJnNdDiI]{4}"),2,0)
6| eval jndi_proto=if(match(_raw,"(?i)jndi:(ldap[s]?
7|rmi
8|dns
9|nis
10|iiop
11|corba
12|nds
13|http
14|https):"),5,0)
15| eval all_match = if(match(_raw, "(?i)(%(25){0,}20
16|\s)*(%(25){0,}24
17|\$)(%(25){0,}20
18|\s)*(%(25){0,}7B
19|{)(%(25){0,}20
20|\s)*(%(25){0,}(6A
21|4A)
22|J)(%(25){0,}(6E
23|4E)
24|N)(%(25){0,}(64
25|44)
26|D)(%(25){0,}(69
27|49)
28|I)(%(25){0,}20
29|\s)*(%(25){0,}3A
30|:)[\w\%]+(%(25){1,}3A
31|:)(%(25){1,}2F
32|\/)[^\n]+"),5,0)
33| 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)
34| eval uridetect = if(match(_raw, "(?i)Basic\/Command\/Base64
35|Basic\/ReverseShell
36|Basic\/TomcatMemshell
37|Basic\/JBossMemshell
38|Basic\/WebsphereMemshell
39|Basic\/SpringMemshell
40|Basic\/Command
41|Deserialization\/CommonsCollectionsK
42|Deserialization\/CommonsBeanutils
43|Deserialization\/Jre8u20\/TomcatMemshell
44|Deserialization\/CVE_2020_2555\/WeblogicMemshell
45|TomcatBypass
46|GroovyBypass
47|WebsphereBypass"),4,0)
48| eval keywords = if(match(_raw,"(?i)\$\{ctx\:loginId\}
49|\$\{map\:type\}
50|\$\{filename\}
51|\$\{date\:MM-dd-yyyy\}
52|\$\{docker\:containerId\}
53|\$\{docker\:containerName\}
54|\$\{docker\:imageName\}
55|\$\{env\:USER\}
56|\$\{event\:Marker\}
57|\$\{mdc\:UserId\}
58|\$\{java\:runtime\}
59|\$\{java\:vm\}
60|\$\{java\:os\}
61|\$\{jndi\:logging/context-name\}
62|\$\{hostName\}
63|\$\{docker\:containerId\}
64|\$\{k8s\:accountName\}
65|\$\{k8s\:clusterName\}
66|\$\{k8s\:containerId\}
67|\$\{k8s\:containerName\}
68|\$\{k8s\:host\}
69|\$\{k8s\:labels.app\}
70|\$\{k8s\:labels.podTemplateHash\}
71|\$\{k8s\:masterUrl\}
72|\$\{k8s\:namespaceId\}
73|\$\{k8s\:namespaceName\}
74|\$\{k8s\:podId\}
75|\$\{k8s\:podIp\}
76|\$\{k8s\:podName\}
77|\$\{k8s\:imageId\}
78|\$\{k8s\:imageName\}
79|\$\{log4j\:configLocation\}
80|\$\{log4j\:configParentLocation\}
81|\$\{spring\:spring.application.name\}
82|\$\{main\:myString\}
83|\$\{main\:0\}
84|\$\{main\:1\}
85|\$\{main\:2\}
86|\$\{main\:3\}
87|\$\{main\:4\}
88|\$\{main\:bar\}
89|\$\{name\}
90|\$\{marker\}
91|\$\{marker\:name\}
92|\$\{spring\:profiles.active[0]
93|\$\{sys\:logPath\}
94|\$\{web\:rootDir\}
95|\$\{sys\:user.name\}"),4,0)
96| eval obf = if(match(_raw, "(\$
97|%24)[^ /]*({
98|%7b)[^ /]*(j
99|%6a)[^ /]*(n
100|%6e)[^ /]*(d
101|%64)[^ /]*(i
102|%69)[^ /]*(:
103|%3a)[^ /]*(:
104|%3a)[^ /]*(/
105|%2f)"),5,0)
106| eval lookups = if(match(_raw, "(?i)({
107|%7b)(main
108|sys
109|k8s
110|spring
111|lower
112|upper
113|env
114|date
115|sd)"),4,0)
116| addtotals fieldname=Score, jndi, jndi_proto, env_var, uridetect, all_match, jndi_fastmatch, keywords, obf, lookups
117| where Score > 2
118| stats values(Score) by jndi, jndi_proto, env_var, uridetect, all_match, jndi_fastmatch, keywords, lookups, obf, dest, src, http_method, _raw
119| `hunting_for_log4shell_filter`
Data Source
Name | Platform | Sourcetype | Source | Supported App |
---|---|---|---|---|
Nginx Access | N/A | 'nginx:plus:kv' |
'/var/log/nginx/access.log' |
N/A |
Macros Used
Name | Value |
---|
| hunting_for_log4shell_filter | search *
|
hunting_for_log4shell_filter
is an empty macro by default. It allows the user to filter out any results (false positives) without editing the SPL.
Annotations
Default Configuration
This detection is configured by default in Splunk Enterprise Security to run with the following settings:
Setting | Value |
---|---|
Disabled | true |
Cron Schedule | 0 * * * * |
Earliest Time | -70m@m |
Latest Time | -10m@m |
Schedule Window | auto |
Creates Risk Event | False |
Implementation
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.
Associated Analytic Story
Risk Based Analytics (RBA)
Risk Message | Risk Score | Impact | Confidence |
---|---|---|---|
Hunting for Log4Shell exploitation has occurred. | 40 | 80 | 50 |
References
-
https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72
-
https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b#gistcomment-3994449
-
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
Detection Testing
Test Type | Status | Dataset | Source | Sourcetype |
---|---|---|---|---|
Validation | ✅ Passing | N/A | N/A | N/A |
Unit | ✅ Passing | Dataset | /var/log/nginx/access.log |
nginx:plus:kv |
Integration | ✅ Passing | Dataset | /var/log/nginx/access.log |
nginx:plus:kv |
Replay any dataset to Splunk Enterprise by using our replay.py
tool or the UI.
Alternatively you can replay a dataset into a Splunk Attack Range
Source: GitHub | Version: 3