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.

  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
Nginx Access N/A 'nginx:plus:kv' '/var/log/nginx/access.log'

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

- MITRE ATT&CK
+ Kill Chain Phases
+ NIST
+ CIS
- Threat Actors
ID Technique Tactic
T1190 Exploit Public-Facing Application Initial Access
T1133 External Remote Services Initial Access
Delivery
Installation
DE.AE
CIS 13

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
This configuration file applies to all detections of type hunting.

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

References

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: 5