Branch was auto-updated.

This commit is contained in:
Bhavin Patel
2021-12-14 18:47:02 -08:00
committed by GitHub
94 changed files with 17853 additions and 171 deletions
+4
View File
@@ -49,3 +49,7 @@ tags:
{% for observable in observables -%}
- {{observable}}
{% endfor -%}
nist:
-
cis20:
-
@@ -33,6 +33,7 @@ tags:
analytic_story:
- Malicious PowerShell
- Ingress Tool Transfer
- Log4Shell CVE-2021-44228
automated_detection_testing: passed
confidence: 70
context:
@@ -66,6 +67,8 @@ tags:
type: Process
role:
- Child Process
cve:
- CVE-2021-44228
product:
- Splunk Enterprise
- Splunk Enterprise Security
@@ -1,32 +1,36 @@
name: CMD Carry Out String Command Parameter
id: 54a6ed00-3256-11ec-b031-acde48001122
version: 1
date: '2021-10-21'
author: Teoderick Contreras, Splunk, Bhavin Patel, Splunk
version: 2
date: '2021-12-13'
author: Teoderick Contreras, Bhavin Patel, Splunk
type: Hunting
datamodel:
- Endpoint
description: This search looks for command-line arguments where `cmd.exe /c` is used
to execute a program. This technique is commonly seen in adversaries and malware
to execute batch command using different shell like powershell or different process
other than cmd.exe. This is a good hunting query for suspicious commandline made
by a script or relative process execute it.
description: 'The following analytic identifies command-line arguments where `cmd.exe /c` is used
to execute a program. `cmd /c` is used to run commands in MS-DOS and terminate after
command or process completion. This technique is commonly seen in adversaries and malware
to execute batch command using different shell like PowerShell or different process
other than `cmd.exe`. This is a good hunting query for suspicious command-line made
by a script or relative process execute it.'
search: '| tstats `security_content_summariesonly` min(_time) as firstTime max(_time)
as lastTime from datamodel=Endpoint.Processes where `process_cmd` AND Processes.process="*
/c *" by Processes.dest Processes.user Processes.parent_process Processes.process_name
Processes.original_file_name Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
| `cmd_carry_out_string_command_parameter_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
logs with the process name, parent process, and command-line executions from your
endpoints. If you are using Sysmon, you must have at least version 6.0.4 of the
Sysmon TA.
known_false_positives: unknown
how_to_implement: To successfully implement this search you need to be ingesting information
on process that include the name of the process responsible for the changes from
your endpoints into the `Endpoint` datamodel in the `Processes` node. In addition,
confirm the latest CIM App 4.20 or higher is installed and the latest TA for the
endpoint product.
known_false_positives: False positives may be high based on legitimate scripted code in any environment.
Filter as needed.
references:
- https://thedfirreport.com/2021/10/18/icedid-to-xinglocker-ransomware-in-24-hours/
tags:
analytic_story:
- IcedID
- Log4Shell CVE-2021-44228
automated_detection_testing: passed
confidence: 50
context:
@@ -37,7 +41,7 @@ tags:
impact: 60
kill_chain_phases:
- Exploitation
message: $process_name$ with commandline $process$ in $dest$
message: An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ by user $user$ attempting spawn a new process.
mitre_attack_id:
- T1059.003
- T1059
@@ -50,6 +54,8 @@ tags:
type: User
role:
- Victim
cve:
- CVE-2021-44228
product:
- Splunk Enterprise
- Splunk Enterprise Security
@@ -0,0 +1,77 @@
name: Curl Download and Bash Execution
id: 900bc324-59f3-11ec-9fb4-acde48001122
version: 1
date: '2021-12-10'
author: Michael Haag, Splunk
type: TTP
datamodel:
- Endpoint
description: The following analytic identifies the use of curl on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
search: '| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time)
as lastTime from datamodel=Endpoint.Processes where Processes.process_name=curl
(Processes.process="*-s *") OR (Processes.process="*|*" AND Processes.process="*bash*") by Processes.dest Processes.user Processes.parent_process_name Processes.process_name
Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `curl_download_and_bash_execution_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
logs with the process name, parent process, and command-line executions from your
endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly.
If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required.
Add parent process name (Processes.parent_process_name) as needed to filter.
known_false_positives: False positives should be limited, however filtering may be required.
references:
- https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java
- https://www.lunasec.io/docs/blog/log4j-zero-day/
- https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890
tags:
analytic_story:
- Ingress Tool Transfer
- Log4Shell CVE-2021-44228
dataset:
- "https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log"
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1105
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- Processes.dest
- Processes.user
- Processes.parent_process_name #parent process name
- Processes.parent_process #parent cmdline
- Processes.process_name #process name
- Processes.process #process cmdline
- Processes.process_id
- Processes.parent_process_path
- Processes.process_path
- Processes.parent_process_id
security_domain: endpoint
impact: 80
confidence: 100
# (impact * confidence)/100
risk_score: 80
context:
- Source:Endpoint
- Stage:Defense Evasion
message: An instance of $process_name$ was identified on endpoint $dest$ attempting to download a remote file and run it with bash.
observable:
- name: user
type: User
role:
- Victim
- name: dest
type: Hostname
role:
- Victim
- name: process_name
type: Process
role:
- Child Process
cve:
- CVE-2021-44228
@@ -0,0 +1,118 @@
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,
"date:") OR match(_raw, "upper:") OR match(_raw, "lower:"),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
asset_type: Web Server
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/log4shell-nginx.log
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
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
security_domain: network
impact: 80
confidence: 50
risk_score: 40
context:
- Source:network
message: Hunting for Log4Shell exploitation has occurred.
observable:
- name: dest
type: Hostname
role:
- Victim
- name: http_method
type: Other
role:
- other
- name: src
type: Other
role:
- other
cve:
- CVE-2021-44228
automated_detection_testing: passed
@@ -0,0 +1,69 @@
name: Java Class File download by Java User Agent
id: 8281ce42-5c50-11ec-82d2-acde48001122
version: 1
date: '2021-12-13'
author: Michael Haag, Splunk
type: TTP
datamodel:
- Web
description: The following analytic identifies a Java user agent performing a GET
request for a .class file from the remote site. This is potentially indicative of
exploitation of the Java application and may be related to current event CVE-2021-44228
(Log4Shell).
search: '| tstats count from datamodel=Web where Web.http_user_agent="*Java*" Web.http_method="GET"
Web.url="*.class*" by Web.http_user_agent Web.http_method, Web.url,Web.url_length
Web.src, Web.dest | `drop_dm_object_name("Web")` | `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)` | `java_class_file_download_by_java_user_agent_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
web or proxy logs, or ensure it is being filled by a proxy like device, into the
Web Datamodel. For additional filtering, allow list private IP space or restrict
by known good.
known_false_positives: Filtering may be required in some instances, filter as needed.
references:
- https://arstechnica.com/information-technology/2021/12/as-log4shell-wreaks-havoc-payroll-service-reports-ransomware-attack/
tags:
analytic_story:
- Log4Shell CVE-2021-44228
asset_type: Web Server
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/java.log
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
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
security_domain: network
impact: 80
confidence: 50
risk_score: 40
context:
- Source:network
message: A Java user agent $http_user_agent$ was performing a $http_method$ to retrieve
a remote class file.
observable:
- name: dest
type: Hostname
role:
- Victim
- name: http_user_agent
type: Other
role:
- other
- name: http_method
type: Other
role:
- Other
automated_detection_testing: passed
cve:
- CVE-2021-44228
@@ -29,15 +29,17 @@ how_to_implement: You must be ingesting data that records process activity from
known_false_positives: Legitimate process can have this combination of command-line
options, but it's not common.
references:
- https://regexr.com/663rr
- https://github.com/redcanaryco/AtomicTestHarnesses/blob/master/TestHarnesses/T1059.001_PowerShell/OutPowerShellCommandLineParameter.ps1
- https://ss64.com/ps/powershell.html
- https://twitter.com/M_haggis/status/1440758396534214658?s=20
- https://regexr.com/663rr
- https://github.com/redcanaryco/AtomicTestHarnesses/blob/master/TestHarnesses/T1059.001_PowerShell/OutPowerShellCommandLineParameter.ps1
- https://ss64.com/ps/powershell.html
- https://twitter.com/M_haggis/status/1440758396534214658?s=20
- https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/
tags:
analytic_story:
- Malicious PowerShell
- Possible Backdoor Activity Associated With MUDCARP Espionage Campaigns
- HAFNIUM Group
- Log4Shell CVE-2021-44228
asset_type: Endpoint
automated_detection_testing: passed
cis20:
@@ -91,3 +93,5 @@ tags:
- Processes.dest
risk_score: 81
security_domain: endpoint
cve:
- CVE-2021-44228
@@ -0,0 +1,64 @@
name: Outbound Network Connection from Java Using Default Ports
id: d2c14d28-5c47-11ec-9892-acde48001122
version: 1
date: '2021-12-13'
author: Mauricio Velazco, Splunk
type: TTP
datamodel: []
description: A required step while exploiting the CVE-2021-44228-Log4j vulnerability
is that the victim server will perform outbound connections to attacker-controlled
infrastructure. This is required as part of the JNDI lookup as well as for retrieving
the second stage .class payload. The following analytic identifies the Java process
reaching out to default ports used by the LDAP and RMI protocols. This behavior
could represent successfull exploitation. Note that adversaries can easily decide to use
arbitrary ports for these protocols and potentially bypass this detection.
search: ' `sysmon` EventCode=3 (process_name=java OR process_name=java.exe) (DestinationPort=389
OR DestinationPort=1389 OR DestinationPort = 1099 ) | rename Computer as dest | stats
count min(_time) as firstTime max(_time) as lastTime by dest, process_name, DestinationPort
| `security_content_ctime(firstTime)` | `outbound_network_connection_from_java_using_default_ports_filter`'
how_to_implement: To successfully implement this search you need to be ingesting information
on process that include the name of the process responsible for the changes from
your endpoints into the `Endpoint` datamodel in the `Processes` node.
known_false_positives: Legitimate Java applications may use perform outbound connections
to these ports. Filter as needed
references:
- https://www.lunasec.io/docs/blog/log4j-zero-day/
- https://www.govcert.admin.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/
tags:
analytic_story:
- Log4Shell CVE-2021-44228
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_java/linux-sysmon.log
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
cve:
- CVE-2021-44228
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- process_name
- EventID
- CommandLine
- Computer
- DestinationPort
- DestinationIp
security_domain: endpoint
impact: 90
confidence: 60
risk_score: 54
context:
- Source:Endpoint
- Stage:Execution
message: Java performed outbound connections to default ports of LDAP or RMI on
$dest$
observable:
- name: dest
type: Hostname
role:
- Victim
automated_detection_testing: passed
@@ -0,0 +1,77 @@
name: Wget Download and Bash Execution
id: 35682718-5a85-11ec-b8f7-acde48001122
version: 1
date: '2021-12-11'
author: Michael Haag, Splunk
type: TTP
datamodel:
- Endpoint
description: The following analytic identifies the use of wget on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
search: '| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time)
as lastTime from datamodel=Endpoint.Processes where Processes.process_name=wget
(Processes.process="*-q *" OR Processes.process="*--quiet*" AND Processes.process="*-O- *") OR (Processes.process="*|*" AND Processes.process="*bash*") by Processes.dest Processes.user Processes.parent_process_name Processes.process_name
Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `wget_download_and_bash_execution_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
logs with the process name, parent process, and command-line executions from your
endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly.
If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required.
Add parent process name (Processes.parent_process_name) as needed to filter.
known_false_positives: False positives should be limited, however filtering may be required.
references:
- https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java
- https://www.lunasec.io/docs/blog/log4j-zero-day/
- https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890
tags:
analytic_story:
- Ingress Tool Transfer
- Log4Shell CVE-2021-44228
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1105
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- Processes.dest
- Processes.user
- Processes.parent_process_name #parent process name
- Processes.parent_process #parent cmdline
- Processes.process_name #process name
- Processes.process #process cmdline
- Processes.process_id
- Processes.parent_process_path
- Processes.process_path
- Processes.parent_process_id
security_domain: endpoint
impact: 80
confidence: 100
# (impact * confidence)/100
risk_score: 80
context:
- Source:Endpoint
- Stage:Defense Evasion
message: An instance of $process_name$ was identified on endpoint $dest$ attempting to download a remote file and run it with bash.
observable:
- name: user
type: User
role:
- Victim
- name: dest
type: Hostname
role:
- Victim
- name: process_name
type: Process
role:
- Child Process
cve:
- CVE-2021-44228
@@ -0,0 +1,77 @@
name: Linux Java Spawning Shell
id: 7b09db8a-5c20-11ec-9945-acde48001122
version: 1
date: '2021-12-13'
author: Michael Haag, Splunk
type: TTP
datamodel:
- Endpoint
description: The following analytic identifies the process name of Java, Apache, or Tomcat spawning a Linux shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell).
The shells included in the macro are "sh", "ksh", "zsh", "bash", "dash", "rbash", "fish", "csh', "tcsh', "ion", "eshell".
Upon triage, review parallel processes and command-line arguments to determine legitimacy.
search: '| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time)
as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name=java OR Processes.parent_process_name=apache OR Processes.parent_process_name=tomcat
`linux_shells` by Processes.dest Processes.user Processes.parent_process_name Processes.process_name
Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `linux_java_spawning_shell_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
logs with the process name, parent process, and command-line executions from your
endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly.
Ensure EDR product is mapping OS Linux to the datamodel properly.
Add any additional java process names for your environment to the analytic as needed.
known_false_positives: Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
references:
- https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/
- https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72
tags:
analytic_story:
- Log4Shell CVE-2021-44228
dataset: []
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- Processes.dest
- Processes.user
- Processes.parent_process_name
- Processes.parent_process
- Processes.original_file_name
- Processes.process_name
- Processes.process
- Processes.process_id
- Processes.parent_process_path
- Processes.process_path
- Processes.parent_process_id
security_domain: endpoint
impact: 80
confidence: 50
# (impact * confidence)/100
risk_score: 40
context:
- Source:Endpoint
- Stage:Defense Evasion
message: An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ spawning a Linux shell, potentially indicative of exploitation.
observable:
- name: dest
type: Hostname
role:
- Victim
- name: parent_process_name
type: Parent Process
role:
- Parent Process
- name: process_name
type: Process
role:
- Child Process
cve:
- CVE-2021-44228
@@ -0,0 +1,75 @@
name: Windows Java Spawning Shells
id: 28c81306-5c47-11ec-bfea-acde48001122
version: 1
date: '2021-12-13'
author: Michael Haag, Splunk
type: TTP
datamodel:
- Endpoint
description: The following analytic identifies the process name of java.exe and w3wp.exe spawning a Windows shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell).
The shells included in the macro are "cmd.exe", "powershell.exe".
Upon triage, review parallel processes and command-line arguments to determine legitimacy.
search: '| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time)
as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name=java.exe OR Processes.parent_process_name=w3wp.exe
`windows_shells` by Processes.dest Processes.user Processes.parent_process_name Processes.process_name
Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `windows_java_spawning_shells_filter`'
how_to_implement: To successfully implement this search, you need to be ingesting
logs with the process name, parent process, and command-line executions from your
endpoints. Restrict the analytic to publicly facing endpoints to reduce false positives. Add any additional identified web application process name to the query. Add any further Windows process names to the macro (ex. LOLBins) to further expand this query.
known_false_positives: Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
references:
- https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/
- https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72
tags:
analytic_story:
- Log4Shell CVE-2021-44228
dataset: []
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- Processes.dest
- Processes.user
- Processes.parent_process_name
- Processes.parent_process
- Processes.original_file_name
- Processes.process_name
- Processes.process
- Processes.process_id
- Processes.parent_process_path
- Processes.process_path
- Processes.parent_process_id
security_domain: endpoint
impact: 80
confidence: 50
# (impact * confidence)/100
risk_score: 40
context:
- Source:Endpoint
- Stage:Defense Evasion
message: An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ spawning a Windows shell, potentially indicative of exploitation.
observable:
- name: dest
type: Hostname
role:
- Victim
- name: parent_process_name
type: Parent Process
role:
- Parent Process
- name: process_name
type: Process
role:
- Child Process
cve:
- CVE-2021-44228
@@ -0,0 +1,65 @@
name: Detect Outbound LDAP Traffic
id: c77162d3-f91c-45cc-80c8-22f6v546119f
version: 1
date: '2021-12-13'
author: Bhavin Patel, Johan Bjerke, Splunk
type: Hunting
datamodel:
- Network_Traffic
description: Malicious actors often abuse misconfigured LDAP servers or applications that use the LDAP servers in organizations. Outbound LDAP traffic should not be allowed outbound through your perimeter firewall. This search will help determine if you have any LDAP connections to IP addresses outside of private (RFC1918) address space.
search: '| tstats earliest(_time) as earliest_time latest(_time) as latest_time values(All_Traffic.dest_ip) as dest_ip from datamodel=Network_Traffic.All_Traffic where All_Traffic.dest_port = 389 OR All_Traffic.dest_port = 636 AND NOT (All_Traffic.dest_ip = 10.0.0.0/8 OR All_Traffic.dest_ip=192.168.0.0/16 OR All_Traffic.dest_ip = 172.16.0.0/12) by All_Traffic.src_ip All_Traffic.dest_ip |`drop_dm_object_name("All_Traffic")` | where src_ip != dest_ip | `security_content_ctime(latest_time)` | `security_content_ctime(earliest_time)`
|`detect_outbound_ldap_traffic_filter`'
how_to_implement: 'You must be ingesting Zeek DNS and Zeek Conn data into Splunk. Zeek
data should also be getting ingested in JSON format and should be mapped to the Network Traffic datamodels that are in use for this search.'
known_false_positives: Unknown at this moment. Outbound LDAP traffic should not be allowed outbound through your perimeter firewall. Please check those servers to verify if the activity is legitimate.
references:
- https://www.govcert.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/
tags:
analytic_story:
- Log4Shell CVE-2021-44228
asset_type: Endpoint
cis20:
- CIS 12
- CIS 13
confidence: 80
context:
- Source:Endpoint
- Stage:Initial Access
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_ldap/bro_conn.json
impact: 70
kill_chain_phases:
- Command and Control
- Actions on Objectives
message: An outbound LDAP connection from $src_ip$ in your infrastructure connecting to dest ip $dest_ip$
mitre_attack_id:
- T1190
- T1059
nist:
- PR.DS
- PR.PT
- DE.AE
- DE.CM
observable:
- name: src_ip
type: IP Address
role:
- Victim
- name: dest_ip
type: IP Address
role:
- Attacker
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- _time
- All_Traffic.dest_ip
- All_Traffic.dest_port
- All_Traffic.src_ip
risk_score: 56
security_domain: network
automated_detection_testing: passed
cve:
- CVE-2021-44228
@@ -0,0 +1,89 @@
name: Log4Shell JNDI Payload Injection Attempt
id: c184f12e-5c90-11ec-bf1f-497c9a704a72
version: 1
date: '2021-12-13'
author: Jose Hernandez
type: Anomaly
datamodel:
- Web
description: CVE-2021-44228 Log4Shell payloads can be injected via various methods,
but on of the most common vectors injection is via Web calls. Many of the vulnerable
java web applications that are using log4j have a web component to them are specially
targets of this injection, specifically projects like Apache Struts, Flink, Druid,
and Solr. The exploit is triggered by a LDAP lookup function in the log4j package,
its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against
vulnerable web applications the invocation can be seen in various part of web logs.
Specifically it has been successfully exploited via headers like X-Forwarded-For,
User-Agent, Referer, and X-Api-Version. In this detection we first limit the scope
of our search to the Web Datamodel and use the `| from datamodel` function to benefit
from schema accelerated searching capabilities, mainly because the second part of
the detection is pretty heavy, it runs a regex across all _raw events that looks
for `${jndi:ldap://` pattern across all potential web fields available to the raw
data, like http headers for example. If you see results for this detection, it means
that there was a attempt at a injection, which could be a reconnaissance activity
or a valid expliotation attempt, but this does not exactly mean that the host was
indeed successfully exploited.
search: '| from datamodel Web.Web | regex _raw="[jJnNdDiI]{4}(\:|\%3A|\/|\%2F)\w+(\:\/\/|\%3A\%2F\%2F)(\$\{.*?\}(\.)?)?"
| fillnull | stats count by action, category, dest, dest_port, http_content_type,
http_method, http_referrer, http_user_agent, site, src, url, url_domain, user |
`log4shell_jndi_payload_injection_attempt_filter`'
how_to_implement: This detection requires the Web datamodel to be populated from a
supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
known_false_positives: If there is a vulnerablility scannner looking for log4shells
this will trigger, otherwise likely to have low false positives.
references:
- https://www.lunasec.io/docs/blog/log4j-zero-day/
tags:
analytic_story:
- Log4Shell CVE-2021-44228
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log
kill_chain_phases:
- Reconnaissance
- Exploitation
mitre_attack_id:
- T1190
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- action
- category
- dest
- dest_port
- http_content_type
- http_method
- http_referrer
- http_user_agent
- site
- src
- url
- url_domain
- user
security_domain: threat
impact: 50
confidence: 30
risk_score: 15
context:
- Source:Application Log
- Stage:Execution
message: CVE-2021-44228 Log4Shell triggered for host $dest$
observable:
- name: user
type: User
role:
- Victim
- name: dest
type: Hostname
role:
- Victim
nist:
- DE.CM
cis20:
- CIS 3
- CIS 5
- CIS 16
cve:
- CVE-2021-44228
automated_detection_testing: passed
@@ -0,0 +1,86 @@
name: Log4Shell JNDI Payload Injection with Outbound Connection
id: 69afee44-5c91-11ec-bf1f-497c9a704a72
version: 1
date: '2021-12-13'
author: Jose Hernandez
type: Anomaly
datamodel:
- Network_Traffic
- Web
description: CVE-2021-44228 Log4Shell payloads can be injected via various methods,
but on of the most common vectors injection is via Web calls. Many of the vulnerable
java web applications that are using log4j have a web component to them are specially
targets of this injection, specifically projects like Apache Struts, Flink, Druid,
and Solr. The exploit is triggered by a LDAP lookup function in the log4j package,
its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against
vulnerable web applications the invocation can be seen in various part of web logs.
Specifically it has been successfully exploited via headers like X-Forwarded-For,
User-Agent, Referer, and X-Api-Version. In this detection we match the invocation
function with a network connection to a malicious ip address.
search: '| from datamodel Web.Web | rex field=_raw max_match=0 "[jJnNdDiI]{4}(\:|\%3A|\/|\%2F)(?<proto>\w+)(\:\/\/|\%3A\%2F\%2F)(\$\{.*?\}(\.)?)?(?<affected_host>[a-zA-Z0-9\.\-\_\$]+)"
| join affected_host type=inner [| tstats `security_content_summariesonly` count
min(_time) as firstTime max(_time) as lastTime from datamodel=Network_Traffic.All_Traffic
by All_Traffic.dest | `drop_dm_object_name(All_Traffic)` | `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)` | rename dest AS affected_host] | fillnull
| stats count by action, category, dest, dest_port, http_content_type, http_method,
http_referrer, http_user_agent, site, src, url, url_domain, user | `log4shell_jndi_payload_injection_with_outbound_connection_filter`'
how_to_implement: This detection requires the Web datamodel to be populated from a
supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
known_false_positives: If there is a vulnerablility scannner looking for log4shells
this will trigger, otherwise likely to have low false positives.
references:
- https://www.lunasec.io/docs/blog/log4j-zero-day/
tags:
analytic_story:
- Log4Shell CVE-2021-44228
dataset:
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log
- https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_network_logs/log4j_network_logs.log
kill_chain_phases:
- Exploitation
mitre_attack_id:
- T1190
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
required_fields:
- action
- category
- dest
- dest_port
- http_content_type
- http_method
- http_referrer
- http_user_agent
- site
- src
- url
- url_domain
- user
security_domain: threat
impact: 50
confidence: 30
risk_score: 15
context:
- Source:Application Log
- Stage:Execution
message: CVE-2021-44228 Log4Shell triggered for host $dest$
observable:
- name: user
type: User
role:
- Victim
- name: dest
type: Hostname
role:
- Victim
nist:
- DE.CM
cis20:
- CIS 3
- CIS 5
- CIS 16
cve:
- CVE-2021-44228
automated_detection_testing: passed
+175 -22
View File
@@ -1,6 +1,6 @@
#############
# Automatically generated by generator.py in splunk/security_content
# On Date: 2021-12-02T18:37:19 UTC
# On Date: 2021-12-14T17:20:44 UTC
# Author: Splunk Security Research
# Contact: research@splunk.com
#############
@@ -80,6 +80,21 @@ description = Monitor for activities and techniques associated with Discovery an
narrative = Discovery consists of techniques an adversay uses to gain knowledge about an internal environment or network. These techniques provide adversaries with situational awareness and allows them to have the necessary information before deciding how to act or who/what to target next.\
Once an attacker obtains an initial foothold in an Active Directory environment, she is forced to engage in Discovery techniques in the initial phases of a breach to better understand and navigate the target network. Some examples include but are not limited to enumerating domain users, domain admins, computers, domain controllers, network shares, group policy objects, domain trusts, etc.
[analytic_story://Active Directory Lateral Movement]
category = Adversary Tactics
last_updated = 2021-12-09
version = 3
references = ["https://www.fireeye.com/blog/executive-perspective/2015/08/malware_lateral_move.html", "http://www.irongeek.com/i.php?page=videos/derbycon7/t405-hunting-lateral-movement-for-fun-and-profit-mauricio-velazco"]
maintainers = [{"company": "Mauricio Velazco Splunk", "email": "-", "name": "David Dorsey"}]
spec_version = 3
searches = ["ESCU - Detect Activity Related to Pass the Hash Attacks - Rule", "ESCU - Detect PsExec With accepteula Flag - Rule", "ESCU - Detect Renamed PSExec - Rule", "ESCU - Executable File Written in Administrative SMB Share - Rule", "ESCU - Impacket Lateral Movement Commandline Parameters - Rule", "ESCU - Interactive Session on Remote Endpoint with PowerShell - Rule", "ESCU - Mmc LOLBAS Execution Process Spawn - Rule", "ESCU - Possible Lateral Movement PowerShell Spawn - Rule", "ESCU - Randomly Generated Scheduled Task Name - Rule", "ESCU - Randomly Generated Windows Service Name - Rule", "ESCU - Remote Desktop Network Traffic - Rule", "ESCU - Remote Desktop Process Running On System - Rule", "ESCU - Remote Process Instantiation via DCOM and PowerShell - Rule", "ESCU - Remote Process Instantiation via DCOM and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WMI - Rule", "ESCU - Remote Process Instantiation via WMI and PowerShell - Rule", "ESCU - Remote Process Instantiation via WMI and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WinRM and PowerShell - Rule", "ESCU - Remote Process Instantiation via WinRM and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WinRM and Winrs - Rule", "ESCU - Scheduled Task Creation on Remote Endpoint using At - Rule", "ESCU - Scheduled Task Initiation on Remote Endpoint - Rule", "ESCU - Schtasks scheduling job on remote system - Rule", "ESCU - Services LOLBAS Execution Process Spawn - Rule", "ESCU - Short Lived Scheduled Task - Rule", "ESCU - Svchost LOLBAS Execution Process Spawn - Rule", "ESCU - Unusual Number of Computer Service Tickets Requested - Rule", "ESCU - Unusual Number of Remote Endpoint Authentication Events - Rule", "ESCU - WinEvent Scheduled Task Created Within Public Path - Rule", "ESCU - Windows Service Created With Suspicious Service Path - Rule", "ESCU - Windows Service Created Within Public Path - Rule", "ESCU - Windows Service Creation on Remote Endpoint - Rule", "ESCU - Windows Service Initiation on Remote Endpoint - Rule", "ESCU - Wmiprsve LOLBAS Execution Process Spawn - Rule", "ESCU - Wsmprovhost LOLBAS Execution Process Spawn - Rule", "ESCU - Investigate Successful Remote Desktop Authentications - Response Task"]
description = Detect and investigate tactics, techniques, and procedures around how attackers move laterally within an Active Directory environment. Since lateral movement is often a necessary step in a breach, it is important for cyber defenders to deploy detection coverage. /n**SOAR:** The following Splunk SOAR playbooks can be used in the response to this story's analytics: 'Delete Detected Files'
narrative = Once attackers gain a foothold within an enterprise, they will seek to expand their accesses and leverage techniques that facilitate lateral movement. Attackers will often spend quite a bit of time and effort moving laterally. Because lateral movement renders an attacker the most vulnerable to detection, it's an excellent focus for detection and investigation.\
Indications of lateral movement in an Active Directory network can include the abuse of system utilities (such as `psexec.exe`), unauthorized use of remote desktop services, `file/admin$` shares, WMI, PowerShell, Service Control Manager, the DCOM protocol, WinRM or the abuse of scheduled tasks. Organizations must be extra vigilant in detecting lateral movement techniques and look for suspicious activity in and around high-value strategic network assets, such as Active Directory, which are often considered the primary target or "crown jewels" to a persistent threat actor.\
An adversary can use lateral movement for multiple purposes, including remote execution of tools, pivoting to additional systems, obtaining access to specific information or files, access to additional credentials, exfiltrating data, or delivering a secondary effect. Adversaries may use legitimate credentials alongside inherent network and operating-system functionality to remotely connect to other systems and remain under the radar of network defenders.\
If there is evidence of lateral movement, it is imperative for analysts to collect evidence of the associated offending hosts. For example, an attacker might leverage host A to gain access to host B. From there, the attacker may try to move laterally to host C. In this example, the analyst should gather as much information as possible from all three hosts. \
It is also important to collect authentication logs for each host, to ensure that the offending accounts are well-documented. Analysts should account for all processes to ensure that the attackers did not install unauthorized software.
[analytic_story://Active Directory Password Spraying]
category = Adversary Tactics
last_updated = 2021-04-07
@@ -529,7 +544,7 @@ version = 1
references = ["https://attack.mitre.org/techniques/T1105/"]
maintainers = [{"company": "Splunk", "email": "-", "name": "Michael Haag"}]
spec_version = 3
searches = ["ESCU - Any Powershell DownloadFile - Rule", "ESCU - Any Powershell DownloadString - Rule", "ESCU - BITSAdmin Download File - Rule", "ESCU - CertUtil Download With URLCache and Split Arguments - Rule", "ESCU - CertUtil Download With VerifyCtl and Split Arguments - Rule", "ESCU - Suspicious Curl Network Connection - Rule", "ESCU - Windows Curl Download to Suspicious Path - Rule", "ESCU - Windows Curl Upload to Remote Destination - Rule"]
searches = ["ESCU - Any Powershell DownloadFile - Rule", "ESCU - Any Powershell DownloadString - Rule", "ESCU - BITSAdmin Download File - Rule", "ESCU - CertUtil Download With URLCache and Split Arguments - Rule", "ESCU - CertUtil Download With VerifyCtl and Split Arguments - Rule", "ESCU - Curl Download and Bash Execution - Rule", "ESCU - Suspicious Curl Network Connection - Rule", "ESCU - Wget Download and Bash Execution - Rule", "ESCU - Windows Curl Download to Suspicious Path - Rule", "ESCU - Windows Curl Upload to Remote Destination - Rule"]
description = Adversaries may transfer tools or other files from an external system into a compromised environment. Files may be copied from an external adversary controlled system through the command and control channel to bring tools into the victim network or through alternate protocols with another tool such as FTP.
narrative = Ingress tool transfer is a Technique under tactic Command and Control. Behaviors will include the use of living off the land binaries to download implants or binaries over alternate communication ports. It is imperative to baseline applications on endpoints to understand what generates network activity, to where, and what is its native behavior. These utilities, when abused, will write files to disk in world writeable paths.\ During triage, review the reputation of the remote public destination IP or domain. Capture any files written to disk and perform analysis. Review other parrallel processes for additional behaviors.
@@ -580,20 +595,16 @@ searches = ["ESCU - AWS EKS Kubernetes cluster sensitive object access - Rule",
description = This story addresses detection and response of accounts acccesing Kubernetes cluster sensitive objects such as configmaps or secrets providing information on items such as user user, group. object, namespace and authorization reason.
narrative = Kubernetes is the most used container orchestration platform, this orchestration platform contains sensitive objects within its architecture, specifically configmaps and secrets, if accessed by an attacker can lead to further compromise. These searches allow operator to detect suspicious requests against Kubernetes sensitive objects.
[analytic_story://Lateral Movement]
[analytic_story://Log4Shell CVE-2021-44228]
category = Adversary Tactics
last_updated = 2021-11-23
version = 2
references = ["https://www.fireeye.com/blog/executive-perspective/2015/08/malware_lateral_move.html", "https://www.youtube.com/watch?v=hVTkkkM9XDg"]
maintainers = [{"company": "Mauricio Velazco Splunk", "email": "-", "name": "David Dorsey"}]
last_updated = 2021-12-11
version = 1
references = ["https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/", "https://www.fastly.com/blog/digging-deeper-into-log4shell-0day-rce-exploit-found-in-log4j", "https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/", "https://www.lunasec.io/docs/blog/log4j-zero-day/", "https://www.splunk.com/en_us/blog/security/log-jammin-log4j-2-rce.html"]
maintainers = [{"company": "no", "email": "-", "name": "Jose Hernandez"}]
spec_version = 3
searches = ["ESCU - Detect Activity Related to Pass the Hash Attacks - Rule", "ESCU - Detect PsExec With accepteula Flag - Rule", "ESCU - Detect Renamed PSExec - Rule", "ESCU - Executable File Written in Administrative SMB Share - Rule", "ESCU - Get DomainUser with PowerShell Script Block - Rule", "ESCU - Impacket Lateral Movement Commandline Parameters - Rule", "ESCU - Interactive Session on Remote Endpoint with PowerShell - Rule", "ESCU - Mmc LOLBAS Execution Process Spawn - Rule", "ESCU - Remote Desktop Network Traffic - Rule", "ESCU - Remote Desktop Process Running On System - Rule", "ESCU - Remote Process Instantiation via DCOM and PowerShell - Rule", "ESCU - Remote Process Instantiation via DCOM and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WMI - Rule", "ESCU - Remote Process Instantiation via WMI and PowerShell - Rule", "ESCU - Remote Process Instantiation via WMI and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WinRM and PowerShell - Rule", "ESCU - Remote Process Instantiation via WinRM and PowerShell Script Block - Rule", "ESCU - Remote Process Instantiation via WinRM and Winrs - Rule", "ESCU - Scheduled Task Creation on Remote Endpoint using At - Rule", "ESCU - Scheduled Task Initiation on Remote Endpoint - Rule", "ESCU - Schtasks scheduling job on remote system - Rule", "ESCU - Services LOLBAS Execution Process Spawn - Rule", "ESCU - Svchost LOLBAS Execution Process Spawn - Rule", "ESCU - WinEvent Scheduled Task Created Within Public Path - Rule", "ESCU - Windows Service Created With Suspicious Service Path - Rule", "ESCU - Windows Service Created Within Public Path - Rule", "ESCU - Windows Service Creation on Remote Endpoint - Rule", "ESCU - Windows Service Initiation on Remote Endpoint - Rule", "ESCU - Wmiprsve LOLBAS Execution Process Spawn - Rule", "ESCU - Wsmprovhost LOLBAS Execution Process Spawn - Rule", "ESCU - Get History Of Email Sources - Response Task", "ESCU - Get Notable History - Response Task", "ESCU - Get Parent Process Info - Response Task", "ESCU - Get Process Info - Response Task", "ESCU - Get Process Information For Port Activity - Response Task", "ESCU - Investigate Successful Remote Desktop Authentications - Response Task"]
description = Detect and investigate tactics, techniques, and procedures around how attackers move laterally within the enterprise. Because lateral movement can expose the adversary to detection, it should be an important focus for security analysts.
narrative = Once attackers gain a foothold within an enterprise, they will seek to expand their accesses and leverage techniques that facilitate lateral movement. Attackers will often spend quite a bit of time and effort moving laterally. Because lateral movement renders an attacker the most vulnerable to detection, it's an excellent focus for detection and investigation.\
Indications of lateral movement can include the abuse of system utilities (such as `psexec.exe`), unauthorized use of remote desktop services, `file/admin$` shares, WMI, PowerShell, pass-the-hash, or the abuse of scheduled tasks. Organizations must be extra vigilant in detecting lateral movement techniques and look for suspicious activity in and around high-value strategic network assets, such as Active Directory, which are often considered the primary target or "crown jewels" to a persistent threat actor.\
An adversary can use lateral movement for multiple purposes, including remote execution of tools, pivoting to additional systems, obtaining access to specific information or files, access to additional credentials, exfiltrating data, or delivering a secondary effect. Adversaries may use legitimate credentials alongside inherent network and operating-system functionality to remotely connect to other systems and remain under the radar of network defenders.\
If there is evidence of lateral movement, it is imperative for analysts to collect evidence of the associated offending hosts. For example, an attacker might leverage host A to gain access to host B. From there, the attacker may try to move laterally to host C. In this example, the analyst should gather as much information as possible from all three hosts. \
It is also important to collect authentication logs for each host, to ensure that the offending accounts are well-documented. Analysts should account for all processes to ensure that the attackers did not install unauthorized software.
searches = ["ESCU - Any Powershell DownloadFile - Rule", "ESCU - CMD Carry Out String Command Parameter - Rule", "ESCU - Curl Download and Bash Execution - Rule", "ESCU - Java Class File download by Java User Agent - Rule", "ESCU - Linux Java Spawning Shell - Rule", "ESCU - Log4Shell JNDI Payload Injection Attempt - Rule", "ESCU - Log4Shell JNDI Payload Injection with Outbound Connection - Rule", "ESCU - Malicious PowerShell Process - Connect To Internet With Hidden Window - Rule", "ESCU - Outbound Network Connection from Java Using Default Ports - Rule", "ESCU - Wget Download and Bash Execution - Rule", "ESCU - Windows Java Spawning Shells - Rule"]
description = Log4Shell or CVE-2021-44228 is a Remote Code Execution (RCE) vulnerability in the Apache Log4j library, a widely used and extremely uibiquitous logging framework for Java. The vulnerability allows an attacker who can control log messages to execute arbitrary code loaded from attacker controlled servers and we anticipate that most apps using the Log4j library will meet this condition.
narrative = In late November 2021, Chen Zhaojun of Alibaba identified a remote code execution vulnerability. Previous work was seen in a 2016 Blackhat tak by Alvaro Munoz and Oleksandr Mirosh called ["A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land"](https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf). Reported under the CVE ID : CVE-2021-44228, released to the public on December 10, 2021. The vulnerability is exploited through improper deserialization of user-input passed into the framework. It permits remote code execution and it can allow an attacker to leak sensitive data, such as environment variables, or execute malicious software on the target system.
[analytic_story://Malicious PowerShell]
category = Adversary Tactics
@@ -602,7 +613,7 @@ version = 5
references = ["https://blogs.mcafee.com/mcafee-labs/malware-employs-powershell-to-infect-systems/", "https://www.crowdstrike.com/blog/bears-midst-intrusion-democratic-national-committee/"]
maintainers = [{"company": "Splunk", "email": "-", "name": "David Dorsey"}]
spec_version = 3
searches = ["ESCU - Any Powershell DownloadFile - Rule", "ESCU - Any Powershell DownloadString - Rule", "ESCU - Detect Empire with PowerShell Script Block Logging - Rule", "ESCU - Detect Mimikatz With PowerShell Script Block Logging - Rule", "ESCU - Get DomainUser with PowerShell Script Block - Rule", "ESCU - Malicious PowerShell Process - Connect To Internet With Hidden Window - Rule", "ESCU - Malicious PowerShell Process - Encoded Command - Rule", "ESCU - Malicious PowerShell Process - Multiple Suspicious Command-Line Arguments - Rule", "ESCU - Malicious PowerShell Process With Obfuscation Techniques - Rule", "ESCU - PowerShell 4104 Hunting - Rule", "ESCU - PowerShell Domain Enumeration - Rule", "ESCU - PowerShell Loading DotNET into Memory via System Reflection Assembly - Rule", "ESCU - Powershell Creating Thread Mutex - Rule", "ESCU - Powershell Enable SMB1Protocol Feature - Rule", "ESCU - Powershell Execute COM Object - Rule", "ESCU - Powershell Fileless Process Injection via GetProcAddress - Rule", "ESCU - Powershell Fileless Script Contains Base64 Encoded Content - Rule", "ESCU - Powershell Processing Stream Of Data - Rule", "ESCU - Powershell Using memory As Backing Store - Rule", "ESCU - Recon AVProduct Through Pwh or WMI - Rule", "ESCU - Recon Using WMI Class - Rule", "ESCU - Set Default PowerShell Execution Policy To Unrestricted or Bypass - Rule", "ESCU - Unloading AMSI via Reflection - Rule", "ESCU - WMI Recon Running Process Or Services - Rule", "ESCU - Get History Of Email Sources - Response Task", "ESCU - Get Notable History - Response Task", "ESCU - Get Parent Process Info - Response Task", "ESCU - Get Process Info - Response Task"]
searches = ["ESCU - Any Powershell DownloadFile - Rule", "ESCU - Any Powershell DownloadString - Rule", "ESCU - Detect Empire with PowerShell Script Block Logging - Rule", "ESCU - Detect Mimikatz With PowerShell Script Block Logging - Rule", "ESCU - Get DomainUser with PowerShell Script Block - Rule", "ESCU - Malicious PowerShell Process - Connect To Internet With Hidden Window - Rule", "ESCU - Malicious PowerShell Process - Encoded Command - Rule", "ESCU - Malicious PowerShell Process - Multiple Suspicious Command-Line Arguments - Rule", "ESCU - Malicious PowerShell Process With Obfuscation Techniques - Rule", "ESCU - Possible Lateral Movement PowerShell Spawn - Rule", "ESCU - PowerShell 4104 Hunting - Rule", "ESCU - PowerShell Domain Enumeration - Rule", "ESCU - PowerShell Loading DotNET into Memory via System Reflection Assembly - Rule", "ESCU - Powershell Creating Thread Mutex - Rule", "ESCU - Powershell Enable SMB1Protocol Feature - Rule", "ESCU - Powershell Execute COM Object - Rule", "ESCU - Powershell Fileless Process Injection via GetProcAddress - Rule", "ESCU - Powershell Fileless Script Contains Base64 Encoded Content - Rule", "ESCU - Powershell Processing Stream Of Data - Rule", "ESCU - Powershell Using memory As Backing Store - Rule", "ESCU - Recon AVProduct Through Pwh or WMI - Rule", "ESCU - Recon Using WMI Class - Rule", "ESCU - Set Default PowerShell Execution Policy To Unrestricted or Bypass - Rule", "ESCU - Unloading AMSI via Reflection - Rule", "ESCU - WMI Recon Running Process Or Services - Rule", "ESCU - Get History Of Email Sources - Response Task", "ESCU - Get Notable History - Response Task", "ESCU - Get Parent Process Info - Response Task", "ESCU - Get Process Info - Response Task"]
description = Attackers are finding stealthy ways "live off the land," leveraging utilities and tools that come standard on the endpoint--such as PowerShell--to achieve their goals without downloading binary files. These searches can help you detect and investigate PowerShell command-line options that may be indicative of malicious intent.
narrative = The searches in this Analytic Story monitor for parameters often used for malicious purposes. It is helpful to understand how often the notable events generated by this story occur, as well as the commonalities between some of these events. These factors may provide clues about whether this is a common occurrence of minimal concern or a rare event that may require more extensive investigation. Likewise, it is important to determine whether the issue is restricted to a single user/system or is broader in scope. \
The following factors may assist you in determining whether the event is malicious: \
@@ -2015,10 +2026,10 @@ providing_technologies = []
type = detection
asset_type =
confidence = medium
explanation = This search looks for command-line arguments where `cmd.exe /c` is used to execute a program. This technique is commonly seen in adversaries and malware to execute batch command using different shell like powershell or different process other than cmd.exe. This is a good hunting query for suspicious commandline made by a script or relative process execute it.
explanation = The following analytic identifies command-line arguments where `cmd.exe /c` is used to execute a program. `cmd /c` is used to run commands in MS-DOS and terminate after command or process completion. This technique is commonly seen in adversaries and malware to execute batch command using different shell like PowerShell or different process other than `cmd.exe`. This is a good hunting query for suspicious command-line made by a script or relative process execute it.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon, you must have at least version 6.0.4 of the Sysmon TA.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1059.003", "T1059"]}
known_false_positives = unknown
known_false_positives = False positives may be high based on legitimate scripted code in any environment. Filter as needed.
providing_technologies = []
[savedsearch://ESCU - CMD Echo Pipe - Escalation - Rule]
@@ -2482,6 +2493,16 @@ annotations = {"cis20": ["CIS 8", "CIS 16"], "kill_chain_phases": ["Actions on O
known_false_positives = unknown
providing_technologies = []
[savedsearch://ESCU - Curl Download and Bash Execution - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies the use of curl on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required. Add parent process name (Processes.parent_process_name) as needed to filter.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1105"]}
known_false_positives = False positives should be limited, however filtering may be required.
providing_technologies = []
[savedsearch://ESCU - DLLHost with no Command Line Arguments with Network - Rule]
type = detection
asset_type =
@@ -4348,8 +4369,8 @@ providing_technologies = []
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies executable files (.exe or .dll) being written to Windows administrative SMB shares (Admin$, IPC$, C$). This represents suspicious behavior as its commonly user by tools like like PsExec/PaExec and others to stage service binaries before creating and starting a Windows service on remote endpoints. Red Teams and adversaries alike may abuse administrative shares for lateral movement and remote code execution. The Trickbot malware family also implements this behavior to try to infect other machines in the infected network.
how_to_implement = To successfully implement this search, you need to be ingesting Windows Security Event Logs with 5145 EventCode enabled. The Windows TA is also required. Also enable the object Audit access success/failure in your group policy.
explanation = The following analytic identifies executable files (.exe or .dll) being written to Windows administrative SMB shares (Admin$, IPC$, C$). This represents suspicious behavior as its commonly used by tools like like PsExec/PaExec and others to stage service binaries before creating and starting a Windows service on remote endpoints. Red Teams and adversaries alike may abuse administrative shares for lateral movement and remote code execution. The Trickbot malware family also implements this behavior to try to infect other machines in the infected network.
how_to_implement = To successfully implement this search, you need to be ingesting Windows Security Event Logs with 5145 EventCode enabled. The Windows TA is also required. Also enable the object Audit access success/failure in your group policy. The following Splunk SOAR playbook can be used to respond to this detection: Delete Detected Files
annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T1021", "T1021.002"]}
known_false_positives = System Administrators may use looks like PsExec for troubleshooting or administrations tasks. However, this will typically come only from certain users and certain systems that can be added to an allow list.
providing_technologies = []
@@ -5214,6 +5235,16 @@ annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T102
known_false_positives = Administrators may leverage WinRM and `Enter-PSSession` for administrative and troubleshooting tasks. This activity is usually limited to a small set of hosts or users. In certain environments, tuning may not be possible.
providing_technologies = []
[savedsearch://ESCU - Java Class File download by Java User Agent - Rule]
type = detection
asset_type = Web Server
confidence = medium
explanation = The following analytic identifies a Java user agent performing a GET request for a .class file from the remote site. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell).
how_to_implement = To successfully implement this search, you need to be ingesting web or proxy logs, or ensure it is being filled by a proxy like device, into the Web Datamodel. For additional filtering, allow list private IP space or restrict by known good.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1190"]}
known_false_positives = Filtering may be required in some instances, filter as needed.
providing_technologies = []
[savedsearch://ESCU - Jscript Execution Using Cscript App - Rule]
type = detection
asset_type =
@@ -5474,6 +5505,16 @@ annotations = {"cis20": ["CIS 11", "CIS 12"], "kill_chain_phases": ["Actions on
known_false_positives = Legitimate ANY requests may trigger this search, however it is unusual to see a large volume of them under typical circumstances. You may modify the threshold in the search to better suit your environment.
providing_technologies = []
[savedsearch://ESCU - Linux Java Spawning Shell - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies the process name of Java, Apache, or Tomcat spawning a Linux shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell). The shells included in the macro are "sh", "ksh", "zsh", "bash", "dash", "rbash", "fish", "csh', "tcsh', "ion", "eshell". Upon triage, review parallel processes and command-line arguments to determine legitimacy.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. Ensure EDR product is mapping OS Linux to the datamodel properly. Add any additional java process names for your environment to the analytic as needed.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1190"]}
known_false_positives = Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
providing_technologies = []
[savedsearch://ESCU - Loading Of Dynwrapx Module - Rule]
type = detection
asset_type =
@@ -5504,6 +5545,26 @@ annotations = {"kill_chain_phases": ["Reconnaissance"], "mitre_attack": ["T1087"
known_false_positives = Administrators or power users may use this command for troubleshooting.
providing_technologies = []
[savedsearch://ESCU - Log4Shell JNDI Payload Injection Attempt - Rule]
type = detection
asset_type =
confidence = medium
explanation = CVE-2021-44228 Log4Shell payloads can be injected via various methods, but on of the most common vectors injection is via Web calls. Many of the vulnerable java web applications that are using log4j have a web component to them are specially targets of this injection, specifically projects like Apache Struts, Flink, Druid, and Solr. The exploit is triggered by a LDAP lookup function in the log4j package, its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against vulnerable web applications the invocation can be seen in various part of web logs. Specifically it has been successfully exploited via headers like X-Forwarded-For, User-Agent, Referer, and X-Api-Version. In this detection we first limit the scope of our search to the Web Datamodel and use the `| from datamodel` function to benefit from schema accelerated searching capabilities, mainly because the second part of the detection is pretty heavy, it runs a regex across all _raw events that looks for `${jndi:ldap://` pattern across all potential web fields available to the raw data, like http headers for example. If you see results for this detection, it means that there was a attempt at a injection, which could be a reconnaissance activity or a valid expliotation attempt, but this does not exactly mean that the host was indeed successfully exploited.
how_to_implement = This detection requires the Web datamodel to be populated from a supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
annotations = {"cis20": ["CIS 3", "CIS 5", "CIS 16"], "kill_chain_phases": ["Reconnaissance", "Exploitation"], "mitre_attack": ["T1190"], "nist": ["DE.CM"]}
known_false_positives = If there is a vulnerablility scannner looking for log4shells this will trigger, otherwise likely to have low false positives.
providing_technologies = []
[savedsearch://ESCU - Log4Shell JNDI Payload Injection with Outbound Connection - Rule]
type = detection
asset_type =
confidence = medium
explanation = CVE-2021-44228 Log4Shell payloads can be injected via various methods, but on of the most common vectors injection is via Web calls. Many of the vulnerable java web applications that are using log4j have a web component to them are specially targets of this injection, specifically projects like Apache Struts, Flink, Druid, and Solr. The exploit is triggered by a LDAP lookup function in the log4j package, its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against vulnerable web applications the invocation can be seen in various part of web logs. Specifically it has been successfully exploited via headers like X-Forwarded-For, User-Agent, Referer, and X-Api-Version. In this detection we match the invocation function with a network connection to a malicious ip address.
how_to_implement = This detection requires the Web datamodel to be populated from a supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
annotations = {"cis20": ["CIS 3", "CIS 5", "CIS 16"], "kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1190"], "nist": ["DE.CM"]}
known_false_positives = If there is a vulnerablility scannner looking for log4shells this will trigger, otherwise likely to have low false positives.
providing_technologies = []
[savedsearch://ESCU - Logon Script Event Trigger Execution - Rule]
type = detection
asset_type =
@@ -6293,6 +6354,16 @@ annotations = {"cis20": ["CIS 4", "CIS 8"], "kill_chain_phases": ["Installation"
known_false_positives = There are no known false positives.
providing_technologies = []
[savedsearch://ESCU - Outbound Network Connection from Java Using Default Ports - Rule]
type = detection
asset_type =
confidence = medium
explanation = A required step while exploiting the CVE-2021-44228-Log4j vulnerability is that the victim server will perform outbound connections to attacker-controlled infrastrucutre. This is required as part of the JNDI lookup as well as for retrieving the second stage .class payload. The following analytic identifies the Java process reaching out to default ports used by the LDAP and RMI protocols. This behavior could represent successfull exploitation. Note that adversaries can easily decide to use arbitrary ports for these protocols and potentially bypass this detection.
how_to_implement = To successfully implement this search you need to be ingesting information on process that include the name of the process responsible for the changes from your endpoints into the `Endpoint` datamodel in the `Processes` node.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1190"]}
known_false_positives = Legitimate Java applications may use perform outbound connections to these ports. Filter as needed
providing_technologies = []
[savedsearch://ESCU - Overwriting Accessibility Binaries - Rule]
type = detection
asset_type = Endpoint
@@ -6366,6 +6437,16 @@ annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1555.00
known_false_positives = False positive is quite limited. Filter is needed
providing_technologies = []
[savedsearch://ESCU - Possible Lateral Movement PowerShell Spawn - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic assists with identifying a PowerShell process spawned as a child or grand child process of commonly abused processes during lateral movement techniques including `services.exe`, `wmiprsve.exe`, `svchost.exe`, `wsmprovhost.exe` and `mmc.exe`. Legitimate Windows features such as the Service Control Manager, Windows Management Instrumentation, Task Scheduler, Windows Remote Management and the DCOM protocol can be abused to start a process on a remote endpoint. Looking for PowerShell spawned out of this processes may reveal a lateral movement attack. Red Teams and adversaries alike may abuse these services during a breach for lateral movement and remote code execution.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints.
annotations = {"kill_chain_phases": ["Lateral Movement", "Malicious PowerShell"], "mitre_attack": ["T1021", "T1021.003", "T1021.006", "T1047", "T1053.005", "T1543.003", "T1059.001"]}
known_false_positives = Legitimate applications may spawn PowerShell as a child process of the the identified processes. Filter as needed.
providing_technologies = []
[savedsearch://ESCU - PowerShell 4104 Hunting - Rule]
type = detection
asset_type =
@@ -6703,6 +6784,26 @@ annotations = {"cis20": ["CIS 9", "CIS 14"], "kill_chain_phases": ["Reconnaissan
known_false_positives = Some networks may use kerberized FTP or telnet servers, however, this is rare.
providing_technologies = []
[savedsearch://ESCU - Randomly Generated Scheduled Task Name - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following hunting analytic leverages Event ID 4698, `A scheduled task was created`, to identify the creation of a Scheduled Task with a suspicious, high entropy, Task Name. To achieve this, this analytic also leverages the `ut_shannon` function from the URL ToolBox Splunk application. Red teams and adversaries alike may abuse the Task Scheduler to create and start a remote Scheduled Task and obtain remote code execution. To achieve this goal, tools like Impacket or Crapmapexec, typically create a Scheduled Task with a random task name on the victim host. This hunting analytic may help defenders identify Scheduled Tasks created as part of a lateral movement attack. The entropy threshold `ut_shannon > 3` should be customized by users. The Command field can be used to determine if the task has malicious intent or not.
how_to_implement = To successfully implement this search, you need to be ingesting Windows Security Event Logs with 4698 EventCode enabled. The Windows TA as well as the URL ToolBox application are also required.
annotations = {"kill_chain_phases": ["Privilege Escalation", "Lateral Movement", "Persistence"], "mitre_attack": ["T1053", "T1053.005"]}
known_false_positives = Legitimate applications may use random Scheduled Task names.
providing_technologies = []
[savedsearch://ESCU - Randomly Generated Windows Service Name - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following hunting analytic leverages Event ID 7045, `A new service was installed in the system`, to identify the installation of a Windows Service with a suspicious, high entropy, Service Name. To achieve this, this analytic also leverages the `ut_shannon` function from the URL ToolBox Splunk application. Red teams and adversaries alike may abuse the Service Control Manager to create and start a remote Windows Service and obtain remote code execution. To achieve this goal, some tools like Metasploit, Cobalt Strike and Impacket, typically create a Windows Service with a random service name on the victim host. This hunting analytic may help defenders identify Windows Services installed as part of a lateral movement attack. The entropy threshold `ut_shannon > 3` should be customized by users. The Service_File_Name field can be used to determine if the Windows Service has malicious intent or not.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the Service name, Service File Name Service Start type, and Service Type from your endpoints. The Windows TA as well as the URL ToolBox application are also required.
annotations = {"kill_chain_phases": ["Privilege Escalation", "Lateral Movement"], "mitre_attack": ["T1543", "T1543.003"]}
known_false_positives = Legitimate applications may use random Windows Service names.
providing_technologies = []
[savedsearch://ESCU - Ransomware Notes bulk creation - Rule]
type = detection
asset_type =
@@ -7441,7 +7542,7 @@ providing_technologies = []
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies `services.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing the Service Control Manager and creating a remote malicious service, the executed command is spawned as a child processs of `services.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of services.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
explanation = The following analytic identifies `services.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing the Service Control Manager and creating a remote malicious service, the executed command is spawned as a child process of `services.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of services.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints.
annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T1543", "T1543.003"]}
known_false_positives = Legitimate applications may trigger this behavior, filter as needed.
@@ -7477,6 +7578,16 @@ annotations = {"cis20": ["CIS 8"], "kill_chain_phases": ["Actions on Objectives"
known_false_positives = None identified
providing_technologies = []
[savedsearch://ESCU - Short Lived Scheduled Task - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic leverages Windows Security EventCode 4698, `A scheduled task was created` and Windows Security EventCode 4699, `A scheduled task was deleted` to identify scheduled tasks created and deleted in less than 30 seconds. This behavior may represent a lateral movement attack abusing the Task Scheduler to obtain code execution. Red Teams and adversaries alike may abuse the Task Scheduler for lateral movement and remote code execution.
how_to_implement = To successfully implement this search, you need to be ingesting Windows Security Event Logs with 4698 EventCode enabled. The Windows TA is also required.
annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T1053.005"]}
known_false_positives = Although uncommon, legitimate applications may create and delete a Scheduled Task within 30 seconds. Filter as needed.
providing_technologies = []
[savedsearch://ESCU - Short Lived Windows Accounts - Rule]
type = detection
asset_type = Windows
@@ -8027,7 +8138,7 @@ providing_technologies = []
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies `svchost.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing the Task Scheduler and creating a malicious remote scheduled task, the executed command is spawned as a child processs of `svchost.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of svchost.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
explanation = The following analytic identifies `svchost.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing the Task Scheduler and creating a malicious remote scheduled task, the executed command is spawned as a child process of `svchost.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of svchost.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints.
annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T1053", "T1053.005"]}
known_false_positives = Legitimate applications may trigger this behavior, filter as needed.
@@ -8217,6 +8328,28 @@ annotations = {"cis20": ["CIS 10"], "nist": ["PR.IP"]}
known_false_positives = None identified
providing_technologies = []
[savedsearch://ESCU - Unusual Number of Computer Service Tickets Requested - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following hunting analytic leverages Event ID 4769, `A Kerberos service ticket was requested`, to identify an unusual number of computer service ticket requests from one source. When a domain joined endpoint connects to a remote endpoint, it first will request a Kerberos Ticket with the computer name as the Service Name. An endpoint requesting a large number of computer service tickets for different endpoints could represent malicious behavior like lateral movement, malware staging, reconnaissance, etc.\
The detection calculates the standard deviation for each host and leverages the 3-sigma statistical rule to identify an unusual number of service requests. To customize this analytic, users can try different combinations of the `bucket` span time, the calculation of the `upperBound` field as well as the Outlier calculation. This logic can be used for real time security monitoring as well as threat hunting exercises.\
how_to_implement = To successfully implement this search, you need to be ingesting Domain Controller and Kerberos events. The Advanced Security Audit policy setting `Audit Kerberos Authentication Service` within `Account Logon` needs to be enabled.
annotations = {"kill_chain_phases": ["Reconnaissance", "Exploitation", "Lateral Movement"], "mitre_attack": ["T1078"]}
known_false_positives = An single endpoint requesting a large number of computer service tickets is not common behavior. Possible false positive scenarios include but are not limited to vulnerability scanners, administration systeams and missconfigured systems.
providing_technologies = []
[savedsearch://ESCU - Unusual Number of Remote Endpoint Authentication Events - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following hunting analytic leverages Event ID 4624, `An account was successfully logged on`, to identify an unusual number of remote authentication attempts coming from one source. An endpoint authenticating to a large number of remote endpoints could represent malicious behavior like lateral movement, malware staging, reconnaissance, etc.\
The detection calculates the standard deviation for each host and leverages the 3-sigma statistical rule to identify an unusual high number of authentication events. To customize this analytic, users can try different combinations of the `bucket` span time, the calculation of the `upperBound` field as well as the Outlier calculation. This logic can be used for real time security monitoring as well as threat hunting exercises.\
how_to_implement = To successfully implement this search, you need to be ingesting Windows Event Logs from domain controllers aas well as member servers and workstations. The Advanced Security Audit policy setting `Audit Logon` within `Logon/Logoff` needs to be enabled.
annotations = {"kill_chain_phases": ["Reconnaissance", "Lateral Movement"], "mitre_attack": ["T1078"]}
known_false_positives = An single endpoint authenticating to a large number of hosts is not common behavior. Possible false positive scenarios include but are not limited to vulnerability scanners, jump servers and missconfigured systems.
providing_technologies = []
[savedsearch://ESCU - Unusually Long Command Line - Rule]
type = detection
asset_type = Endpoint
@@ -8452,6 +8585,16 @@ annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1059"]}
known_false_positives = unknown
providing_technologies = []
[savedsearch://ESCU - Wget Download and Bash Execution - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies the use of wget on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required. Add parent process name (Processes.parent_process_name) as needed to filter.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1105"]}
known_false_positives = False positives should be limited, however filtering may be required.
providing_technologies = []
[savedsearch://ESCU - WinEvent Scheduled Task Created Within Public Path - Rule]
type = detection
asset_type =
@@ -8643,6 +8786,16 @@ annotations = {"kill_chain_phases": ["Exploitation", "Privilege Escalation"], "m
known_false_positives = Limited false positives should be present as InstallUtil is not typically used to download remote files. Filter as needed based on Developers requirements.
providing_technologies = []
[savedsearch://ESCU - Windows Java Spawning Shells - Rule]
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies the process name of java.exe and w3wp.exe spawning a Windows shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell). The shells included in the macro are "cmd.exe", "powershell.exe". Upon triage, review parallel processes and command-line arguments to determine legitimacy.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. Restrict the analytic to publicly facing endpoints to reduce false positives. Add any additional identified web application process name to the query. Add any further Windows process names to the macro (ex. LOLBins) to further expand this query.
annotations = {"kill_chain_phases": ["Exploitation"], "mitre_attack": ["T1190"]}
known_false_positives = Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
providing_technologies = []
[savedsearch://ESCU - Windows Security Account Manager Stopped - Rule]
type = detection
asset_type = Endpoint
@@ -8779,7 +8932,7 @@ providing_technologies = []
type = detection
asset_type =
confidence = medium
explanation = The following analytic identifies `wmiprsve.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing Windows Management Instrumention (WMI), the executed command is spawned as a child processs of `wmiprvse.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of wmiprvse.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
explanation = The following analytic identifies `wmiprsve.exe` spawning a LOLBAS execution process. When adversaries execute code on remote endpoints abusing Windows Management Instrumentation (WMI), the executed command is spawned as a child process of `wmiprvse.exe`. The LOLBAS project documents Windows native binaries that can be abused by threat actors to perform tasks like executing malicious code. Looking for child processes of wmiprvse.exe that are part of the LOLBAS project can help defenders identify lateral movement activity.
how_to_implement = To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints.
annotations = {"kill_chain_phases": ["Lateral Movement"], "mitre_attack": ["T1047"]}
known_false_positives = Legitimate applications may trigger this behavior, filter as needed.
+1 -1
View File
@@ -1,6 +1,6 @@
#############
# Automatically generated by generator.py in splunk/security_content
# On Date: 2021-12-02T18:37:19 UTC
# On Date: 2021-12-14T17:20:43 UTC
# Author: Splunk Security Research
# Contact: research@splunk.com
#############
+11 -4
View File
@@ -41,6 +41,13 @@ disabled = 0
panels = ["panel://workbench_panel_get_notable_history___response_task"]
[panel_group://workbench_panel_group_active_directory_lateral_movement]
label = Active Directory Lateral Movement
description = Detect and investigate tactics, techniques, and procedures around how attackers move laterally within an Active Directory environment. Since lateral movement is often a necessary step in a breach, it is important for cyber defenders to deploy detection coverage. /n**SOAR:** The following Splunk SOAR playbooks can be used in the response to this story's analytics: 'Delete Detected Files'
disabled = 0
panels = ["panel://workbench_panel_investigate_successful_remote_desktop_authentications___response_task"]
[panel_group://workbench_panel_group_active_directory_password_spraying]
label = Active Directory Password Spraying
description = Monitor for activities and techniques associated with Password Spraying attacks within Active Directory environments.
@@ -314,12 +321,12 @@ disabled = 0
panels = ["panel://workbench_panel_get_notable_history___response_task"]
[panel_group://workbench_panel_group_lateral_movement]
label = Lateral Movement
description = Detect and investigate tactics, techniques, and procedures around how attackers move laterally within the enterprise. Because lateral movement can expose the adversary to detection, it should be an important focus for security analysts.
[panel_group://workbench_panel_group_log4shell_cve_2021_44228]
label = Log4Shell CVE-2021-44228
description = Log4Shell or CVE-2021-44228 is a Remote Code Execution (RCE) vulnerability in the Apache Log4j library, a widely used and extremely uibiquitous logging framework for Java. The vulnerability allows an attacker who can control log messages to execute arbitrary code loaded from attacker controlled servers and we anticipate that most apps using the Log4j library will meet this condition.
disabled = 0
panels = ["panel://workbench_panel_get_history_of_email_sources___response_task", "panel://workbench_panel_get_notable_history___response_task", "panel://workbench_panel_get_parent_process_info___response_task", "panel://workbench_panel_get_process_info___response_task", "panel://workbench_panel_get_process_information_for_port_activity___response_task", "panel://workbench_panel_investigate_successful_remote_desktop_authentications___response_task"]
panels = ["panel://workbench_panel_get_notable_history___response_task"]
[panel_group://workbench_panel_group_malicious_powershell]
label = Malicious PowerShell
+66 -2
View File
@@ -1,6 +1,6 @@
#############
# Automatically generated by generator.py in splunk/security_content
# On Date: 2021-12-02T18:37:19 UTC
# On Date: 2021-12-14T17:20:44 UTC
# Author: Splunk Security Research
# Contact: research@splunk.com
#############
@@ -174,6 +174,10 @@ description = customer specific splunk configurations(eg- index, source, sourcet
definition = index=*
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
[linux_shells]
definition = (Processes.process_name IN ("sh", "ksh", "zsh", "bash", "dash", "rbash", "fish", "csh', "tcsh', "ion", "eshell"))
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
[netbackup]
definition = sourcetype="netbackup_logs"
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
@@ -484,7 +488,7 @@ definition = lookup suspicious_writes_lookup file as file_name OUTPUT note as "R
description = This macro limites the output to file names that have been marked as suspicious
[sysmon]
definition = sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational
definition = sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=Syslog:Linux-Sysmon/Operational
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
[system_network_configuration_discovery_tools]
@@ -495,6 +499,10 @@ description = This macro is a list of process that can be used to discover the n
definition = lookup update=true lookup_uncommon_processes_default process_name as process_name outputnew uncommon_default,category_default,analytic_story_default,kill_chain_phase_default,mitre_attack_default | lookup update=true lookup_uncommon_processes_local process_name as process_name outputnew uncommon_local,category_local,analytic_story_local,kill_chain_phase_local,mitre_attack_local | eval uncommon = coalesce(uncommon_default, uncommon_local), analytic_story = coalesce(analytic_story_default, analytic_story_local), category=coalesce(category_default, category_local), kill_chain_phase=coalesce(kill_chain_phase_default, kill_chain_phase_local), mitre_attack=coalesce(mitre_attack_default, mitre_attack_local) | fields - analytic_story_default, analytic_story_local, category_default, category_local, kill_chain_phase_default, kill_chain_phase_local, mitre_attack_default, mitre_attack_local, uncommon_default, uncommon_local | search uncommon=true
description = This macro limits the output to processes that have been marked as uncommon
[windows_shells]
definition = (Processes.process_name=cmd.exe OR Processes.process_name=powershell.exe)
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
[wineventlog_security]
definition = eventtype=wineventlog_security
description = customer specific splunk configurations(eg- index, source, sourcetype). Replace the macro definition with configurations for your Splunk Environmnent.
@@ -1063,6 +1071,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[curl_download_and_bash_execution_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[dllhost_with_no_command_line_arguments_with_network_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -2299,6 +2311,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[java_class_file_download_by_java_user_agent_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[jscript_execution_using_cscript_app_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -2403,6 +2419,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[linux_java_spawning_shell_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[loading_of_dynwrapx_module_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -2415,6 +2435,14 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[log4shell_jndi_payload_injection_attempt_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[log4shell_jndi_payload_injection_with_outbound_connection_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[logon_script_event_trigger_execution_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -2727,6 +2755,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[outbound_network_connection_from_java_using_default_ports_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[overwriting_accessibility_binaries_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -2755,6 +2787,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[possible_lateral_movement_powershell_spawn_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[powershell_4104_hunting_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -3015,6 +3051,14 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[randomly_generated_scheduled_task_name_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[randomly_generated_windows_service_name_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[ransomware_notes_bulk_creation_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -3323,6 +3367,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[short_lived_scheduled_task_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[short_lived_windows_accounts_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -3615,6 +3663,14 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[unusual_number_of_computer_service_tickets_requested_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[unusual_number_of_remote_endpoint_authentication_events_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[unusually_long_command_line_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -3711,6 +3767,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[wget_download_and_bash_execution_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[winevent_scheduled_task_created_within_public_path_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
@@ -3775,6 +3835,10 @@ description = Update this macro to limit the output results to filter out false
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[windows_java_spawning_shells_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
[windows_security_account_manager_stopped_filter]
definition = search *
description = Update this macro to limit the output results to filter out false positives.
+719 -88
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
#############
# Automatically generated by generator.py in splunk/security_content
# On Date: 2021-12-02T18:37:19 UTC
# On Date: 2021-12-14T17:20:43 UTC
# Author: Splunk Security Research
# Contact: research@splunk.com
#############
+1
View File
@@ -28,6 +28,7 @@ sidebar:
| [F5 TMUI RCE CVE-2020-5902](/stories/f5_tmui_rce_cve-2020-5902/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | [Initial Access](/tags/#initial-access) |
| [HAFNIUM Group](/stories/hafnium_group/) | [Server Software Component](/tags/#server-software-component), [Web Shell](/tags/#web-shell) | [Persistence](/tags/#persistence) |
| [Ingress Tool Transfer](/stories/ingress_tool_transfer/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | [Command And Control](/tags/#command-and-control) |
| [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | [Initial Access](/tags/#initial-access) |
| [Malicious PowerShell](/stories/malicious_powershell/) | [Gather Victim Host Information](/tags/#gather-victim-host-information) | [Reconnaissance](/tags/#reconnaissance) |
| [Masquerading - Rename System Utilities](/stories/masquerading_-_rename_system_utilities/) | [Masquerading](/tags/#masquerading), [Rename System Utilities](/tags/#rename-system-utilities) | [Defense Evasion](/tags/#defense-evasion) |
| [Meterpreter](/stories/meterpreter/) | [System Owner/User Discovery](/tags/#system-owner/user-discovery) | [Discovery](/tags/#discovery) |
+10
View File
@@ -114,6 +114,7 @@ sidebar:
| [Creation of lsass Dump with Taskmgr](/endpoint/creation_of_lsass_dump_with_taskmgr/) | [LSASS Memory](/tags/#lsass-memory), [OS Credential Dumping](/tags/#os-credential-dumping) | TTP |
| [Credential Dumping via Copy Command from Shadow Copy](/endpoint/credential_dumping_via_copy_command_from_shadow_copy/) | [NTDS](/tags/#ntds), [OS Credential Dumping](/tags/#os-credential-dumping) | TTP |
| [Credential Dumping via Symlink to Shadow Copy](/endpoint/credential_dumping_via_symlink_to_shadow_copy/) | [NTDS](/tags/#ntds), [OS Credential Dumping](/tags/#os-credential-dumping) | TTP |
| [Curl Download and Bash Execution](/endpoint/curl_download_and_bash_execution/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [DLLHost with no Command Line Arguments with Network](/endpoint/dllhost_with_no_command_line_arguments_with_network/) | [Process Injection](/tags/#process-injection) | TTP |
| [DNS Exfiltration Using Nslookup App](/endpoint/dns_exfiltration_using_nslookup_app/) | [Exfiltration Over Alternative Protocol](/tags/#exfiltration-over-alternative-protocol) | TTP |
| [DNS Exfiltration Using Nslookup App](/endpoint/dns_exfiltration_using_nslookup_app/) | [Exfiltration Over Alternative Protocol](/tags/#exfiltration-over-alternative-protocol) | TTP |
@@ -161,6 +162,7 @@ sidebar:
| [Detect New Open GCP Storage Buckets](/cloud/detect_new_open_gcp_storage_buckets/) | [Data from Cloud Storage Object](/tags/#data-from-cloud-storage-object) | TTP |
| [Detect New Open S3 Buckets over AWS CLI](/cloud/detect_new_open_s3_buckets_over_aws_cli/) | [Data from Cloud Storage Object](/tags/#data-from-cloud-storage-object) | TTP |
| [Detect New Open S3 buckets](/cloud/detect_new_open_s3_buckets/) | [Data from Cloud Storage Object](/tags/#data-from-cloud-storage-object) | TTP |
| [Detect Outbound LDAP Traffic](/network/detect_outbound_ldap_traffic/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application), [Command and Scripting Interpreter](/tags/#command-and-scripting-interpreter) | Hunting |
| [Detect Outbound SMB Traffic](/network/detect_outbound_smb_traffic/) | [File Transfer Protocols](/tags/#file-transfer-protocols), [Application Layer Protocol](/tags/#application-layer-protocol) | TTP |
| [Detect Outlook exe writing a zip file](/endpoint/detect_outlook_exe_writing_a_zip_file/) | [Phishing](/tags/#phishing), [Spearphishing Attachment](/tags/#spearphishing-attachment) | TTP |
| [Detect Path Interception By Creation Of program exe](/endpoint/detect_path_interception_by_creation_of_program_exe/) | [Path Interception by Unquoted Path](/tags/#path-interception-by-unquoted-path), [Hijack Execution Flow](/tags/#hijack-execution-flow) | TTP |
@@ -358,11 +360,13 @@ sidebar:
| [High Number of Login Failures from a single source](/cloud/high_number_of_login_failures_from_a_single_source/) | [Password Guessing](/tags/#password-guessing), [Brute Force](/tags/#brute-force) | Anomaly |
| [High Process Termination Frequency](/endpoint/high_process_termination_frequency/) | [Data Encrypted for Impact](/tags/#data-encrypted-for-impact) | Anomaly |
| [Hosts receiving high volume of network traffic from email server](/network/hosts_receiving_high_volume_of_network_traffic_from_email_server/) | [Remote Email Collection](/tags/#remote-email-collection), [Email Collection](/tags/#email-collection) | Anomaly |
| [Hunting for Log4Shell](/endpoint/hunting_for_log4shell/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | Hunting |
| [ICACLS Grant Command](/endpoint/icacls_grant_command/) | [File and Directory Permissions Modification](/tags/#file-and-directory-permissions-modification) | TTP |
| [Icacls Deny Command](/endpoint/icacls_deny_command/) | [File and Directory Permissions Modification](/tags/#file-and-directory-permissions-modification) | TTP |
| [IcedID Exfiltrated Archived File Creation](/endpoint/icedid_exfiltrated_archived_file_creation/) | [Archive via Utility](/tags/#archive-via-utility), [Archive Collected Data](/tags/#archive-collected-data) | Hunting |
| [Impacket Lateral Movement Commandline Parameters](/endpoint/impacket_lateral_movement_commandline_parameters/) | [Remote Services](/tags/#remote-services), [SMB/Windows Admin Shares](/tags/#smb/windows-admin-shares), [Distributed Component Object Model](/tags/#distributed-component-object-model), [Windows Management Instrumentation](/tags/#windows-management-instrumentation), [Windows Service](/tags/#windows-service) | TTP |
| [Interactive Session on Remote Endpoint with PowerShell](/endpoint/interactive_session_on_remote_endpoint_with_powershell/) | [Remote Services](/tags/#remote-services), [Windows Remote Management](/tags/#windows-remote-management) | TTP |
| [Java Class File download by Java User Agent](/endpoint/java_class_file_download_by_java_user_agent/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | TTP |
| [Jscript Execution Using Cscript App](/endpoint/jscript_execution_using_cscript_app/) | [Command and Scripting Interpreter](/tags/#command-and-scripting-interpreter), [JavaScript](/tags/#javascript) | TTP |
| [Kerberoasting spn request with RC4 encryption](/endpoint/kerberoasting_spn_request_with_rc4_encryption/) | [Kerberoasting](/tags/#kerberoasting), [Steal or Forge Kerberos Tickets](/tags/#steal-or-forge-kerberos-tickets) | TTP |
| [Known Services Killed by Ransomware](/endpoint/known_services_killed_by_ransomware/) | [Inhibit System Recovery](/tags/#inhibit-system-recovery) | TTP |
@@ -371,9 +375,12 @@ sidebar:
| [Kubernetes Nginx Ingress RFI](/cloud/kubernetes_nginx_ingress_rfi/) | [Exploitation for Credential Access](/tags/#exploitation-for-credential-access) | TTP |
| [Kubernetes Scanner Image Pulling](/cloud/kubernetes_scanner_image_pulling/) | [Cloud Service Discovery](/tags/#cloud-service-discovery) | TTP |
| [Large Volume of DNS ANY Queries](/network/large_volume_of_dns_any_queries/) | [Network Denial of Service](/tags/#network-denial-of-service), [Reflection Amplification](/tags/#reflection-amplification) | Anomaly |
| [Linux Java Spawning Shell](/endpoint/linux_java_spawning_shell/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | TTP |
| [Loading Of Dynwrapx Module](/endpoint/loading_of_dynwrapx_module/) | [Process Injection](/tags/#process-injection), [Dynamic-link Library Injection](/tags/#dynamic-link-library-injection) | TTP |
| [Local Account Discovery With Wmic](/endpoint/local_account_discovery_with_wmic/) | [Account Discovery](/tags/#account-discovery), [Local Account](/tags/#local-account) | Hunting |
| [Local Account Discovery with Net](/endpoint/local_account_discovery_with_net/) | [Account Discovery](/tags/#account-discovery), [Local Account](/tags/#local-account) | Hunting |
| [Log4Shell JNDI Payload Injection Attempt](/web/log4shell_jndi_payload_injection_attempt/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | Anomaly |
| [Log4Shell JNDI Payload Injection with Outbound Connection](/web/log4shell_jndi_payload_injection_with_outbound_connection/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | Anomaly |
| [Logon Script Event Trigger Execution](/endpoint/logon_script_event_trigger_execution/) | [Boot or Logon Initialization Scripts](/tags/#boot-or-logon-initialization-scripts), [Logon Script (Windows)](/tags/#logon-script-(windows)) | TTP |
| [MS Scripting Process Loading Ldap Module](/endpoint/ms_scripting_process_loading_ldap_module/) | [Command and Scripting Interpreter](/tags/#command-and-scripting-interpreter), [JavaScript](/tags/#javascript) | Anomaly |
| [MS Scripting Process Loading WMI Module](/endpoint/ms_scripting_process_loading_wmi_module/) | [Command and Scripting Interpreter](/tags/#command-and-scripting-interpreter), [JavaScript](/tags/#javascript) | Anomaly |
@@ -448,6 +455,7 @@ sidebar:
| [Okta Account Lockout Events](/application/okta_account_lockout_events/) | [Valid Accounts](/tags/#valid-accounts), [Default Accounts](/tags/#default-accounts) | Anomaly |
| [Okta Failed SSO Attempts](/application/okta_failed_sso_attempts/) | [Valid Accounts](/tags/#valid-accounts), [Default Accounts](/tags/#default-accounts) | Anomaly |
| [Okta User Logins From Multiple Cities](/application/okta_user_logins_from_multiple_cities/) | [Valid Accounts](/tags/#valid-accounts), [Default Accounts](/tags/#default-accounts) | Anomaly |
| [Outbound Network Connection from Java Using Default Ports](/endpoint/outbound_network_connection_from_java_using_default_ports/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | TTP |
| [Overwriting Accessibility Binaries](/endpoint/overwriting_accessibility_binaries/) | [Event Triggered Execution](/tags/#event-triggered-execution), [Accessibility Features](/tags/#accessibility-features) | TTP |
| [Password Policy Discovery with Net](/endpoint/password_policy_discovery_with_net/) | [Password Policy Discovery](/tags/#password-policy-discovery) | Hunting |
| [Permission Modification using Takeown App](/endpoint/permission_modification_using_takeown_app/) | [File and Directory Permissions Modification](/tags/#file-and-directory-permissions-modification) | TTP |
@@ -658,6 +666,7 @@ sidebar:
| [Wermgr Process Spawned CMD Or Powershell Process](/endpoint/wermgr_process_spawned_cmd_or_powershell_process/) | [Command and Scripting Interpreter](/tags/#command-and-scripting-interpreter) | TTP |
| [WevtUtil Usage To Clear Logs](/endpoint/wevtutil_usage_to_clear_logs/) | [Indicator Removal on Host](/tags/#indicator-removal-on-host), [Clear Windows Event Logs](/tags/#clear-windows-event-logs) | TTP |
| [Wevtutil Usage To Disable Logs](/endpoint/wevtutil_usage_to_disable_logs/) | [Indicator Removal on Host](/tags/#indicator-removal-on-host), [Clear Windows Event Logs](/tags/#clear-windows-event-logs) | TTP |
| [Wget Download and Bash Execution](/endpoint/wget_download_and_bash_execution/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [WinEvent Scheduled Task Created Within Public Path](/endpoint/winevent_scheduled_task_created_within_public_path/) | [Scheduled Task](/tags/#scheduled-task), [Scheduled Task/Job](/tags/#scheduled-task/job) | TTP |
| [WinEvent Scheduled Task Created to Spawn Shell](/endpoint/winevent_scheduled_task_created_to_spawn_shell/) | [Scheduled Task](/tags/#scheduled-task), [Scheduled Task/Job](/tags/#scheduled-task/job) | TTP |
| [WinEvent Windows Task Scheduler Event Action Started](/endpoint/winevent_windows_task_scheduler_event_action_started/) | [Scheduled Task](/tags/#scheduled-task) | Hunting |
@@ -675,6 +684,7 @@ sidebar:
| [Windows InstallUtil URL in Command Line](/endpoint/windows_installutil_url_in_command_line/) | [InstallUtil](/tags/#installutil), [Signed Binary Proxy Execution](/tags/#signed-binary-proxy-execution) | TTP |
| [Windows InstallUtil Uninstall Option](/endpoint/windows_installutil_uninstall_option/) | [InstallUtil](/tags/#installutil), [Signed Binary Proxy Execution](/tags/#signed-binary-proxy-execution) | TTP |
| [Windows InstallUtil Uninstall Option with Network](/endpoint/windows_installutil_uninstall_option_with_network/) | [InstallUtil](/tags/#installutil), [Signed Binary Proxy Execution](/tags/#signed-binary-proxy-execution) | TTP |
| [Windows Java Spawning Shells](/endpoint/windows_java_spawning_shells/) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | TTP |
| [Windows Security Account Manager Stopped](/endpoint/windows_security_account_manager_stopped/) | [Service Stop](/tags/#service-stop) | TTP |
| [Windows Service Created With Suspicious Service Path](/endpoint/windows_service_created_with_suspicious_service_path/) | [System Services](/tags/#system-services), [Service Execution](/tags/#service-execution) | TTP |
| [Windows Service Created Within Public Path](/endpoint/windows_service_created_within_public_path/) | [Create or Modify System Process](/tags/#create-or-modify-system-process), [Windows Service](/tags/#windows-service) | TTP |
+8
View File
@@ -13,6 +13,14 @@ sidebar:
| [Active Directory Reset password](/playbooks/active_directory_reset_password/)| None | Response |
| [Crowdstrike Malware Triage](/playbooks/crowdstrike_malware_triage/)| None | Response |
| [Delete Detected Files](/playbooks/delete_detected_files/)|[Executable File Written in Administrative SMB Share](/detections/TTP/executable_file_written_in_administrative_smb_share)| Response |
| [Internal Host SSH Investigate](/playbooks/internal_host_ssh_investigate/)| None | Investigate |
| [Internal Host SSH Log4j Investigate](/playbooks/internal_host_ssh_log4j_investigate/)| None | Investigate |
| [Internal Host SSH Log4j Respond](/playbooks/internal_host_ssh_log4j_respond/)| None | Respond |
| [Internal Host WinRM Investigate](/playbooks/internal_host_winrm_investigate/)| None | Investigate |
| [Internal Host WinRM Log4j Investigate](/playbooks/internal_host_winrm_log4j_investigate/)| None | Investigate |
| [Internal Host WinRM Response](/playbooks/internal_host_winrm_response/)| None | Investigate |
| [Log4j Investigate and Respond](/playbooks/log4j_investigate_and_respond/)|[Curl Download and Bash Execution](/detections/TTP/curl_download_and_bash_execution)[Wget Download and Bash Execution](/detections/TTP/wget_download_and_bash_execution)[Linux Java Spawning Shell](/detections/TTP/linux_java_spawning_shell)[Java Class File download by Java User Agent](/detections/TTP/java_class_file_download_by_java_user_agent)[Outbound Network Connection from Java Using Default Ports](/detections/TTP/outbound_network_connection_from_java_using_default_ports)[Log4Shell JNDI Payload Injection Attempt](/detections/Anomaly/log4shell_jndi_payload_injection_attempt)[Log4Shell JNDI Payload Injection with Outbound Connection](/detections/Anomaly/log4shell_jndi_payload_injection_with_outbound_connection)[Detect Outbound LDAP Traffic](/detections/Hunting/detect_outbound_ldap_traffic)| Investigate |
| [Log4j Splunk Investigate And Respond](/playbooks/log4j_splunk_investigate_and_respond/)| None | Investigation |
| [Ransomware Investigate and Contain](/playbooks/ransomware_investigate_and_contain/)|[Conti Common Exec parameter](/detections/TTP/conti_common_exec_parameter)| Response |
| [Risk Notable Block Indicators](/playbooks/risk_notable_block_indicators/)| None | Response |
| [Risk Notable Enrich](/playbooks/risk_notable_enrich/)| None | Investigation |
+1
View File
@@ -57,6 +57,7 @@ sidebar:
| [JBoss Vulnerability](jboss_vulnerability) | [System Information Discovery](/tags/#system-information-discovery) | [Discovery](/tags/#discovery) |
| [Kubernetes Scanning Activity](kubernetes_scanning_activity) | [Cloud Service Discovery](/tags/#cloud-service-discovery) | [Discovery](/tags/#discovery) |
| [Kubernetes Sensitive Object Access Activity]() | None | None |
| [Log4Shell CVE-2021-44228](log4shell_cve-2021-44228) | [Exploit Public-Facing Application](/tags/#exploit-public-facing-application) | [Initial Access](/tags/#initial-access) |
| [Malicious PowerShell](malicious_powershell) | [Gather Victim Host Information](/tags/#gather-victim-host-information) | [Reconnaissance](/tags/#reconnaissance) |
| [Masquerading - Rename System Utilities](masquerading_-_rename_system_utilities) | [Masquerading](/tags/#masquerading), [Rename System Utilities](/tags/#rename-system-utilities) | [Defense Evasion](/tags/#defense-evasion) |
| [Meterpreter](meterpreter) | [System Owner/User Discovery](/tags/#system-owner/user-discovery) | [Discovery](/tags/#discovery) |
+10
View File
@@ -291,6 +291,8 @@ This playbook acts upon events where a file has been determined to be malicious
@@ -704,6 +706,14 @@ This playbook acts upon events where a file has been determined to be malicious
@@ -0,0 +1,44 @@
---
title: "Internal Host SSH Investigate"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Investigate
- Splunk SOAR
- SSH
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting generic information about the processes, user activity, and network activity. This includes the process list, login history, cron jobs, and open sockets. The results are zipped up in .csv files and added to the vault for an analyst to review.
- **Type**: Investigate
- **Product**: Splunk SOAR
- **Apps**: [SSH](https://splunkbase.splunk.com/apps/#/search/SSH/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Philip Royer, Splunk
- **ID**: fdb65816-6688-41d8-8698-755b7b4ec44e
#### Associated Detections
#### How To Implement
The ssh asset requires sudo access to view the processes with open sockets.
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_ssh_investigate.png)
#### Required field
#### Reference
* [https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh](https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh)
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_ssh_investigate.yml) \| *version*: **1**
@@ -0,0 +1,44 @@
---
title: "Internal Host SSH Log4j Respond"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Respond
- Splunk SOAR
- SSH
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
- **Type**: Respond
- **Product**: Splunk SOAR
- **Apps**: [SSH](https://splunkbase.splunk.com/apps/#/search/SSH/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Kelby Shelton, Splunk
- **ID**: 6ea2007c-8ef8-4647-a4a4-7825cfee3866
#### Associated Detections
#### How To Implement
The ssh asset may require ssh access to delete some files depending on their permissions.
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_ssh_log4j_respond.png)
#### Required field
#### Reference
* [https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh](https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh)
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_ssh_log4j_respond.yml) \| *version*: **1**
@@ -0,0 +1,41 @@
---
title: "Internal Host WinRM Investigate"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Investigate
- Splunk SOAR
- Windows Remote Management
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Performs a general investigation on key aspects of a windows device using windows remote management. Important files related to the endpoint are generated, bundled into a zip, and copied to the container vault.
- **Type**: Investigate
- **Product**: Splunk SOAR
- **Apps**: [Windows Remote Management](https://splunkbase.splunk.com/apps/#/search/Windows Remote Management/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Kelby Shelton, Splunk
- **ID**: 32fd9db5-5201-4a2f-b2c2-9299c7b3495d
#### Associated Detections
#### How To Implement
The winrm asset requires Administrator access to gather certain files.
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_winrm_investigate.png)
#### Required field
#### Reference
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_winrm_investigate.yml) \| *version*: **1**
@@ -0,0 +1,44 @@
---
title: "Internal Host WinRM Log4j Investigate"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Investigate
- Splunk SOAR
- Windows Remote Management
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Published in response to CVE-2021-44228, this playbook uses WinRM to scan Windows endpoints for the presence of &#34;jndilookup.class&#34; in all .jar files. The presence of that string could indicate a log4j vulnerability.
- **Type**: Investigate
- **Product**: Splunk SOAR
- **Apps**: [Windows Remote Management](https://splunkbase.splunk.com/apps/#/search/Windows Remote Management/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Kelby Shelton, Splunk
- **ID**: 2cf7c9f4-b273-44f6-a27c-e0db668ff05a
#### Associated Detections
#### How To Implement
The winrm asset requires Administrator access to scan the whole file system.
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_winrm_log4j_investigate.png)
#### Required field
#### Reference
* [https://twitter.com/CyberRaiju/status/1469505677580124160](https://twitter.com/CyberRaiju/status/1469505677580124160)
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_winrm_log4j_investigate.yml) \| *version*: **1**
@@ -0,0 +1,41 @@
---
title: "Internal Host WinRM Response"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Investigate
- Splunk SOAR
- Windows Remote Management
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
- **Type**: Investigate
- **Product**: Splunk SOAR
- **Apps**: [Windows Remote Management](https://splunkbase.splunk.com/apps/#/search/Windows Remote Management/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Kelby Shelton, Splunk
- **ID**: 32fd9db5-5201-4b2f-b2c2-9299c7b3495d
#### Associated Detections
#### How To Implement
The winrm asset requires Administrator access to gather certain files.
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_winrm_log4j_respond.png)
#### Required field
#### Reference
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_winrm_log4j_respond.yml) \| *version*: **1**
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,46 @@
---
title: "Log4j Splunk Investigate And Respond"
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Investigation
- Splunk SOAR
- Splunk
---
[Try in Splunk SOAR](https://www.splunk.com/en_us/software/splunk-security-orchestration-and-automation.html){: .btn .btn--success}
#### Description
Published in response to CVE-2021-44228, this playbook utilizes data already in your Splunk environment to help investigate and remediate impacts caused by this vulnerability in your environment.
- **Type**: Investigation
- **Product**: Splunk SOAR
- **Apps**: [Splunk](https://splunkbase.splunk.com/apps/#/search/Splunk/product/soar)
- **Last Updated**: 2021-12-14
- **Author**: Lou Stella, Splunk
- **ID**: fc0adc66-ff2b-48b0-9a6f-63da6783fd63
#### Associated Detections
#### How To Implement
This playbook presumes you have Enterprise Security and have configured Assets &amp; Identities, as well as the Endpoint.Processes datamodel
#### Playbooks
![](https://raw.githubusercontent.com/splunk/security_content/develop/playbooks/internal_host_splunk_investigate_log4j.png)
#### Required field
* hostName
* destinationAddress
#### Reference
* [https://www.splunk.com/en_us/blog/security/log-jammin-log4j-2-rce.html](https://www.splunk.com/en_us/blog/security/log-jammin-log4j-2-rce.html)
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_splunk_investigate_log4j.yml) \| *version*: **1**
@@ -706,6 +706,16 @@ This playbook investigates and contains ransomware detected on endpoints.
+3 -3
View File
@@ -26,9 +26,9 @@ This playbook gathers all of the events associated with the risk notable and imp
#### How To Implement
&#39;The Splunk search used to locate contributing events requires three fields in the notable artifact\: risk_object, info_min_time, and info_max_time. The query also performs some deduplication on contributing events and may need to be adjusted based on individual Enterprise Security environments. Mitre Tactics and Techniques appear if using the annotation framework in Splunk ES.&#34;
index=risk risk_object=\&#34;{0}\&#34; earliest=\&#34;{1}\&#34; latest=&#34;{2}\&#34; | rex field=source \&#34;.*-\s(?&lt;source&gt;.*)\s+-\s+\w+\s+-\s+Rule\&#34; | fillnull value=\&#34;unknown\&#34; threat_object | eval risk_message=coalesce(risk_message,source) | stats values(*) as * by _time source threat_object risk_message | rename annotations.mitre_attack.mitre_technique_id as mitre_technique_id annotations.mitre_attack.mitre_tactic as mitre_tactic annotations.mitre_attack.mitre_technique as mitre_technique | fields - annotations* risk_object_* date_* orig_* user_* src_user_* src_* dest_* dest_user_* info_* search_* splunk_* tag* risk_modifier* risk_rule* sourcetype timestamp index next_cron_time timeendpos timestartpos testmode linecount | sort + _time | \`uitime(_time)\` | dedup source threat_object
A custom code block sorts the returned event data and produces a markdown formatted note into the note_content output field. This field is then available for use in downstream playbooks.&#34;&#39;
The Splunk search used to locate contributing events requires three fields in the notable artifact\: risk_object, info_min_time, and info_max_time. The query also performs some deduplication on contributing events and may need to be adjusted based on individual Enterprise Security environments. Mitre Tactics and Techniques appear if using the annotation framework in Splunk ES.&#34;
```index=risk risk_object=\&#34;{0}\&#34; earliest=\&#34;{1}\&#34; latest=&#34;{2}\&#34; | rex field=source \&#34;.*-\s(?&lt;source&gt;.*)\s+-\s+\w+\s+-\s+Rule\&#34; | fillnull value=\&#34;unknown\&#34; threat_object | eval risk_message=coalesce(risk_message,source) | stats values(*) as * by _time source threat_object risk_message | rename annotations.mitre_attack.mitre_technique_id as mitre_technique_id annotations.mitre_attack.mitre_tactic as mitre_tactic annotations.mitre_attack.mitre_technique as mitre_technique | fields - annotations* risk_object_* date_* orig_* user_* src_user_* src_* dest_* dest_user_* info_* search_* splunk_* tag* risk_modifier* risk_rule* sourcetype timestamp index next_cron_time timeendpos timestartpos testmode linecount | sort + _time | `uitime(_time)` | dedup source threat_object```
A custom code block sorts the returned event data and produces a markdown formatted note into the note_content output field. This field is then available for use in downstream playbooks.&#34;
#### Playbooks
@@ -14,6 +14,7 @@ tags:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
@@ -55,6 +56,7 @@ The following analytic identifies the use of PowerShell downloading a file using
#### Associated Analytic Story
* [Malicious PowerShell](/stories/malicious_powershell)
* [Ingress Tool Transfer](/stories/ingress_tool_transfer)
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
@@ -91,6 +93,13 @@ False positives may be present and filtering will need to occur by parent proces
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
@@ -14,6 +14,7 @@ tags:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
@@ -61,6 +62,7 @@ The following hunting analytic identifies PowerShell commands utilizing the Wind
* [Malicious PowerShell](/stories/malicious_powershell)
* [Possible Backdoor Activity Associated With MUDCARP Espionage Campaigns](/stories/possible_backdoor_activity_associated_with_mudcarp_espionage_campaigns)
* [HAFNIUM Group](/stories/hafnium_group)
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
@@ -92,6 +94,13 @@ Legitimate process can have this combination of command-line options, but it&#39
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
@@ -99,6 +108,7 @@ Legitimate process can have this combination of command-line options, but it&#39
* [https://github.com/redcanaryco/AtomicTestHarnesses/blob/master/TestHarnesses/T1059.001_PowerShell/OutPowerShellCommandLineParameter.ps1](https://github.com/redcanaryco/AtomicTestHarnesses/blob/master/TestHarnesses/T1059.001_PowerShell/OutPowerShellCommandLineParameter.ps1)
* [https://ss64.com/ps/powershell.html](https://ss64.com/ps/powershell.html)
* [https://twitter.com/M_haggis/status/1440758396534214658?s=20](https://twitter.com/M_haggis/status/1440758396534214658?s=20)
* [https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/](https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/)
@@ -0,0 +1,115 @@
---
title: "Curl Download and Bash Execution"
excerpt: "Ingress Tool Transfer"
categories:
- Endpoint
last_modified_at: 2021-12-10
toc: true
toc_label: ""
tags:
- Ingress Tool Transfer
- Command And Control
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
The following analytic identifies the use of curl on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Endpoint](https://docs.splunk.com/Documentation/CIM/latest/User/Endpoint)
- **Last Updated**: 2021-12-10
- **Author**: Michael Haag, Splunk
- **ID**: 900bc324-59f3-11ec-9fb4-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1105](https://attack.mitre.org/techniques/T1105/) | Ingress Tool Transfer | Command And Control |
#### Search
```
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.process_name=curl (Processes.process="*-s *") OR (Processes.process="*
|*" AND Processes.process="*bash*") by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `curl_download_and_bash_execution_filter`
```
#### Associated Analytic Story
* [Ingress Tool Transfer](/stories/ingress_tool_transfer)
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required. Add parent process name (Processes.parent_process_name) as needed to filter.
#### Required field
* _time
* Processes.dest
* Processes.user
* Processes.parent_process_name
* Processes.parent_process
* Processes.process_name
* Processes.process
* Processes.process_id
* Processes.parent_process_path
* Processes.process_path
* Processes.parent_process_id
#### Kill Chain Phase
* Exploitation
#### Known False Positives
False positives should be limited, however filtering may be required.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 80.0 | 80 | 100 | An instance of $process_name$ was identified on endpoint $dest$ attempting to download a remote file and run it with bash. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java](https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java)
* [https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)
* [https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890](https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/curl_download_and_bash_execution.yml) \| *version*: **1**
@@ -0,0 +1,115 @@
---
title: "Wget Download and Bash Execution"
excerpt: "Ingress Tool Transfer"
categories:
- Endpoint
last_modified_at: 2021-12-11
toc: true
toc_label: ""
tags:
- Ingress Tool Transfer
- Command And Control
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
The following analytic identifies the use of wget on Linux or MacOS attempting to download a file from a remote source and pipe it to bash. This is typically found with coinminers and most recently with CVE-2021-44228, a vulnerability in Log4j.
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Endpoint](https://docs.splunk.com/Documentation/CIM/latest/User/Endpoint)
- **Last Updated**: 2021-12-11
- **Author**: Michael Haag, Splunk
- **ID**: 35682718-5a85-11ec-b8f7-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1105](https://attack.mitre.org/techniques/T1105/) | Ingress Tool Transfer | Command And Control |
#### Search
```
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.process_name=wget (Processes.process="*-q *" OR Processes.process="*--quiet*" AND Processes.process="*-O- *") OR (Processes.process="*
|*" AND Processes.process="*bash*") by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `wget_download_and_bash_execution_filter`
```
#### Associated Analytic Story
* [Ingress Tool Transfer](/stories/ingress_tool_transfer)
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. If the EDR is not parsing the pipe bash in the command-line, modifying the analytic will be required. Add parent process name (Processes.parent_process_name) as needed to filter.
#### Required field
* _time
* Processes.dest
* Processes.user
* Processes.parent_process_name
* Processes.parent_process
* Processes.process_name
* Processes.process
* Processes.process_id
* Processes.parent_process_path
* Processes.process_path
* Processes.parent_process_id
#### Kill Chain Phase
* Exploitation
#### Known False Positives
False positives should be limited, however filtering may be required.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 80.0 | 80 | 100 | An instance of $process_name$ was identified on endpoint $dest$ attempting to download a remote file and run it with bash. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java](https://www.huntress.com/blog/rapid-response-critical-rce-vulnerability-is-affecting-java)
* [https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)
* [https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890](https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/wget_download_and_bash_execution.yml) \| *version*: **1**
@@ -3,7 +3,7 @@ title: "CMD Carry Out String Command Parameter"
excerpt: "Windows Command Shell, Command and Scripting Interpreter"
categories:
- Endpoint
last_modified_at: 2021-10-21
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
@@ -14,6 +14,7 @@ tags:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
@@ -23,13 +24,13 @@ tags:
#### Description
This search looks for command-line arguments where `cmd.exe /c` is used to execute a program. This technique is commonly seen in adversaries and malware to execute batch command using different shell like powershell or different process other than cmd.exe. This is a good hunting query for suspicious commandline made by a script or relative process execute it.
The following analytic identifies command-line arguments where `cmd.exe /c` is used to execute a program. `cmd /c` is used to run commands in MS-DOS and terminate after command or process completion. This technique is commonly seen in adversaries and malware to execute batch command using different shell like PowerShell or different process other than `cmd.exe`. This is a good hunting query for suspicious command-line made by a script or relative process execute it.
- **Type**: Hunting
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Endpoint](https://docs.splunk.com/Documentation/CIM/latest/User/Endpoint)
- **Last Updated**: 2021-10-21
- **Author**: Teoderick Contreras, Splunk, Bhavin Patel, Splunk
- **Last Updated**: 2021-12-13
- **Author**: Teoderick Contreras, Bhavin Patel, Splunk
- **ID**: 54a6ed00-3256-11ec-b031-acde48001122
@@ -54,10 +55,11 @@ This search looks for command-line arguments where `cmd.exe /c` is used to execu
#### Associated Analytic Story
* [IcedID](/stories/icedid)
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon, you must have at least version 6.0.4 of the Sysmon TA.
To successfully implement this search you need to be ingesting information on process that include the name of the process responsible for the changes from your endpoints into the `Endpoint` datamodel in the `Processes` node. In addition, confirm the latest CIM App 4.20 or higher is installed and the latest TA for the endpoint product.
#### Required field
* _time
@@ -77,17 +79,24 @@ To successfully implement this search, you need to be ingesting logs with the pr
#### Known False Positives
unknown
False positives may be high based on legitimate scripted code in any environment. Filter as needed.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 30.0 | 60 | 50 | $process_name$ with commandline $process$ in $dest$ |
| 30.0 | 60 | 50 | An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ by user $user$ attempting spawn a new process. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
@@ -103,4 +112,4 @@ Alternatively you can replay a dataset into a [Splunk Attack Range](https://gith
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/cmd_carry_out_string_command_parameter.yml) \| *version*: **1**
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/cmd_carry_out_string_command_parameter.yml) \| *version*: **2**
@@ -0,0 +1,110 @@
---
title: "Detect Outbound LDAP Traffic"
excerpt: "Exploit Public-Facing Application, Command and Scripting Interpreter"
categories:
- Network
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Command and Scripting Interpreter
- Execution
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Network_Traffic
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
Malicious actors often abuse misconfigured LDAP servers or applications that use the LDAP servers in organizations. Outbound LDAP traffic should not be allowed outbound through your perimeter firewall. This search will help determine if you have any LDAP connections to IP addresses outside of private (RFC1918) address space.
- **Type**: Hunting
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Network_Traffic](https://docs.splunk.com/Documentation/CIM/latest/User/NetworkTraffic)
- **Last Updated**: 2021-12-13
- **Author**: Bhavin Patel, Johan Bjerke, Splunk
- **ID**: c77162d3-f91c-45cc-80c8-22f6v546119f
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
| [T1059](https://attack.mitre.org/techniques/T1059/) | Command and Scripting Interpreter | Execution |
#### Search
```
| tstats earliest(_time) as earliest_time latest(_time) as latest_time values(All_Traffic.dest_ip) as dest_ip from datamodel=Network_Traffic.All_Traffic where All_Traffic.dest_port = 389 OR All_Traffic.dest_port = 636 AND NOT (All_Traffic.dest_ip = 10.0.0.0/8 OR All_Traffic.dest_ip=192.168.0.0/16 OR All_Traffic.dest_ip = 172.16.0.0/12) by All_Traffic.src_ip All_Traffic.dest_ip
|`drop_dm_object_name("All_Traffic")`
| where src_ip != dest_ip
| `security_content_ctime(latest_time)`
| `security_content_ctime(earliest_time)`
|`detect_outbound_ldap_traffic_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
You must be ingesting Zeek DNS and Zeek Conn data into Splunk. Zeek data should also be getting ingested in JSON format and should be mapped to the Network Traffic datamodels that are in use for this search.
#### Required field
* _time
* All_Traffic.dest_ip
* All_Traffic.dest_port
* All_Traffic.src_ip
#### Kill Chain Phase
* Command and Control
* Actions on Objectives
#### Known False Positives
Unknown at this moment. Outbound LDAP traffic should not be allowed outbound through your perimeter firewall. Please check those servers to verify if the activity is legitimate.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 56.0 | 70 | 80 | An outbound LDAP connection from $src_ip$ in your infrastructure connecting to dest ip $dest_ip$ |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.govcert.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/](https://www.govcert.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_ldap/bro_conn.json](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_ldap/bro_conn.json)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/network/detect_outbound_ldap_traffic.yml) \| *version*: **1**
@@ -0,0 +1,107 @@
---
title: "Java Class File download by Java User Agent"
excerpt: "Exploit Public-Facing Application"
categories:
- Endpoint
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Web
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
The following analytic identifies a Java user agent performing a GET request for a .class file from the remote site. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell).
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Web](https://docs.splunk.com/Documentation/CIM/latest/User/Web)
- **Last Updated**: 2021-12-13
- **Author**: Michael Haag, Splunk
- **ID**: 8281ce42-5c50-11ec-82d2-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
| tstats count from datamodel=Web where Web.http_user_agent="*Java*" Web.http_method="GET" Web.url="*.class*" by Web.http_user_agent Web.http_method, Web.url,Web.url_length Web.src, Web.dest
| `drop_dm_object_name("Web")`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `java_class_file_download_by_java_user_agent_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting web or proxy logs, or ensure it is being filled by a proxy like device, into the Web Datamodel. For additional filtering, allow list private IP space or restrict by known good.
#### Required field
* _time
* Web.http_method
* Web.url
* Web.url_length
* Web.src
* Web.dest
* Web.http_user_agent
#### Kill Chain Phase
* Exploitation
#### Known False Positives
Filtering may be required in some instances, filter as needed.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 40.0 | 80 | 50 | A Java user agent $http_user_agent$ was performing a $http_method$ to retrieve a remote class file. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://arstechnica.com/information-technology/2021/12/as-log4shell-wreaks-havoc-payroll-service-reports-ransomware-attack/](https://arstechnica.com/information-technology/2021/12/as-log4shell-wreaks-havoc-payroll-service-reports-ransomware-attack/)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/java.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/java.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/java_class_file_download_by_java_user_agent.yml) \| *version*: **1**
@@ -0,0 +1,114 @@
---
title: "Linux Java Spawning Shell"
excerpt: "Exploit Public-Facing Application"
categories:
- Endpoint
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
### ⚠️ WARNING THIS IS A EXPERIMENTAL DETECTION
We have not been able to test, simulate or build datasets for it, use at your own risk!
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
The following analytic identifies the process name of Java, Apache, or Tomcat spawning a Linux shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell). The shells included in the macro are &#34;sh&#34;, &#34;ksh&#34;, &#34;zsh&#34;, &#34;bash&#34;, &#34;dash&#34;, &#34;rbash&#34;, &#34;fish&#34;, &#34;csh&#39;, &#34;tcsh&#39;, &#34;ion&#34;, &#34;eshell&#34;. Upon triage, review parallel processes and command-line arguments to determine legitimacy.
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Endpoint](https://docs.splunk.com/Documentation/CIM/latest/User/Endpoint)
- **Last Updated**: 2021-12-13
- **Author**: Michael Haag, Splunk
- **ID**: 7b09db8a-5c20-11ec-9945-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name=java OR Processes.parent_process_name=apache OR Processes.parent_process_name=tomcat `linux_shells` by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `linux_java_spawning_shell_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. If you are using Sysmon for Linux, you will need to ensure mapping is occurring correctly. Ensure EDR product is mapping OS Linux to the datamodel properly. Add any additional java process names for your environment to the analytic as needed.
#### Required field
* _time
* Processes.dest
* Processes.user
* Processes.parent_process_name
* Processes.parent_process
* Processes.original_file_name
* Processes.process_name
* Processes.process
* Processes.process_id
* Processes.parent_process_path
* Processes.process_path
* Processes.parent_process_id
#### Kill Chain Phase
* Exploitation
#### Known False Positives
Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 40.0 | 80 | 50 | An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ spawning a Linux shell, potentially indicative of exploitation. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/](https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/)
* [https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72](https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/experimental/endpoint/linux_java_spawning_shell.yml) \| *version*: **1**
@@ -0,0 +1,118 @@
---
title: "Log4Shell JNDI Payload Injection Attempt"
excerpt: "Exploit Public-Facing Application"
categories:
- Web
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Web
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
CVE-2021-44228 Log4Shell payloads can be injected via various methods, but on of the most common vectors injection is via Web calls. Many of the vulnerable java web applications that are using log4j have a web component to them are specially targets of this injection, specifically projects like Apache Struts, Flink, Druid, and Solr. The exploit is triggered by a LDAP lookup function in the log4j package, its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against vulnerable web applications the invocation can be seen in various part of web logs. Specifically it has been successfully exploited via headers like X-Forwarded-For, User-Agent, Referer, and X-Api-Version. In this detection we first limit the scope of our search to the Web Datamodel and use the `| from datamodel` function to benefit from schema accelerated searching capabilities, mainly because the second part of the detection is pretty heavy, it runs a regex across all _raw events that looks for `${jndi:ldap://` pattern across all potential web fields available to the raw data, like http headers for example. If you see results for this detection, it means that there was a attempt at a injection, which could be a reconnaissance activity or a valid expliotation attempt, but this does not exactly mean that the host was indeed successfully exploited.
- **Type**: Anomaly
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Web](https://docs.splunk.com/Documentation/CIM/latest/User/Web)
- **Last Updated**: 2021-12-13
- **Author**: Jose Hernandez
- **ID**: c184f12e-5c90-11ec-bf1f-497c9a704a72
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
| from datamodel Web.Web
| regex _raw="[jJnNdDiI]{4}(\:
|\%3A
|\/
|\%2F)\w+(\:\/\/
|\%3A\%2F\%2F)(\$\{.*?\}(\.)?)?"
| fillnull
| stats count by action, category, dest, dest_port, http_content_type, http_method, http_referrer, http_user_agent, site, src, url, url_domain, user
| `log4shell_jndi_payload_injection_attempt_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
This detection requires the Web datamodel to be populated from a supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
#### Required field
* action
* category
* dest
* dest_port
* http_content_type
* http_method
* http_referrer
* http_user_agent
* site
* src
* url
* url_domain
* user
#### Kill Chain Phase
* Reconnaissance
* Exploitation
#### Known False Positives
If there is a vulnerablility scannner looking for log4shells this will trigger, otherwise likely to have low false positives.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 15.0 | 50 | 30 | CVE-2021-44228 Log4Shell triggered for host $dest$ |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/web/log4shell_jndi_payload_injection_attempt.yml) \| *version*: **1**
@@ -0,0 +1,125 @@
---
title: "Log4Shell JNDI Payload Injection with Outbound Connection"
excerpt: "Exploit Public-Facing Application"
categories:
- Web
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Network_Traffic
- Web
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
CVE-2021-44228 Log4Shell payloads can be injected via various methods, but on of the most common vectors injection is via Web calls. Many of the vulnerable java web applications that are using log4j have a web component to them are specially targets of this injection, specifically projects like Apache Struts, Flink, Druid, and Solr. The exploit is triggered by a LDAP lookup function in the log4j package, its invocation is similar to `${jndi:ldap://PAYLOAD_INJECTED}`, when executed against vulnerable web applications the invocation can be seen in various part of web logs. Specifically it has been successfully exploited via headers like X-Forwarded-For, User-Agent, Referer, and X-Api-Version. In this detection we match the invocation function with a network connection to a malicious ip address.
- **Type**: Anomaly
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Network_Traffic](https://docs.splunk.com/Documentation/CIM/latest/User/NetworkTraffic), [Web](https://docs.splunk.com/Documentation/CIM/latest/User/Web)
- **Last Updated**: 2021-12-13
- **Author**: Jose Hernandez
- **ID**: 69afee44-5c91-11ec-bf1f-497c9a704a72
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
| from datamodel Web.Web
| rex field=_raw max_match=0 "[jJnNdDiI]{4}(\:
|\%3A
|\/
|\%2F)(?<proto>\w+)(\:\/\/
|\%3A\%2F\%2F)(\$\{.*?\}(\.)?)?(?<affected_host>[a-zA-Z0-9\.\-\_\$]+)"
| join affected_host type=inner [
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Network_Traffic.All_Traffic by All_Traffic.dest
| `drop_dm_object_name(All_Traffic)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| rename dest AS affected_host]
| fillnull
| stats count by action, category, dest, dest_port, http_content_type, http_method, http_referrer, http_user_agent, site, src, url, url_domain, user
| `log4shell_jndi_payload_injection_with_outbound_connection_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
This detection requires the Web datamodel to be populated from a supported Technology Add-On like Splunk for Apache or Splunk for Nginx.
#### Required field
* action
* category
* dest
* dest_port
* http_content_type
* http_method
* http_referrer
* http_user_agent
* site
* src
* url
* url_domain
* user
#### Kill Chain Phase
* Exploitation
#### Known False Positives
If there is a vulnerablility scannner looking for log4shells this will trigger, otherwise likely to have low false positives.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 15.0 | 50 | 30 | CVE-2021-44228 Log4Shell triggered for host $dest$ |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_network_logs/log4j_network_logs.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_network_logs/log4j_network_logs.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/web/log4shell_jndi_payload_injection_with_outbound_connection.yml) \| *version*: **1**
@@ -0,0 +1,106 @@
---
title: "Outbound Network Connection from Java Using Default Ports"
excerpt: "Exploit Public-Facing Application"
categories:
- Endpoint
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
A required step while exploiting the CVE-2021-44228-Log4j vulnerability is that the victim server will perform outbound connections to attacker-controlled infrastructure. This is required as part of the JNDI lookup as well as for retrieving the second stage .class payload. The following analytic identifies the Java process reaching out to default ports used by the LDAP and RMI protocols. This behavior could represent successfull exploitation. Note that adversaries can easily decide to use arbitrary ports for these protocols and potentially bypass this detection.
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**:
- **Last Updated**: 2021-12-13
- **Author**: Mauricio Velazco, Splunk
- **ID**: d2c14d28-5c47-11ec-9892-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
`sysmon` EventCode=3 (process_name=java OR process_name=java.exe) (DestinationPort=389 OR DestinationPort=1389 OR DestinationPort = 1099 )
| rename Computer as dest
| stats count min(_time) as firstTime max(_time) as lastTime by dest, process_name, DestinationPort
| `security_content_ctime(firstTime)`
| `outbound_network_connection_from_java_using_default_ports_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search you need to be ingesting information on process that include the name of the process responsible for the changes from your endpoints into the `Endpoint` datamodel in the `Processes` node.
#### Required field
* _time
* process_name
* EventID
* CommandLine
* Computer
* DestinationPort
* DestinationIp
#### Kill Chain Phase
* Exploitation
#### Known False Positives
Legitimate Java applications may use perform outbound connections to these ports. Filter as needed
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 54.0 | 90 | 60 | Java performed outbound connections to default ports of LDAP or RMI on $dest$ |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)
* [https://www.govcert.admin.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/](https://www.govcert.admin.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_java/linux-sysmon.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_java/linux-sysmon.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/outbound_network_connection_from_java_using_default_ports.yml) \| *version*: **1**
@@ -0,0 +1,114 @@
---
title: "Windows Java Spawning Shells"
excerpt: "Exploit Public-Facing Application"
categories:
- Endpoint
last_modified_at: 2021-12-13
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Endpoint
---
### ⚠️ WARNING THIS IS A EXPERIMENTAL DETECTION
We have not been able to test, simulate or build datasets for it, use at your own risk!
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### Description
The following analytic identifies the process name of java.exe and w3wp.exe spawning a Windows shell. This is potentially indicative of exploitation of the Java application and may be related to current event CVE-2021-44228 (Log4Shell). The shells included in the macro are &#34;cmd.exe&#34;, &#34;powershell.exe&#34;. Upon triage, review parallel processes and command-line arguments to determine legitimacy.
- **Type**: TTP
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Endpoint](https://docs.splunk.com/Documentation/CIM/latest/User/Endpoint)
- **Last Updated**: 2021-12-13
- **Author**: Michael Haag, Splunk
- **ID**: 28c81306-5c47-11ec-bfea-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### Search
```
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name=java.exe OR Processes.parent_process_name=w3wp.exe `windows_shells` by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.process Processes.process_id Processes.parent_process_id
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `windows_java_spawning_shells_filter`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### How To Implement
To successfully implement this search, you need to be ingesting logs with the process name, parent process, and command-line executions from your endpoints. Restrict the analytic to publicly facing endpoints to reduce false positives. Add any additional identified web application process name to the query. Add any further Windows process names to the macro (ex. LOLBins) to further expand this query.
#### Required field
* _time
* Processes.dest
* Processes.user
* Processes.parent_process_name
* Processes.parent_process
* Processes.original_file_name
* Processes.process_name
* Processes.process
* Processes.process_id
* Processes.parent_process_path
* Processes.process_path
* Processes.parent_process_id
#### Kill Chain Phase
* Exploitation
#### Known False Positives
Filtering may be required on internal developer build systems or classify assets as web facing and restrict the analytic based on that.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 40.0 | 80 | 50 | An instance of $parent_process_name$ spawning $process_name$ was identified on endpoint $dest$ spawning a Windows shell, potentially indicative of exploitation. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/](https://blog.netlab.360.com/ten-families-of-malicious-samples-are-spreading-using-the-log4j2-vulnerability-now/)
* [https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72](https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/experimental/endpoint/windows_java_spawning_shells.yml) \| *version*: **1**
@@ -0,0 +1,228 @@
---
title: "Hunting for Log4Shell"
excerpt: "Exploit Public-Facing Application"
categories:
- Endpoint
last_modified_at: 2021-12-14
toc: true
toc_label: ""
tags:
- Exploit Public-Facing Application
- Initial Access
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
- CVE-2021-44228
- Web
---
[Try in Splunk Security Cloud](https://www.splunk.com/en_us/cyber-security.html){: .btn .btn--success}
#### 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 &#34;base&#34; 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.
- **Type**: Hunting
- **Product**: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud
- **Datamodel**: [Web](https://docs.splunk.com/Documentation/CIM/latest/User/Web)
- **Last Updated**: 2021-12-14
- **Author**: Michael Haag, Splunk
- **ID**: 158b68fa-5d1a-11ec-aac8-acde48001122
#### [ATT&CK](https://attack.mitre.org/)
| ID | Technique | Tactic |
| ----------- | ----------- |--------------- |
| [T1190](https://attack.mitre.org/techniques/T1190/) | Exploit Public-Facing Application | Initial Access |
#### 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, "date:") OR match(_raw, "upper:") OR match(_raw, "lower:"),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`
```
#### Associated Analytic Story
* [Log4Shell CVE-2021-44228](/stories/log4shell_cve-2021-44228)
#### 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&#39;s against.
#### Required field
* _time
* Web.http_method
* Web.url
* Web.url_length
* Web.src
* Web.dest
* Web.http_user_agent
* _raw
#### Kill Chain Phase
* Exploitation
#### 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.
#### RBA
| Risk Score | Impact | Confidence | Message |
| ----------- | ----------- |--------------|--------------|
| 40.0 | 80 | 50 | Hunting for Log4Shell exploitation has occurred. |
#### CVE
| ID | Summary | [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) |
| ----------- | ----------- | -------------- |
| [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) | Apache Log4j2 &lt;=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. In previous releases (&gt;2.10) this behavior can be mitigated by setting system property &#34;log4j2.formatMsgNoLookups&#34; to “true” or it can be mitigated in prior releases (&lt;2.10) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). | None |
#### Reference
* [https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72](https://gist.github.com/olafhartong/916ebc673ba066537740164f7e7e1d72)
* [https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b#gistcomment-3994449](https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b#gistcomment-3994449)
* [https://regex101.com/r/OSrm0q/1/](https://regex101.com/r/OSrm0q/1/)
* [https://github.com/Neo23x0/signature-base/blob/master/yara/expl_log4j_cve_2021_44228.yar](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://news.sophos.com/en-us/2021/12/12/log4shell-hell-anatomy-of-an-exploit-outbreak/)
* [https://gist.github.com/MHaggis/1899b8554f38c8692a9fb0ceba60b44c](https://gist.github.com/MHaggis/1899b8554f38c8692a9fb0ceba60b44c)
* [https://twitter.com/sasi2103/status/1469764719850442760?s=20](https://twitter.com/sasi2103/status/1469764719850442760?s=20)
#### Test Dataset
Replay any dataset to Splunk Enterprise by using our [`replay.py`](https://github.com/splunk/attack_data#using-replaypy) tool or the [UI](https://github.com/splunk/attack_data#using-ui).
Alternatively you can replay a dataset into a [Splunk Attack Range](https://github.com/splunk/attack_range#replay-dumps-into-attack-range-splunk-server)
* [https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/log4shell-nginx.log](https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/log4shell-nginx.log)
[*source*](https://github.com/splunk/security_content/tree/develop/detections/endpoint/hunting_for_log4shell.yml) \| *version*: **1**
+2
View File
@@ -36,7 +36,9 @@ Ingress tool transfer is a Technique under tactic Command and Control. Behaviors
| [BITSAdmin Download File](/endpoint/bitsadmin_download_file/) | [BITS Jobs](/tags/#bits-jobs), [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [CertUtil Download With URLCache and Split Arguments](/endpoint/certutil_download_with_urlcache_and_split_arguments/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [CertUtil Download With VerifyCtl and Split Arguments](/endpoint/certutil_download_with_verifyctl_and_split_arguments/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Curl Download and Bash Execution](/endpoint/curl_download_and_bash_execution/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Suspicious Curl Network Connection](/endpoint/suspicious_curl_network_connection/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Wget Download and Bash Execution](/endpoint/wget_download_and_bash_execution/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Windows Curl Download to Suspicious Path](/endpoint/windows_curl_download_to_suspicious_path/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Windows Curl Upload to Remote Destination](/endpoint/windows_curl_upload_to_remote_destination/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
| [Windows Curl Upload to Remote Destination](/endpoint/windows_curl_upload_to_remote_destination/) | [Ingress Tool Transfer](/tags/#ingress-tool-transfer) | TTP |
+4 -4
View File
@@ -9,26 +9,26 @@ header:
actions:
- label: "Download"
url: "https://splunkbase.splunk.com/app/3449/"
excerpt: "Get the latest **FREE** Enterprise Security Content Update (ESCU) App with **686** detections for Splunk."
excerpt: "Get the latest **FREE** Enterprise Security Content Update (ESCU) App with **696** detections for Splunk."
feature_row:
- image_path: /static/feature_detection.png
alt: "customizable"
title: "Detections"
excerpt: "See all **686** Splunk Analytics built to find evil 😈."
excerpt: "See all **696** Splunk Analytics built to find evil 😈."
url: "/detections"
btn_class: "btn--primary"
btn_label: "Explore"
- image_path: /static/feature_stories.png
alt: "fully responsive"
title: "Analytic Stories"
excerpt: "See all **106** use cases, 📦 of detections built to address a threat."
excerpt: "See all **107** use cases, 📦 of detections built to address a threat."
url: "/stories"
btn_class: "btn--primary"
btn_label: "Explore"
- image_path: /static/feature_playbooks.png
alt: "100% free"
title: "Playbooks"
excerpt: "See all **14** sets of steps 🐾 to automatically response to a threat."
excerpt: "See all **22** sets of steps 🐾 to automatically response to a threat."
url: "/playbooks"
btn_class: "btn--primary"
btn_label: "Explore"
+4
View File
@@ -0,0 +1,4 @@
definition: (Processes.process_name IN ("sh", "ksh", "zsh", "bash", "dash", "rbash", "fish", "csh', "tcsh', "ion", "eshell"))
description: customer specific splunk configurations(eg- index, source, sourcetype).
Replace the macro definition with configurations for your Splunk Environmnent.
name: linux_shells
+1 -1
View File
@@ -1,4 +1,4 @@
definition: sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational
definition: sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational OR source=Syslog:Linux-Sysmon/Operational
description: customer specific splunk configurations(eg- index, source, sourcetype).
Replace the macro definition with configurations for your Splunk Environmnent.
name: sysmon
+4
View File
@@ -0,0 +1,4 @@
definition: (Processes.process_name=cmd.exe OR Processes.process_name=powershell.exe)
description: customer specific splunk configurations(eg- index, source, sourcetype).
Replace the macro definition with configurations for your Splunk Environmnent.
name: windows_shells
@@ -0,0 +1,378 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Threat Response",
"coa": {
"data": {
"description": "Published in response to CVE-2021-44228, this playbook utilizes data already in your Splunk environment to help investigate and remediate impacts caused by this vulnerability in your environment.",
"edges": [
{
"id": "port_6_to_port_11",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "11",
"targetPort": "11_in"
},
{
"id": "port_7_to_port_12",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "12",
"targetPort": "12_in"
},
{
"id": "port_8_to_port_13",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "13",
"targetPort": "13_in"
},
{
"id": "port_10_to_port_14",
"sourceNode": "10",
"sourcePort": "10_out",
"targetNode": "14",
"targetPort": "14_in"
},
{
"id": "port_0_to_port_6",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_0_to_port_7",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"id": "port_0_to_port_8",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "8",
"targetPort": "8_in"
},
{
"id": "port_0_to_port_10",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "10",
"targetPort": "10_in"
},
{
"id": "port_11_to_port_1",
"sourceNode": "11",
"sourcePort": "11_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_12_to_port_1",
"sourceNode": "12",
"sourcePort": "12_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_13_to_port_1",
"sourceNode": "13",
"sourcePort": "13_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_14_to_port_1",
"sourceNode": "14",
"sourcePort": "14_out",
"targetNode": "1",
"targetPort": "1_in"
}
],
"hash": "b2bce4ea7e2dbaefba3a2b8403baf8d50fe9c488",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 530,
"y": 0
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 530,
"y": 481
},
"10": {
"data": {
"advanced": {
"customName": "ES Assets ",
"customNameId": 0,
"join": [],
"note": "Formatting ES Assets & Identities Search"
},
"functionId": 1,
"functionName": "es_assets",
"id": "10",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\nasset_lookup_by_str | search asset IN (\"{0}\") | eval category = mvjoin(category, \"; \")\n%%",
"type": "format"
},
"errors": {},
"id": "10",
"type": "format",
"x": 1020,
"y": 150
},
"11": {
"data": {
"action": "run query",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "Splunk",
"connectorConfigs": [
"splunk"
],
"connectorId": "91883aa8-9c81-470b-97a1-5d8f7995f560",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "run_query_1",
"id": "11",
"parameters": {
"command": "search",
"query": "get_notable_history:formatted_data.*"
},
"requiredParameters": [
"query"
],
"type": "action"
},
"errors": {},
"id": "11",
"type": "action",
"userCode": "\n parameters = []\n phantom.debug(get_notable_history__as_list)\n for formatted_item in get_notable_history__as_list:\n parameters.append({\n \"query\": formatted_item,\n \"command\": \"search\",\n })\n\n",
"x": 0,
"y": 331
},
"12": {
"data": {
"action": "run query",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "Splunk",
"connectorConfigs": [
"splunk"
],
"connectorId": "91883aa8-9c81-470b-97a1-5d8f7995f560",
"connectorVersion": "v1",
"functionId": 2,
"functionName": "run_query_2",
"id": "12",
"parameters": {
"command": "tstats",
"query": "get_process_info:formatted_data.*"
},
"requiredParameters": [
"query"
],
"type": "action"
},
"errors": {},
"id": "12",
"type": "action",
"userCode": "\n parameters = []\n phantom.debug(get_process_info__as_list)\n for formatted_item in get_process_info__as_list:\n parameters.append({\n \"query\": formatted_item,\n \"command\": \"tstats\",\n })\n \n",
"x": 340,
"y": 331
},
"13": {
"data": {
"action": "run query",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "Splunk",
"connectorConfigs": [
"splunk"
],
"connectorId": "91883aa8-9c81-470b-97a1-5d8f7995f560",
"connectorVersion": "v1",
"functionId": 3,
"functionName": "run_query_3",
"id": "13",
"parameters": {
"command": "tstats",
"query": "get_children_of_java:formatted_data.*"
},
"requiredParameters": [
"query"
],
"type": "action"
},
"errors": {},
"id": "13",
"type": "action",
"userCode": "\n\n parameters = []\n phantom.debug(get_children_of_java__as_list)\n for formatted_item in get_children_of_java__as_list:\n parameters.append({\n \"query\": formatted_item,\n \"command\": \"tstats\",\n })\n \n",
"x": 680,
"y": 331
},
"14": {
"data": {
"action": "run query",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "Splunk",
"connectorConfigs": [
"splunk"
],
"connectorId": "91883aa8-9c81-470b-97a1-5d8f7995f560",
"connectorVersion": "v1",
"functionId": 4,
"functionName": "run_query_4",
"id": "14",
"parameters": {
"command": "| inputlookup",
"query": "es_assets:formatted_data.*"
},
"requiredParameters": [
"query"
],
"type": "action"
},
"errors": {},
"id": "14",
"type": "action",
"userCode": "\n parameters = []\n phantom.debug(es_assets__as_list)\n for formatted_item in es_assets__as_list:\n parameters.append({\n \"query\": formatted_item,\n \"command\": \"| inputlookup\",\n })\n \n",
"x": 1020,
"y": 331
},
"6": {
"data": {
"advanced": {
"customName": "Get Notable History",
"customNameId": 0,
"description": "",
"join": [],
"note": "Formatting Notable History search"
},
"functionId": 2,
"functionName": "get_notable_history",
"id": "6",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\n`notable` | search dest={0} | table _time, dest, rule_name, owner, priority, severity, status_description\n%%",
"type": "format"
},
"errors": {},
"id": "6",
"type": "format",
"userCode": "\n # Write your custom code here...\n\n",
"x": 0,
"y": 150
},
"7": {
"data": {
"advanced": {
"customName": "Get Process Info",
"customNameId": 0,
"description": "",
"join": [],
"note": "Formatting Process info search"
},
"functionId": 3,
"functionName": "get_process_info",
"id": "7",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\n`security_content_summariesonly` count values(Processes.process)\n as process min(_time) as firstTime max(_time) as lastTime FROM datamodel=Endpoint.Processes\n by Processes.user Processes.parent_process_name Processes.process_name Processes.dest\n | `drop_dm_object_name(\"Processes\")` | search process_name= \"*java*\" | search\n dest = {0} | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`\n%%",
"type": "format"
},
"errors": {},
"id": "7",
"type": "format",
"x": 340,
"y": 150
},
"8": {
"data": {
"advanced": {
"customName": "Get Children of Java",
"customNameId": 0,
"join": [],
"note": "Formatting Children of Java search"
},
"functionId": 4,
"functionName": "get_children_of_java",
"id": "8",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\n`security_content_summariesonly` count values(Processes.process)\n as process min(_time) as firstTime max(_time) as lastTime FROM datamodel=Endpoint.Processes\n by Processes.user Processes.parent_process_name Processes.process_name Processes.dest\n | `drop_dm_object_name(\"Processes\")` | search parent_process_name= \"*java*\" | search dest = {0} |`security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`\n%%",
"type": "format"
},
"errors": {},
"id": "8",
"type": "format",
"x": 680,
"y": 150
}
},
"notes": "Deployment Notes: This playbook presumes you have Enterprise Security and have configured Assets and Identities, as well as the Endpoint.Processes datamodel."
},
"input_spec": [
{
"contains": [
"host name",
"ip"
],
"description": "IP address or hostname of the internal host to investigate",
"name": "ip_or_hostname"
}
],
"output_spec": null,
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-15T00:13:52.864984+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"investigate"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

@@ -0,0 +1,300 @@
"""
Published in response to CVE-2021-44228, this playbook utilizes data already in your Splunk environment to help investigate and remediate impacts caused by this vulnerability in your environment.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'get_notable_history' block
get_notable_history(container=container)
# call 'get_process_info' block
get_process_info(container=container)
# call 'get_children_of_java' block
get_children_of_java(container=container)
# call 'es_assets' block
es_assets(container=container)
return
def get_notable_history(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_notable_history() called")
template = """%%\n`notable` | search dest={0} | table _time, dest, rule_name, owner, priority, severity, status_description\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="get_notable_history")
run_query_1(container=container)
return
def get_process_info(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_process_info() called")
template = """%%\n`security_content_summariesonly` count values(Processes.process)\n as process min(_time) as firstTime max(_time) as lastTime FROM datamodel=Endpoint.Processes\n by Processes.user Processes.parent_process_name Processes.process_name Processes.dest\n | `drop_dm_object_name(\"Processes\")` | search process_name= \"*java*\" | search\n dest = {0} | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="get_process_info")
run_query_2(container=container)
return
def get_children_of_java(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_children_of_java() called")
template = """%%\n`security_content_summariesonly` count values(Processes.process)\n as process min(_time) as firstTime max(_time) as lastTime FROM datamodel=Endpoint.Processes\n by Processes.user Processes.parent_process_name Processes.process_name Processes.dest\n | `drop_dm_object_name(\"Processes\")` | search parent_process_name= \"*java*\" | search dest = {0} |`security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="get_children_of_java")
run_query_3(container=container)
return
def es_assets(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("es_assets() called")
template = """%%\nasset_lookup_by_str | search asset IN (\"{0}\") | eval category = mvjoin(category, \"; \")\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="es_assets")
run_query_4(container=container)
return
def run_query_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_query_1() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
get_notable_history__as_list = phantom.get_format_data(name="get_notable_history__as_list")
parameters = []
if get_notable_history__as_list is not None:
parameters.append({
"query": get_notable_history__as_list,
"command": "search",
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
phantom.debug(get_notable_history__as_list)
for formatted_item in get_notable_history__as_list:
parameters.append({
"query": formatted_item,
"command": "search",
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run query", parameters=parameters, name="run_query_1", assets=["splunk"])
return
def run_query_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_query_2() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
get_process_info__as_list = phantom.get_format_data(name="get_process_info__as_list")
parameters = []
if get_process_info__as_list is not None:
parameters.append({
"query": get_process_info__as_list,
"command": "tstats",
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
phantom.debug(get_process_info__as_list)
for formatted_item in get_process_info__as_list:
parameters.append({
"query": formatted_item,
"command": "tstats",
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run query", parameters=parameters, name="run_query_2", assets=["splunk"])
return
def run_query_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_query_3() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
get_children_of_java__as_list = phantom.get_format_data(name="get_children_of_java__as_list")
parameters = []
if get_children_of_java__as_list is not None:
parameters.append({
"query": get_children_of_java__as_list,
"command": "tstats",
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
phantom.debug(get_children_of_java__as_list)
for formatted_item in get_children_of_java__as_list:
parameters.append({
"query": formatted_item,
"command": "tstats",
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run query", parameters=parameters, name="run_query_3", assets=["splunk"])
return
def run_query_4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_query_4() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
es_assets__as_list = phantom.get_format_data(name="es_assets__as_list")
parameters = []
if es_assets__as_list is not None:
parameters.append({
"query": es_assets__as_list,
"command": "| inputlookup",
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
phantom.debug(es_assets__as_list)
for formatted_item in es_assets__as_list:
parameters.append({
"query": formatted_item,
"command": "| inputlookup",
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run query", parameters=parameters, name="run_query_4", assets=["splunk"])
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,23 @@
name: Log4j Splunk Investigate And Respond
id: fc0adc66-ff2b-48b0-9a6f-63da6783fd63
version: 1
date: '2021-12-14'
author: Lou Stella, Splunk
type: Investigation
description: Published in response to CVE-2021-44228, this playbook utilizes data already in your Splunk environment to help investigate and remediate impacts caused by this vulnerability in your environment.
playbook: internal_host_splunk_investigate_log4j
how_to_implement: This playbook presumes you have Enterprise Security and have configured Assets & Identities, as well as the Endpoint.Processes datamodel
references:
- https://www.splunk.com/en_us/blog/security/log-jammin-log4j-2-rce.html
app_list:
- "Splunk"
tags:
analytic_story:
- Log4Shell CVE-2021-44228
platform_tags:
- Response
playbook_fields:
- hostName
- destinationAddress
product:
- Splunk SOAR
@@ -0,0 +1,498 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Use Cases",
"coa": {
"data": {
"description": "Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting generic information about the processes, user activity, and network activity. This includes the process list, login history, cron jobs, and open sockets. The results are zipped up in .csv files and added to the vault for an analyst to review.",
"edges": [
{
"id": "port_0_to_port_2",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "2",
"targetPort": "2_in"
},
{
"id": "port_0_to_port_3",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "3",
"targetPort": "3_in"
},
{
"id": "port_0_to_port_5",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "5",
"targetPort": "5_in"
},
{
"id": "port_0_to_port_6",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_6_to_port_7",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"id": "port_7_to_port_8",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "8",
"targetPort": "8_in"
},
{
"id": "port_8_to_port_9",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "9",
"targetPort": "9_in"
},
{
"id": "port_9_to_port_1",
"sourceNode": "9",
"sourcePort": "9_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_5_to_port_1",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_3_to_port_1",
"sourceNode": "3",
"sourcePort": "3_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_2_to_port_1",
"sourceNode": "2",
"sourcePort": "2_out",
"targetNode": "1",
"targetPort": "1_in"
}
],
"hash": "0da2cbd02719d0f1db566ed2b4c158466d774b17",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 500,
"y": 0
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 500,
"y": 520
},
"2": {
"data": {
"action": "list processes",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_processes_1",
"id": "2",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "2",
"type": "action",
"x": 1080,
"y": 120
},
"3": {
"data": {
"action": "list connections",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_connections_1",
"id": "3",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "3",
"type": "action",
"x": 800,
"y": 120
},
"5": {
"data": {
"action": "list firewall rules",
"actionType": "investigate",
"advanced": {
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_firewall_rules_1",
"id": "5",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "5",
"type": "action",
"x": 160,
"y": 120
},
"6": {
"data": {
"advanced": {
"customName": "write embedded bash script to vault",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "passthrough",
"repoName": "community"
},
"functionId": 1,
"functionName": "write_embedded_bash_script_to_vault",
"id": "6",
"selectMore": false,
"type": "utility",
"utilities": {
"passthrough": {
"description": "Return the inputs as outputs. This is useful for publishing pieces of data for other blocks in the playbook to use.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_1",
"name": "input_1",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_2",
"name": "input_2",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_3",
"name": "input_3",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_4",
"name": "input_4",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_5",
"name": "input_5",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_6",
"name": "input_6",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_7",
"name": "input_7",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_8",
"name": "input_8",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_9",
"name": "input_9",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_10",
"name": "input_10",
"placeholder": "",
"renderType": "datapath",
"required": false
}
],
"label": "passthrough",
"name": "passthrough"
}
},
"utilityType": "custom_function",
"values": {
"passthrough": {
"input_1": null,
"input_10": null,
"input_2": null,
"input_3": null,
"input_4": null,
"input_5": null,
"input_6": null,
"input_7": null,
"input_8": null,
"input_9": null
}
}
},
"errors": {},
"id": "6",
"type": "utility",
"userCode": "\n bash_script = r\"\"\"\n#!/bin/bash\n\n# This script is part of the Splunk SOAR playbook called internal_host_ssh_log4j_investigate. It gathers system information as part of a unix endpoint investigation. The output is a human-readable log and a set of .csv files\n\necho \"##############################################################\"\necho \"splunk_soar_internal_host_ssh_investigate.sh\"\necho \"##############################################################\"\necho \"\"\necho \"[+] Basic system configuration:\"\n\necho \"key,value\" > basic_system_configuration.csv\n\necho \"hostname: $(uname -n | tr -d \"\\n\")\"\necho \"hostname,$(uname -n | tr -d \"\\n\")\" >> basic_system_configuration.csv\n\necho \"current time: $(date +%F_%T)\"\necho \"current time,$(date +%F_%T)\" >> basic_system_configuration.csv\n\necho \"IP address: $(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\\.){3}[0-9]*' | grep -Eo '([0-9]*\\.){3}[0-9]*' | grep -v '127.0.0.1' | tr '\\n' ' ')\"\necho \"IP address,$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\\.){3}[0-9]*' | grep -Eo '([0-9]*\\.){3}[0-9]*' | grep -v '127.0.0.1' | tr '\\n' ' ')\" >> basic_system_configuration.csv\n\necho \"OS release: $(cat /etc/*release | sort -u | tr \"\\n\" \";\")\"\necho \"OS release,$(cat /etc/*release | sort -u | tr \"\\n\" \";\")\" >> basic_system_configuration.csv\n\necho \"OS issue: $(cat /etc/issue)\"\necho \"OS issue,$(cat /etc/issue)\" >> basic_system_configuration.csv\n\necho \"OS kernel: $(uname -a)\"\necho \"OS kernel,$(uname -a)\" >> basic_system_configuration.csv\n\necho \"\"\necho \"USER,PID,%CPU,%MEM,VSZ,RSS,TTY,STAT,START,TIME,COMMAND\" > process_list.csv\necho \"$(ps aux)\" >> process_list.csv\necho \"[+] Process list:\"\necho \"$(ps aux)\"\n\necho \"\"\necho \"UNIT,LOAD,ACTIVE,SUB,DESCRIPTION\" > service_list.csv\necho \"$(systemctl)\" >> service_list.csv\necho \"[+] Service list:\"\necho \"$(systemctl)\"\n\necho \"\"\necho \"$(ss -tunapl)\" > open_sockets.csv\necho \"[+] Open sockets:\"\necho \"$(ss -tunapl)\"\n\necho \"\"\necho \"cron_job\" > cron_jobs.csv\necho \"$(for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null | grep -v '^#'; done)\" >> cron_jobs.csv\necho \"[+] Cron jobs:\"\necho \"$(for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null | grep -v '^#'; done)\"\n\necho \"[+] Zip up the outputs ...\"\nhostname=$1\nzip $(hostname)_ssh_output.zip basic_system_configuration.csv process_list.csv service_list.csv open_sockets.csv cron_jobs.csv\n\"\"\"\n\n file_name = 'splunk_soar_internal_host_ssh_investigate.sh'\n file_path = '/opt/phantom/vault/tmp/{}'.format(file_name)\n with open(file_path, 'w') as bash_script_file:\n bash_script_file.write(bash_script)\n \n success, message, vault_id = phantom.vault_add(file_location=file_path, file_name=file_name)\n parameters = [{'input_1': vault_id}]\n \n",
"x": 480,
"y": 120
},
"7": {
"data": {
"action": "put file",
"actionType": "generic",
"advanced": {
"customName": "upload bash script",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "upload_bash_script",
"id": "7",
"requiredParameters": [
"vault_id",
"ip_hostname",
"file_destination"
],
"type": "action"
},
"errors": {},
"id": "7",
"type": "action",
"x": 480,
"y": 220
},
"8": {
"data": {
"action": "execute program",
"actionType": "generic",
"advanced": {
"customName": "run bash script",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "run_bash_script",
"id": "8",
"requiredParameters": [
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "8",
"type": "action",
"x": 480,
"y": 320
},
"9": {
"data": {
"action": "get file",
"actionType": "investigate",
"advanced": {
"customName": "get output zip file",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "get_output_zip_file",
"id": "9",
"requiredParameters": [
"file_path",
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "9",
"type": "action",
"x": 480,
"y": 420
}
},
"notes": "TODO: last -a login history"
},
"input_spec": [
{
"contains": [
"host name",
"ip"
],
"description": "IP address or hostname of the internal host to investigate",
"name": "ip_or_hostname"
}
],
"output_spec": null,
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-15T01:02:29.241695+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"unix",
"internal_host"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

+304
View File
@@ -0,0 +1,304 @@
"""
Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting generic information about the processes, user activity, and network activity. This includes the process list, login history, cron jobs, and open sockets. The results are zipped up in .csv files and added to the vault for an analyst to review.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'list_processes_1' block
list_processes_1(container=container)
# call 'list_connections_1' block
list_connections_1(container=container)
# call 'list_firewall_rules_1' block
list_firewall_rules_1(container=container)
# call 'write_embedded_bash_script_to_vault' block
write_embedded_bash_script_to_vault(container=container)
return
def list_processes_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_processes_1() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_processes_1' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list processes", parameters=parameters, name="list_processes_1", assets=["ssh"])
return
def list_connections_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_connections_1() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_connections_1' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list connections", parameters=parameters, name="list_connections_1", assets=["ssh"])
return
def list_firewall_rules_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_firewall_rules_1() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_firewall_rules_1' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list firewall rules", parameters=parameters, name="list_firewall_rules_1", assets=["ssh"])
return
def write_embedded_bash_script_to_vault(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("write_embedded_bash_script_to_vault() called")
parameters = []
parameters.append({
"input_1": None,
"input_2": None,
"input_3": None,
"input_4": None,
"input_5": None,
"input_6": None,
"input_7": None,
"input_8": None,
"input_9": None,
"input_10": None,
})
################################################################################
## Custom Code Start
################################################################################
bash_script = r"""
#!/bin/bash
# This script is part of the Splunk SOAR playbook called internal_host_ssh_log4j_investigate. It gathers system information as part of a unix endpoint investigation. The output is a human-readable log and a set of .csv files
echo "##############################################################"
echo "splunk_soar_internal_host_ssh_investigate.sh"
echo "##############################################################"
echo ""
echo "[+] Basic system configuration:"
echo "key,value" > basic_system_configuration.csv
echo "hostname: $(uname -n | tr -d "\n")"
echo "hostname,$(uname -n | tr -d "\n")" >> basic_system_configuration.csv
echo "current time: $(date +%F_%T)"
echo "current time,$(date +%F_%T)" >> basic_system_configuration.csv
echo "IP address: $(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | tr '\n' ' ')"
echo "IP address,$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | tr '\n' ' ')" >> basic_system_configuration.csv
echo "OS release: $(cat /etc/*release | sort -u | tr "\n" ";")"
echo "OS release,$(cat /etc/*release | sort -u | tr "\n" ";")" >> basic_system_configuration.csv
echo "OS issue: $(cat /etc/issue)"
echo "OS issue,$(cat /etc/issue)" >> basic_system_configuration.csv
echo "OS kernel: $(uname -a)"
echo "OS kernel,$(uname -a)" >> basic_system_configuration.csv
echo ""
echo "USER,PID,%CPU,%MEM,VSZ,RSS,TTY,STAT,START,TIME,COMMAND" > process_list.csv
echo "$(ps aux)" >> process_list.csv
echo "[+] Process list:"
echo "$(ps aux)"
echo ""
echo "UNIT,LOAD,ACTIVE,SUB,DESCRIPTION" > service_list.csv
echo "$(systemctl)" >> service_list.csv
echo "[+] Service list:"
echo "$(systemctl)"
echo ""
echo "$(ss -tunapl)" > open_sockets.csv
echo "[+] Open sockets:"
echo "$(ss -tunapl)"
echo ""
echo "cron_job" > cron_jobs.csv
echo "$(for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null | grep -v '^#'; done)" >> cron_jobs.csv
echo "[+] Cron jobs:"
echo "$(for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null | grep -v '^#'; done)"
echo "[+] Zip up the outputs ..."
hostname=$1
zip $(hostname)_ssh_output.zip basic_system_configuration.csv process_list.csv service_list.csv open_sockets.csv cron_jobs.csv
"""
file_name = 'splunk_soar_internal_host_ssh_investigate.sh'
file_path = '/opt/phantom/vault/tmp/{}'.format(file_name)
with open(file_path, 'w') as bash_script_file:
bash_script_file.write(bash_script)
success, message, vault_id = phantom.vault_add(file_location=file_path, file_name=file_name)
parameters = [{'input_1': vault_id}]
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/passthrough", parameters=parameters, name="write_embedded_bash_script_to_vault", callback=upload_bash_script)
return
def upload_bash_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("upload_bash_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
parameters = []
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("put file", parameters=parameters, name="upload_bash_script", assets=["ssh"], callback=run_bash_script)
return
def run_bash_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_bash_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
parameters = []
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="run_bash_script", assets=["ssh"], callback=get_output_zip_file)
return
def get_output_zip_file(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_output_zip_file() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
parameters = []
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("get file", parameters=parameters, name="get_output_zip_file", assets=["ssh"])
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host SSH Investigate
id: fdb65816-6688-41d8-8698-755b7b4ec44e
version: 1
date: '2021-12-14'
author: Philip Royer, Splunk
type: Investigate
description: Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting generic information about the processes, user activity, and network activity. This includes the process list, login history, cron jobs, and open sockets. The results are zipped up in .csv files and added to the vault for an analyst to review.
playbook: internal_host_ssh_investigate
how_to_implement: The ssh asset requires sudo access to view the processes with open sockets.
references: ["https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh"]
app_list:
- "SSH"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
@@ -0,0 +1,382 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Use Cases",
"coa": {
"data": {
"description": "Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting information specific to the December 2021 log4j vulnerability disclosure. This includes the java version installed on the host, any running java processes, and the results of a scan for the affected JndiLookup.class file or log4j .jar files. ",
"edges": [
{
"id": "port_0_to_port_5",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "5",
"targetPort": "5_in"
},
{
"id": "port_5_to_port_7",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"id": "port_7_to_port_6",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_6_to_port_8",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "8",
"targetPort": "8_in"
},
{
"id": "port_8_to_port_1",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "1",
"targetPort": "1_in"
}
],
"hash": "f0f51d60c1f03e0566b642644ddb96be1979fb2e",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 1000,
"y": 419.99999999999966
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 1000,
"y": 1000
},
"5": {
"data": {
"advanced": {
"customName": "write embedded bash script to vault",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "passthrough",
"repoName": "community"
},
"functionId": 3,
"functionName": "write_embedded_bash_script_to_vault",
"id": "5",
"selectMore": false,
"type": "utility",
"utilities": {
"passthrough": {
"description": "Return the inputs as outputs. This is useful for publishing pieces of data for other blocks in the playbook to use.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_1",
"name": "input_1",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_2",
"name": "input_2",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_3",
"name": "input_3",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_4",
"name": "input_4",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_5",
"name": "input_5",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_6",
"name": "input_6",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_7",
"name": "input_7",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_8",
"name": "input_8",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_9",
"name": "input_9",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_10",
"name": "input_10",
"placeholder": "",
"renderType": "datapath",
"required": false
}
],
"label": "passthrough",
"name": "passthrough"
}
},
"utilityType": "custom_function",
"values": {
"passthrough": {
"input_1": null,
"input_10": null,
"input_2": null,
"input_3": null,
"input_4": null,
"input_5": null,
"input_6": null,
"input_7": null,
"input_8": null,
"input_9": null
}
}
},
"errors": {},
"id": "5",
"type": "utility",
"userCode": "\n bash_script = r\"\"\"\n#!/bin/bash\n \n# This script is part of the Splunk SOAR playbook called internal_host_ssh_log4j_investigate. It shows\n# the installed java version, lists any running java processes, performs a search for the JndiLookup.class\n# file in any .jar files found on disk, and searches any .war files for a log4j jar.\n\necho \"##############################################################\"\necho \"splunk_soar_internal_host_ssh_log4j_investigate.sh\"\necho \"##############################################################\"\necho \"\"\n\necho \"java environment configuration\" > java_environment.csv\necho \"[+] Checking Java version:\"\necho \"$(java -version)\"\necho \"java version:\" >> java_environment.csv\njava -version 2>> java_environment.csv\n\necho \"\"\necho \"[+] Checking running Java processes with ps:\"\necho \"$(ps aux | grep java)\"\necho \"ps java processes:\" >> java_environment.csv\necho \"$(ps aux | grep java)\" >> java_environment.csv\n\necho \"\"\necho \"[+] Checking running Java processes with jps:\"\necho \"$(jps -v)\"\necho \"jps java processes:\" >> java_environment.csv\necho \"$(jps -v)\" >> java_environment.csv\n\necho \"[+] Search .jar files for JndiLookup.class files ...\"\necho \"jar_file\" > jars_with_jndi.csv\nfind / 2>/dev/null -name '*.jar' -type f -print0 | xargs -0 grep JndiLookup.class | awk '{print $3}' | while read -r file\ndo\n if [ -f \"$file\" ]; then\n echo \"JndiLookup.class found in .jar file: $file\"\n echo \"$file\" >> jars_with_jndi.csv\n fi\ndone\n\necho \"\"\necho \"[+] Search .war files for log4j .jar files ...\"\necho \"war_file,jar_size,jar_time_modified,jar_file\" > wars_with_jars.csv\nfind / 2>/dev/null -name '*.war' -type f -print0 | xargs -0 grep log4j | awk '{print $3}' | while read -r war_file\ndo\n if [ -f \"$war_file\" ]; then\n unzip -l \"$war_file\" | grep log4j | awk '{print $1\",\" $2\" \"$3\",\"$4}' | while read -r jar_file\n do\n echo \".war file $war_file was found containing the file $jar_file\"\n echo \"$war_file,$jar_file\" >> wars_with_jars.csv\n done\n fi\ndone\n\necho \"[+] Zip up the outputs ...\"\nhostname=$1\nzip $(hostname)_ssh_log4j_output.zip java_environment.csv jars_with_jndi.csv wars_with_jars.csv\n\"\"\"\n \n file_name = 'splunk_soar_internal_host_ssh_log4j_investigate.sh'\n file_path = '/opt/phantom/vault/tmp/{}'.format(file_name)\n with open(file_path, 'w') as bash_script_file:\n bash_script_file.write(bash_script)\n \n success, message, vault_id = phantom.vault_add(file_location=file_path, file_name=file_name)\n parameters = [{'input_1': vault_id}]\n\n",
"x": 980,
"y": 524.5
},
"6": {
"data": {
"action": "execute program",
"actionType": "generic",
"advanced": {
"customName": "run bash script",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "run_bash_script",
"id": "6",
"parameters": {
"command": "bash /tmp/splunk_soar_internal_host_ssh_log4j_investigate.sh",
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "6",
"type": "action",
"userCode": "\n # append the ip_hostname as an argument so it can be used in the output zip file name\n for parameter in parameters:\n parameter['command'] = parameter['command'] + ' ' + parameter['ip_hostname']\n\n",
"x": 980,
"y": 740
},
"7": {
"data": {
"action": "put file",
"actionType": "generic",
"advanced": {
"customName": "upload bash script",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "upload_bash_script",
"id": "7",
"parameters": {
"file_destination": "/tmp/",
"ip_hostname": "playbook_input:ip_or_hostname",
"vault_id": "write_embedded_bash_script_to_vault:custom_function_result.data.*.item"
},
"requiredParameters": [
"vault_id",
"ip_hostname",
"file_destination"
],
"type": "action"
},
"errors": {},
"id": "7",
"type": "action",
"x": 980,
"y": 640
},
"8": {
"data": {
"action": "get file",
"actionType": "investigate",
"advanced": {
"customName": "get output zip file",
"customNameId": 0,
"join": []
},
"connector": "SSH",
"connectorConfigs": [
"ssh"
],
"connectorId": "d37aa7fe-c973-44ee-a164-2ca5bf321b1f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "get_output_zip_file",
"id": "8",
"parameters": {
"file_path": "playbook_input:ip_or_hostname",
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"file_path",
"ip_hostname"
],
"type": "action"
},
"errors": {},
"id": "8",
"type": "action",
"userCode": "\n import re\n for parameter in parameters:\n parameter['file_path'] = '/tmp/' + parameter['file_path'] + '_ssh_log4j_output.zip'\n\n",
"x": 980,
"y": 864.5
}
},
"notes": ""
},
"input_spec": [
{
"contains": [
"host name",
"ip"
],
"description": "IP address or hostname of the internal host to investigate",
"name": "ip_or_hostname"
}
],
"output_spec": null,
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-15T00:25:26.575505+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"internal_host",
"unix",
"log4j"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

@@ -0,0 +1,242 @@
"""
Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting information specific to the December 2021 log4j vulnerability disclosure. This includes the java version installed on the host, any running java processes, and the results of a scan for the affected JndiLookup.class file or log4j .jar files.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'write_embedded_bash_script_to_vault' block
write_embedded_bash_script_to_vault(container=container)
return
def write_embedded_bash_script_to_vault(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("write_embedded_bash_script_to_vault() called")
parameters = []
parameters.append({
"input_1": None,
"input_2": None,
"input_3": None,
"input_4": None,
"input_5": None,
"input_6": None,
"input_7": None,
"input_8": None,
"input_9": None,
"input_10": None,
})
################################################################################
## Custom Code Start
################################################################################
bash_script = r"""
#!/bin/bash
# This script is part of the Splunk SOAR playbook called internal_host_ssh_log4j_investigate. It shows
# the installed java version, lists any running java processes, performs a search for the JndiLookup.class
# file in any .jar files found on disk, and searches any .war files for a log4j jar.
echo "##############################################################"
echo "splunk_soar_internal_host_ssh_log4j_investigate.sh"
echo "##############################################################"
echo ""
echo "java environment configuration" > java_environment.csv
echo "[+] Checking Java version:"
echo "$(java -version)"
echo "java version:" >> java_environment.csv
java -version 2>> java_environment.csv
echo ""
echo "[+] Checking running Java processes with ps:"
echo "$(ps aux | grep java)"
echo "ps java processes:" >> java_environment.csv
echo "$(ps aux | grep java)" >> java_environment.csv
echo ""
echo "[+] Checking running Java processes with jps:"
echo "$(jps -v)"
echo "jps java processes:" >> java_environment.csv
echo "$(jps -v)" >> java_environment.csv
echo "[+] Search .jar files for JndiLookup.class files ..."
echo "jar_file" > jars_with_jndi.csv
find / 2>/dev/null -name '*.jar' -type f -print0 | xargs -0 grep JndiLookup.class | awk '{print $3}' | while read -r file
do
if [ -f "$file" ]; then
echo "JndiLookup.class found in .jar file: $file"
echo "$file" >> jars_with_jndi.csv
fi
done
echo ""
echo "[+] Search .war files for log4j .jar files ..."
echo "war_file,jar_size,jar_time_modified,jar_file" > wars_with_jars.csv
find / 2>/dev/null -name '*.war' -type f -print0 | xargs -0 grep log4j | awk '{print $3}' | while read -r war_file
do
if [ -f "$war_file" ]; then
unzip -l "$war_file" | grep log4j | awk '{print $1"," $2" "$3","$4}' | while read -r jar_file
do
echo ".war file $war_file was found containing the file $jar_file"
echo "$war_file,$jar_file" >> wars_with_jars.csv
done
fi
done
echo "[+] Zip up the outputs ..."
hostname=$1
zip $(hostname)_ssh_log4j_output.zip java_environment.csv jars_with_jndi.csv wars_with_jars.csv
"""
file_name = 'splunk_soar_internal_host_ssh_log4j_investigate.sh'
file_path = '/opt/phantom/vault/tmp/{}'.format(file_name)
with open(file_path, 'w') as bash_script_file:
bash_script_file.write(bash_script)
success, message, vault_id = phantom.vault_add(file_location=file_path, file_name=file_name)
parameters = [{'input_1': vault_id}]
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/passthrough", parameters=parameters, name="write_embedded_bash_script_to_vault", callback=upload_bash_script)
return
def run_bash_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_bash_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'run_bash_script' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"command": "bash /tmp/splunk_soar_internal_host_ssh_log4j_investigate.sh",
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# append the ip_hostname as an argument so it can be used in the output zip file name
for parameter in parameters:
parameter['command'] = parameter['command'] + ' ' + parameter['ip_hostname']
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="run_bash_script", assets=["ssh"], callback=get_output_zip_file)
return
def upload_bash_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("upload_bash_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
write_embedded_bash_script_to_vault_data = phantom.collect2(container=container, datapath=["write_embedded_bash_script_to_vault:custom_function_result.data.*.item"])
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'upload_bash_script' call
for write_embedded_bash_script_to_vault_data_item in write_embedded_bash_script_to_vault_data:
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if write_embedded_bash_script_to_vault_data_item[0] is not None and playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"vault_id": write_embedded_bash_script_to_vault_data_item[0],
"ip_hostname": playbook_input_ip_or_hostname_item[0],
"file_destination": "/tmp/",
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("put file", parameters=parameters, name="upload_bash_script", assets=["ssh"], callback=run_bash_script)
return
def get_output_zip_file(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_output_zip_file() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'get_output_zip_file' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
"file_path": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
import re
for parameter in parameters:
parameter['file_path'] = '/tmp/' + parameter['file_path'] + '_ssh_log4j_output.zip'
################################################################################
## Custom Code End
################################################################################
phantom.act("get file", parameters=parameters, name="get_output_zip_file", assets=["ssh"])
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host SSH Log4j Investigate
id: 49b2b88c-8e22-48a6-8808-ace1efcb194b
version: 1
date: '2021-12-14'
author: Philip Royer, Splunk
type: Investigate
description: Investigate an internal unix host using SSH. This pushes a bash script to the endpoint and runs it, collecting information specific to the December 2021 log4j vulnerability disclosure. This includes the java version installed on the host, any running java processes, and the results of a scan for the affected JndiLookup.class file or log4j .jar files.
playbook: internal_host_ssh_log4j_investigate
how_to_implement: The ssh asset requires sudo access to scan the whole file system.
references: ["https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh"]
app_list:
- "SSH"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

@@ -0,0 +1,690 @@
"""
Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'filepath_decision' block
filepath_decision(container=container)
return
def locate_files(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("locate_files() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Run a search to locate files. Contains custom code.
################################################################################
playbook_input_filepath = phantom.collect2(container=container, datapath=["playbook_input:filepath"])
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'locate_files' call
for playbook_input_filepath_item in playbook_input_filepath:
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if playbook_input_ip_or_hostname_item[0] is not None:
parameters.append({
"command": playbook_input_filepath_item[0],
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
host_search = {}
# Treat ip_or_hostname and filePath as a paired unit and iterate through them,
# then create a dictionary for each host with a list of its filepaths
for playbook_input_filepath_item, playbook_input_ip_or_hostname_item in zip(playbook_input_filepath, playbook_input_ip_or_hostname):
if playbook_input_ip_or_hostname_item[0] in host_search.keys():
host_search[playbook_input_ip_or_hostname_item[0]].append(playbook_input_filepath_item[0])
else:
host_search[playbook_input_ip_or_hostname_item[0]] = [playbook_input_filepath_item[0]]
# Iterate through the host dictionary and generation one search string that checks all filepaths per host.
# This ensures that we are only connecting to each host once.
for k,v in host_search.items():
script_str = f'''RESULT=""; for i in "{'" "'.join(v)}"; do if [ -f "$i" ]; then RESULT="${{RESULT}} true"; else RESULT="${{RESULT}} false"; fi; done; echo $RESULT'''
parameters.append({
"ip_hostname": k,
"command": script_str
})
# Save the host_search dictionary into temporary data to access downstream.
# This makes it easier to compare the results of locate files with the filepaths and hosts
phantom.save_run_data(value=json.dumps(host_search), key="host_dictionary")
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="locate_files", assets=["ssh"], callback=file_search_decision)
return
def file_search_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("file_search_decision() called")
################################################################################
# Determine if at least one file was found
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["true", "in", "locate_files:action_result.data.*.output"]
])
# call connected blocks if condition 1 matched
if found_match_1:
generate_deletion_commands(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def generate_deletion_commands(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("generate_deletion_commands() called")
################################################################################
# Generate a prompt along with one deletion command per host.
################################################################################
locate_files_result_data = phantom.collect2(container=container, datapath=["locate_files:action_result.parameter.ip_hostname","locate_files:action_result.data.*.output"], action_results=results)
locate_files_parameter_ip_hostname = [item[0] for item in locate_files_result_data]
locate_files_result_item_1 = [item[1] for item in locate_files_result_data]
generate_deletion_commands__prompt_content = None
generate_deletion_commands__deletion_command = None
generate_deletion_commands__host = None
################################################################################
## Custom Code Start
################################################################################
generate_deletion_commands__prompt_content = ""
generate_deletion_commands__host = []
generate_deletion_commands__deletion_command = []
# Retrieve previously saved key
host_dictionary = json.loads(phantom.get_run_data(key="host_dictionary"))
# Iterate through the paired host and locate files action result
for hostname, action_result in zip(locate_files_parameter_ip_hostname, locate_files_result_item_1):
# Ensure at least one file was found for that host
if "true" in action_result.split(' '):
# Attach this host to list of deletion hosts
generate_deletion_commands__host.append(hostname)
# Begin building deletion powershell script and prompt message
deletion_string = f'''for i in '''
generate_deletion_commands__prompt_content += f"### {hostname}\n\n"
for filepath, result in zip(host_dictionary[hostname], action_result.split(' ')):
if result == "true":
generate_deletion_commands__prompt_content += f"- {filepath}\n"
deletion_string += f'"{filepath}" '
# Remove trailing comma and attach one deletion command
deletion_string = deletion_string.rstrip(',')
deletion_string += '; do rm -v $i; done;'
generate_deletion_commands__deletion_command.append(deletion_string)
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="generate_deletion_commands:prompt_content", value=json.dumps(generate_deletion_commands__prompt_content))
phantom.save_run_data(key="generate_deletion_commands:deletion_command", value=json.dumps(generate_deletion_commands__deletion_command))
phantom.save_run_data(key="generate_deletion_commands:host", value=json.dumps(generate_deletion_commands__host))
deletion_confirmation(container=container)
return
def deletion_confirmation(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("deletion_confirmation() called")
################################################################################
# Prompt the user to confirm deletion
################################################################################
# set user and message variables for phantom.prompt call
user = "admin"
message = """SOAR found results for the following files. Please review the returned list and confirm if they should be deleted.\n\n{0}"""
# parameter list for template variable replacement
parameters = [
"generate_deletion_commands:custom_function:prompt_content"
]
# responses
response_types = [
{
"prompt": "Type 'confirm' to delete",
"options": {
"type": "message",
},
}
]
phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="deletion_confirmation", parameters=parameters, response_types=response_types, callback=deletion_decision)
return
def deletion_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("deletion_decision() called")
################################################################################
# Determine if user wants to delete files
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["deletion_confirmation:action_result.summary.responses.0", "==", "confirm"]
])
# call connected blocks if condition 1 matched
if found_match_1:
delete_files(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def delete_files(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("delete_files() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Iterate through host and deletion command. Contains custom code.
################################################################################
generate_deletion_commands__deletion_command = json.loads(phantom.get_run_data(key="generate_deletion_commands:deletion_command"))
generate_deletion_commands__host = json.loads(phantom.get_run_data(key="generate_deletion_commands:host"))
parameters = []
if generate_deletion_commands__host is not None:
parameters.append({
"command": generate_deletion_commands__deletion_command,
"ip_hostname": generate_deletion_commands__host,
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
for del_cmd, host in zip(generate_deletion_commands__deletion_command, generate_deletion_commands__host):
parameters.append({
"command": del_cmd,
"ip_hostname": host,
})
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="delete_files", assets=["ssh"], callback=join_dedup_hostnames)
return
def filepath_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("filepath_decision() called")
################################################################################
# Determine if filepath is present in playbook inputs
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["playbook_input:filepath", "!=", ""]
])
# call connected blocks if condition 1 matched
if found_match_1:
locate_files(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def format_host_list_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_host_list_prompt() called")
################################################################################
# Format a list of the hosts. This will feed both env var prompt and shut down
# prompts.
################################################################################
template = """%%\n- {0}\n%%"""
# parameter list for template variable replacement
parameters = [
"dedup_hostnames:custom_function_result.data.*.item"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_host_list_prompt")
quarantine_prompt(container=container)
return
def quarantine_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("quarantine_prompt() called")
################################################################################
# Offer the user options to quarantine the affected endpoints
################################################################################
# set user and message variables for phantom.prompt call
user = "admin"
message = """Choose an action you would like to take on the following hosts and then type confirm. The same selected action will be performed on every host.\n\n### Available Actions:\n- Restrict Outbound Traffic\n(Sets a firewall policy to prevent all outbound traffic. This may disrupt domain authentication for all but cached credentials.)\n- Shutdown Host (This is a forced shutdown)\n\n### Target Hosts\n{0}"""
# parameter list for template variable replacement
parameters = [
"format_host_list_prompt:formatted_data"
]
# responses
response_types = [
{
"prompt": "Available Actions",
"options": {
"type": "list",
"choices": [
"Restrict Outbound Traffic",
"Shutdown",
"Restrict Outbound Traffic and Shutdown",
"Do Nothing"
],
},
},
{
"prompt": "Type \"confirm\"",
"options": {
"type": "message",
},
}
]
phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="quarantine_prompt", parameters=parameters, response_types=response_types, callback=quarantine_decision)
return
def quarantine_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("quarantine_decision() called")
################################################################################
# Determine which action the user selected
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Restrict Outbound Traffic"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 1 matched
if found_match_1:
block_outbound_traffic(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'elif' condition 2
found_match_2 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Shutdown"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 2 matched
if found_match_2:
shutdown(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'elif' condition 3
found_match_3 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Restrict Outbound Traffic and Shutdown"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 3 matched
if found_match_3:
join_block_and_shutdown(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 4
join_format_custom_note(action=action, success=success, container=container, results=results, handle=handle)
return
def block_outbound_traffic(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("block_outbound_traffic() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Add firewall rule blocking outbound traffic
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'block_outbound_traffic' call
for dedup_hostnames_data_item in dedup_hostnames_data:
if dedup_hostnames_data_item[0] is not None:
parameters.append({
"command": "sudo -S iptables -I OUTPUT -p all 0.0.0.0/0 -j DROP SPLUNK_SOAR_BLOCK",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="block_outbound_traffic", assets=["ssh"], callback=join_format_custom_note)
return
def shutdown(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("shutdown() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Shutdown machine
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'shutdown' call
for dedup_hostnames_data_item in dedup_hostnames_data:
if dedup_hostnames_data_item[0] is not None:
parameters.append({
"command": "shutdown now",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="shutdown", assets=["ssh"], callback=shutdown_callback)
return
def shutdown_callback(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("shutdown_callback() called")
join_block_and_shutdown(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=filtered_artifacts, filtered_results=filtered_results)
join_format_custom_note(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=filtered_artifacts, filtered_results=filtered_results)
return
def join_block_and_shutdown(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("join_block_and_shutdown() called")
if phantom.completed(action_names=["quarantine_prompt", "shutdown"]):
# call connected block "block_and_shutdown"
block_and_shutdown(container=container, handle=handle)
return
def block_and_shutdown(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("block_and_shutdown() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Add firewall rule and then shutdown machine
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'block_and_shutdown' call
for dedup_hostnames_data_item in dedup_hostnames_data:
if dedup_hostnames_data_item[0] is not None:
parameters.append({
"command": "sudo -S iptables -I OUTPUT -p all 0.0.0.0/0 -j DROP SPLUNK_SOAR_BLOCK && shutdown now",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("execute program", parameters=parameters, name="block_and_shutdown", assets=["ssh"], callback=join_format_custom_note)
return
def summary_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("summary_note() called")
################################################################################
# Leave a summary note
################################################################################
format_custom_note__output = json.loads(phantom.get_run_data(key="format_custom_note:output"))
################################################################################
## Custom Code Start
################################################################################
################################################################################
## Custom Code End
################################################################################
phantom.add_note(container=container, content=format_custom_note__output, note_format="markdown", note_type="general", title="WinRm Log4j Response")
return
def join_dedup_hostnames(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("join_dedup_hostnames() called")
# if the joined function has already been called, do nothing
if phantom.get_run_data(key="join_dedup_hostnames_called"):
return
# save the state that the joined function has now been called
phantom.save_run_data(key="join_dedup_hostnames_called", value="dedup_hostnames")
# call connected block "dedup_hostnames"
dedup_hostnames(container=container, handle=handle)
return
def dedup_hostnames(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("dedup_hostnames() called")
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
playbook_input_ip_or_hostname_values = [item[0] for item in playbook_input_ip_or_hostname]
parameters = []
parameters.append({
"input_list": playbook_input_ip_or_hostname_values,
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/list_deduplicate", parameters=parameters, name="dedup_hostnames", callback=format_host_list_prompt)
return
def join_format_custom_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("join_format_custom_note() called")
# if the joined function has already been called, do nothing
if phantom.get_run_data(key="join_format_custom_note_called"):
return
# save the state that the joined function has now been called
phantom.save_run_data(key="join_format_custom_note_called", value="format_custom_note")
# call connected block "format_custom_note"
format_custom_note(container=container, handle=handle)
return
def format_custom_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_custom_note() called")
################################################################################
# Format a dynamic summary note from playbook.get_summary()
################################################################################
format_custom_note__output = None
################################################################################
## Custom Code Start
################################################################################
format_custom_note__output = ""
playbook_summary = phantom.get_summary()
if 'result' in playbook_summary.keys() and playbook_summary['result']:
for result_item in playbook_summary['result']:
format_custom_note__output += f"#### Action - {result_item['name']}: {result_item['message']}\n"
# Generate app run summary for each action
if 'app_runs' in result_item.keys() and result_item['app_runs']:
for app_run_item in result_item['app_runs']:
format_custom_note__output += f"- app_run_id: {app_run_item['app_run_id']}\n"
for k,v in app_run_item['parameter'].items():
if k != 'context':
format_custom_note__output += f" - {k}: {v}\n"
format_custom_note__output += f"- summary: {app_run_item['summary']}\n"
format_custom_note__output += "\n"
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="format_custom_note:output", value=json.dumps(format_custom_note__output))
summary_note(container=container)
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host SSH Log4j Respond
id: 6ea2007c-8ef8-4647-a4a4-7825cfee3866
version: 1
date: '2021-12-14'
author: Kelby Shelton, Splunk
type: Respond
description: Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
playbook: internal_host_ssh_log4j_respond
how_to_implement: The ssh asset may require ssh access to delete some files depending on their permissions.
references: ["https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh"]
app_list:
- "SSH"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
@@ -0,0 +1,413 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Use Cases",
"coa": {
"data": {
"description": "Performs a general investigation on key aspects of a windows device using windows remote management. Important files related to the endpoint are generated, bundled into a zip, and copied to the container vault.",
"edges": [
{
"id": "port_6_to_port_1",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_0_to_port_8",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "8",
"targetPort": "8_in"
},
{
"id": "port_8_to_port_9",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "9",
"targetPort": "9_in"
},
{
"id": "port_9_to_port_10",
"sourceNode": "9",
"sourcePort": "9_out",
"targetNode": "10",
"targetPort": "10_in"
},
{
"id": "port_10_to_port_7",
"sourceNode": "10",
"sourcePort": "10_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"id": "port_7_to_port_4",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "4",
"targetPort": "4_in"
},
{
"id": "port_5_to_port_12",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "12",
"targetPort": "12_in"
},
{
"id": "port_12_to_port_6",
"sourceNode": "12",
"sourcePort": "12_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_11_to_port_5",
"sourceNode": "11",
"sourcePort": "11_out",
"targetNode": "5",
"targetPort": "5_in"
},
{
"id": "port_4_to_port_11",
"sourceNode": "4",
"sourcePort": "4_out",
"targetNode": "11",
"targetPort": "11_in"
}
],
"hash": "36b13ec7d9928057516702e1b9a2a3b6aaf1b7f0",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 20,
"y": -1.1368683772161603e-13
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 20,
"y": 1360
},
"10": {
"data": {
"action": "list sessions",
"actionType": "investigate",
"advanced": {
"customName": "list sessions",
"customNameId": 0,
"description": "List active sessions",
"join": [],
"note": "List active sessions"
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_sessions",
"id": "10",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "10",
"type": "action",
"x": -5.684341886080802e-14,
"y": 380
},
"11": {
"data": {
"advanced": {
"customName": "format zip",
"customNameId": 0,
"description": "Format a dynamic string where the ZIP is located.",
"join": [],
"note": "Format a dynamic string where the ZIP is located."
},
"functionId": 2,
"functionName": "format_zip",
"id": "11",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\n.\\{0}-SOARFetch.zip\n%%",
"type": "format"
},
"errors": {},
"id": "11",
"type": "format",
"x": -5.684341886080802e-14,
"y": 780
},
"12": {
"data": {
"advanced": {
"customName": "format file removal",
"customNameId": 0,
"description": "Format dynamic string for file removal",
"join": [],
"note": "Format dynamic string for file removal"
},
"functionId": 3,
"functionName": "format_file_removal",
"id": "12",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\nRemove-Item -Path .\\{0}-SOARFetch*\n%%",
"type": "format"
},
"errors": {},
"id": "12",
"type": "format",
"x": -2.842170943040401e-14,
"y": 1060
},
"4": {
"data": {
"action": "run script",
"actionType": "generic",
"advanced": {
"customName": "run data collect script",
"customNameId": 0,
"description": "Enumerates autoruns, installed programs, listening network connections, running processes, registered services, scheduled tasks, local users, and local groups. It then exports to CSV. Finally, all information is exported to zip.",
"join": [],
"note": "Enumerates autoruns, installed programs, listening network connections, running processes, registered services, scheduled tasks, local users, and local groups. It then exports to CSV. Finally, all information is exported to zip."
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 2,
"functionName": "run_data_collect_script",
"id": "4",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname",
"script_str": "format_data_collect_script:formatted_data.*"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "4",
"type": "action",
"userCode": "\n parameters = []\n\n # build parameters list for 'run_data_collect_script' call\n for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_data_collect_script__as_list):\n parameters.append({\n \"script_str\": formatted_part,\n \"ip_hostname\": playbook_input_ip_or_hostname_item[0],\n })\n\n\n",
"x": -2.842170943040401e-14,
"y": 640
},
"5": {
"data": {
"action": "get file",
"actionType": "investigate",
"advanced": {
"customName": "get zip",
"customNameId": 0,
"description": "Fetches the zip created by the data capture script and uploads to vault.",
"join": [],
"note": "Fetches the zip created by the data capture script and uploads to vault."
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "get_zip",
"id": "5",
"parameters": {
"file_path": "format_zip:formatted_data.*",
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [
"file_path"
],
"tab": "byConnector",
"type": "action"
},
"errors": {},
"id": "5",
"type": "action",
"userCode": " parameters = []\n\n # build parameters list for 'get_zip' call\n for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_zip__as_list):\n parameters.append({\n \"ip_hostname\": playbook_input_ip_or_hostname_item[0],\n \"file_path\": formatted_part,\n })\n\n",
"x": -2.842170943040401e-14,
"y": 920
},
"6": {
"data": {
"action": "run script",
"actionType": "generic",
"advanced": {
"customName": "remove data capture files",
"customNameId": 0,
"description": "Removes the temporary files created by the data collection script",
"join": [],
"note": "Removes the temporary files created by the data collection script"
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "remove_data_capture_files",
"id": "6",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname",
"script_str": "format_file_removal:formatted_data.*"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "6",
"type": "action",
"userCode": "\n parameters = []\n\n # build parameters list for 'remove_data_capture_files' call\n for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_file_removal__as_list):\n parameters.append({\n \"script_str\": formatted_part,\n \"ip_hostname\": playbook_input_ip_or_hostname_item[0],\n })\n\n",
"x": -9.947598300641403e-14,
"y": 1200
},
"7": {
"data": {
"advanced": {
"customName": "format data collect script",
"customNameId": 0,
"join": []
},
"functionId": 1,
"functionName": "format_data_collect_script",
"id": "7",
"parameters": [
"playbook_input:ip_or_hostname"
],
"template": "%%\n$ProgressPreference = 'SilentlyContinue'; Get-CimInstance -ClassName Win32_StartupCommand | Export-Csv -Path .\\{0}-SOARFetch-Autorun.csv -NoType; Get-ItemProperty HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Export-Csv -Path .\\{0}-SOARFetch-InstalledPrograms.csv -NoType; Get-NetTCPConnection -State Listen | Export-Csv -Path .\\{0}-SOARFetch-NetworkConnections.csv -NoType; Get-Process -IncludeUserName | Export-Csv -Path .\\{0}-SOARFetch-Processes.csv -NoType; Get-Service | Export-Csv -Path .\\{0}-SOARFetch-Services.csv -NoType; Get-ScheduledTask | Export-Csv -Path .\\{0}-SOARFetch-ScheduledTasks.csv -NoType; Get-LocalUser | Export-Csv -Path .\\{0}-SOARFetch-Users.csv -NoType; Get-LocalGroup | Export-Csv -Path .\\{0}-SOARFetch-Groups.csv -NoType; Compress-Archive -Path .\\{0}-SOARFetch* .\\{0}-SOARFetch.zip; \n%%",
"type": "format"
},
"errors": {},
"id": "7",
"type": "format",
"x": 1.4210854715202004e-14,
"y": 520
},
"8": {
"data": {
"action": "list processes",
"actionType": "investigate",
"advanced": {
"customName": "list processes",
"customNameId": 0,
"description": "List running processes",
"join": [],
"note": "List running processes"
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_processes",
"id": "8",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "8",
"type": "action",
"x": -5.684341886080802e-14,
"y": 99.99999999999994
},
"9": {
"data": {
"action": "list connections",
"actionType": "investigate",
"advanced": {
"customName": "list connections",
"customNameId": 0,
"description": "List current connections",
"join": [],
"note": "List current connections"
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "list_connections",
"id": "9",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "9",
"type": "action",
"x": -5.684341886080802e-14,
"y": 240
}
},
"notes": ""
},
"input_spec": [
{
"contains": [
"host name",
"ip"
],
"description": "IP address or hostname of the internal host to investigate",
"name": "ip_or_hostname"
}
],
"output_spec": null,
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-15T00:19:14.002156+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"windows",
"internal_host"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

@@ -0,0 +1,364 @@
"""
Performs a general investigation on key aspects of a windows device using windows remote management. Important files related to the endpoint are generated, bundled into a zip, and copied to the container vault.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'list_processes' block
list_processes(container=container)
return
def run_data_collect_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_data_collect_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Enumerates autoruns, installed programs, listening network connections, running
# processes, registered services, scheduled tasks, local users, and local groups.
# It then exports to CSV. Finally, all information is exported to zip.
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
format_data_collect_script__as_list = phantom.get_format_data(name="format_data_collect_script__as_list")
parameters = []
# build parameters list for 'run_data_collect_script' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"script_str": format_data_collect_script__as_list,
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
# build parameters list for 'run_data_collect_script' call
for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_data_collect_script__as_list):
parameters.append({
"script_str": formatted_part,
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="run_data_collect_script", assets=["winrm"], callback=format_zip)
return
def get_zip(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("get_zip() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Fetches the zip created by the data capture script and uploads to vault.
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
format_zip__as_list = phantom.get_format_data(name="format_zip__as_list")
parameters = []
# build parameters list for 'get_zip' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
if format_zip__as_list is not None:
parameters.append({
"file_path": format_zip__as_list,
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
# build parameters list for 'get_zip' call
for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_zip__as_list):
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
"file_path": formatted_part,
})
################################################################################
## Custom Code End
################################################################################
phantom.act("get file", parameters=parameters, name="get_zip", assets=["winrm"], callback=format_file_removal)
return
def remove_data_capture_files(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("remove_data_capture_files() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Removes the temporary files created by the data collection script
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
format_file_removal__as_list = phantom.get_format_data(name="format_file_removal__as_list")
parameters = []
# build parameters list for 'remove_data_capture_files' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"script_str": format_file_removal__as_list,
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
# build parameters list for 'remove_data_capture_files' call
for playbook_input_ip_or_hostname_item, formatted_part in zip(playbook_input_ip_or_hostname, format_file_removal__as_list):
parameters.append({
"script_str": formatted_part,
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="remove_data_capture_files", assets=["winrm"])
return
def format_data_collect_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_data_collect_script() called")
template = """%%\n$ProgressPreference = 'SilentlyContinue'; Get-CimInstance -ClassName Win32_StartupCommand | Export-Csv -Path .\\{0}-SOARFetch-Autorun.csv -NoType; Get-ItemProperty HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Export-Csv -Path .\\{0}-SOARFetch-InstalledPrograms.csv -NoType; Get-NetTCPConnection -State Listen | Export-Csv -Path .\\{0}-SOARFetch-NetworkConnections.csv -NoType; Get-Process -IncludeUserName | Export-Csv -Path .\\{0}-SOARFetch-Processes.csv -NoType; Get-Service | Export-Csv -Path .\\{0}-SOARFetch-Services.csv -NoType; Get-ScheduledTask | Export-Csv -Path .\\{0}-SOARFetch-ScheduledTasks.csv -NoType; Get-LocalUser | Export-Csv -Path .\\{0}-SOARFetch-Users.csv -NoType; Get-LocalGroup | Export-Csv -Path .\\{0}-SOARFetch-Groups.csv -NoType; Compress-Archive -Path .\\{0}-SOARFetch* .\\{0}-SOARFetch.zip; \n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_data_collect_script")
run_data_collect_script(container=container)
return
def list_processes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_processes() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# List running processes
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_processes' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list processes", parameters=parameters, name="list_processes", assets=["winrm"], callback=list_connections)
return
def list_connections(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_connections() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# List current connections
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_connections' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list connections", parameters=parameters, name="list_connections", assets=["winrm"], callback=list_sessions)
return
def list_sessions(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("list_sessions() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# List active sessions
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'list_sessions' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("list sessions", parameters=parameters, name="list_sessions", assets=["winrm"], callback=format_data_collect_script)
return
def format_zip(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_zip() called")
################################################################################
# Format a dynamic string where the ZIP is located.
################################################################################
template = """%%\n.\\{0}-SOARFetch.zip\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_zip")
get_zip(container=container)
return
def format_file_removal(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_file_removal() called")
################################################################################
# Format dynamic string for file removal
################################################################################
template = """%%\nRemove-Item -Path .\\{0}-SOARFetch*\n%%"""
# parameter list for template variable replacement
parameters = [
"playbook_input:ip_or_hostname"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_file_removal")
remove_data_capture_files(container=container)
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host WinRM Investigate
id: 32fd9db5-5201-4a2f-b2c2-9299c7b3495d
version: 1
date: '2021-12-14'
author: Kelby Shelton, Splunk
type: Investigate
description: Performs a general investigation on key aspects of a windows device using windows remote management. Important files related to the endpoint are generated, bundled into a zip, and copied to the container vault.
playbook: internal_host_winrm_investigate
how_to_implement: The winrm asset requires Administrator access to gather certain files.
references: []
app_list:
- "Windows Remote Management"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
@@ -0,0 +1,315 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Use Cases",
"coa": {
"data": {
"description": "Published in response to CVE-2021-44228, this playbook scans the endpoint for the presence of \"jndilookup.class\" in all .jar files. The presence of that string could indicate a log4j vulnerability.",
"edges": [
{
"id": "port_0_to_port_3",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "3",
"targetPort": "3_in"
},
{
"id": "port_5_to_port_6",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_6_to_port_1",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_3_to_port_7",
"sourceNode": "3",
"sourcePort": "3_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_7_to_port_5",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "5",
"targetPort": "5_in"
}
],
"hash": "6be22bd4339e81de35e935fd531dd37b71c5e6a6",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 840,
"y": 359.99999999999955
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 840,
"y": 1000
},
"3": {
"data": {
"action": "run script",
"actionType": "generic",
"advanced": {
"customName": "run traversal script",
"customNameId": 0,
"description": "Run a script to locate all drives and traverse them for the presence of the jndilookup.class",
"join": [],
"note": "Run a script to locate all drives and traverse them for the presence of the jndilookup.class"
},
"connector": "Windows Remote Management",
"connectorConfigs": [
"winrm"
],
"connectorId": "a0222b95-b006-4c9e-9578-1428defcec0f",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "run_traversal_script",
"id": "3",
"parameters": {
"ip_hostname": "playbook_input:ip_or_hostname",
"script_str": "$ProgressPreference = 'SilentlyContinue'; Get-PSDrive -PSProvider FileSystem | foreach {(gci ($_.Root) -rec -force -include ('*.war', '*.jsp', '*.jspx', '*.jar') -ea 0 | foreach {select-string \"JndiLookup.class\" $_} | Select-Object -Property LineNumber, Path )} | ConvertTo-Json"
},
"requiredParameters": [],
"type": "action"
},
"errors": {},
"id": "3",
"type": "action",
"x": 820,
"y": 480
},
"5": {
"data": {
"advanced": {
"customName": "custom format",
"customNameId": 0,
"description": "Parse out the JSON returned by the traversal script",
"join": [],
"note": "Parse out the JSON returned by the traversal script"
},
"functionId": 1,
"functionName": "custom_format",
"id": "5",
"inputParameters": [
"run_traversal_script:action_result.data.*.std_out",
"playbook_input:ip_or_hostname"
],
"outputVariables": [
"note_content"
],
"type": "code"
},
"errors": {},
"id": "5",
"type": "code",
"userCode": " custom_format__note_content = \"\"\n for script_result_item, ip_hostname in zip(run_traversal_script_result_item_0, playbook_input_ip_or_hostname_values):\n try:\n custom_format__note_content += f\"### Device - {ip_hostname}\\n\"\n custom_format__note_content += \" | Path | LineNumber |\\n\"\n custom_format__note_content += \"| --- | --- |\\n\"\n result_to_json = json.loads(script_result_item)\n for json_result in result_to_json:\n custom_format__note_content += f\"| {json_result['Path']} | {json_result['LineNumber']} |\\n\"\n custom_format__note_content += \"\\n&nbsp;\"\n except:\n phantom.error(\"Unable to parse JSON\")\n",
"x": 820,
"y": 780
},
"6": {
"data": {
"advanced": {
"join": []
},
"functionId": 2,
"functionName": "add_note_2",
"id": "6",
"selectMore": false,
"tab": "apis",
"type": "utility",
"utilities": {
"add_note": {
"description": "",
"fields": [
{
"description": "",
"label": "title",
"name": "title",
"placeholder": "Enter a note title",
"renderType": "input",
"required": false
},
{
"description": "",
"label": "content",
"name": "content",
"placeholder": "Enter the note content",
"renderType": "datapath",
"required": false
},
{
"choices": [
"markdown",
"html"
],
"default": "markdown",
"description": "",
"label": "note format",
"name": "note_format",
"placeholder": "Enter the note content",
"renderType": "dropdown",
"required": false
},
{
"hidden": true,
"name": "container",
"required": false
},
{
"default": "general",
"hidden": true,
"name": "note_type",
"required": false
},
{
"hidden": true,
"name": "author",
"required": false
},
{
"hidden": true,
"name": "event_id",
"required": false
},
{
"hidden": true,
"name": "task_id",
"required": false
},
{
"hidden": true,
"name": "trace",
"required": false
}
],
"label": "add note",
"name": "add_note"
}
},
"utilityType": "api",
"values": {
"add_note": {
"_internal": [
"container",
"note_type",
"author",
"event_id",
"task_id",
"trace"
],
"content": "custom_format:custom_function:note_content",
"note_format": "markdown",
"note_type": "general",
"title": "Evidence of jndilookup.class for CVE-2021-44228"
}
}
},
"errors": {},
"id": "6",
"type": "utility",
"x": 820,
"y": 904.5
},
"7": {
"data": {
"advanced": {
"customName": "results decision",
"customNameId": 0,
"description": "Only proceed if stdout has results",
"join": [],
"note": "Only proceed if stdout has results"
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "run_traversal_script:action_result.data.*.std_out",
"value": ""
}
],
"conditionIndex": 0,
"customName": "results exist",
"display": "If",
"logic": "and",
"type": "if"
}
],
"functionId": 1,
"functionName": "results_decision",
"id": "7",
"type": "decision"
},
"errors": {},
"id": "7",
"type": "decision",
"x": 900,
"y": 620
}
},
"notes": "Based on \"https://twitter.com/CyberRaiju/status/1469505677580124160\""
},
"input_spec": [
{
"contains": [
"host name",
"ip"
],
"description": "IP address or hostname of the internal host to investigate",
"name": "ip_or_hostname"
}
],
"output_spec": null,
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-15T00:24:05.504834+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"windows",
"internal_host",
"log4j"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

@@ -0,0 +1,160 @@
"""
Published in response to CVE-2021-44228, this playbook scans the endpoint for the presence of &quot;jndilookup.class&quot; in all .jar files. The presence of that string could indicate a log4j vulnerability.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'run_traversal_script' block
run_traversal_script(container=container)
return
def run_traversal_script(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("run_traversal_script() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Run a script to locate all drives and traverse them for the presence of the
# jndilookup.class
################################################################################
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'run_traversal_script' call
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"script_str": "$ProgressPreference = 'SilentlyContinue'; Get-PSDrive -PSProvider FileSystem | foreach {(gci ($_.Root) -rec -force -include ('*.war', '*.jsp', '*.jspx', '*.jar') -ea 0 | foreach {select-string \"JndiLookup.class\" $_} | Select-Object -Property LineNumber, Path )} | ConvertTo-Json",
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="run_traversal_script", assets=["winrm"], callback=results_decision)
return
def custom_format(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("custom_format() called")
################################################################################
# Parse out the JSON returned by the traversal script
################################################################################
run_traversal_script_result_data = phantom.collect2(container=container, datapath=["run_traversal_script:action_result.data.*.std_out"], action_results=results)
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
run_traversal_script_result_item_0 = [item[0] for item in run_traversal_script_result_data]
playbook_input_ip_or_hostname_values = [item[0] for item in playbook_input_ip_or_hostname]
custom_format__note_content = None
################################################################################
## Custom Code Start
################################################################################
custom_format__note_content = ""
for script_result_item, ip_hostname in zip(run_traversal_script_result_item_0, playbook_input_ip_or_hostname_values):
try:
custom_format__note_content += f"### Device - {ip_hostname}\n"
custom_format__note_content += " | Path | LineNumber |\n"
custom_format__note_content += "| --- | --- |\n"
result_to_json = json.loads(script_result_item)
for json_result in result_to_json:
custom_format__note_content += f"| {json_result['Path']} | {json_result['LineNumber']} |\n"
custom_format__note_content += "\n&nbsp;"
except:
phantom.error("Unable to parse JSON")
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="custom_format:note_content", value=json.dumps(custom_format__note_content))
add_note_2(container=container)
return
def add_note_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("add_note_2() called")
custom_format__note_content = json.loads(phantom.get_run_data(key="custom_format:note_content"))
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.add_note(container=container, content=custom_format__note_content, note_format="markdown", note_type="general", title="Evidence of jndilookup.class for CVE-2021-44228")
return
def results_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("results_decision() called")
################################################################################
# Only proceed if stdout has results
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["run_traversal_script:action_result.data.*.std_out", "!=", ""]
])
# call connected blocks if condition 1 matched
if found_match_1:
custom_format(action=action, success=success, container=container, results=results, handle=handle)
return
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host WinRM Log4j Investigate
id: 2cf7c9f4-b273-44f6-a27c-e0db668ff05a
version: 1
date: '2021-12-14'
author: Kelby Shelton, Splunk
type: Investigate
description: Published in response to CVE-2021-44228, this playbook uses WinRM to scan Windows endpoints for the presence of "jndilookup.class" in all .jar files. The presence of that string could indicate a log4j vulnerability.
playbook: internal_host_winrm_log4j_investigate
how_to_implement: The winrm asset requires Administrator access to scan the whole file system.
references: ["https://twitter.com/CyberRaiju/status/1469505677580124160"]
app_list:
- "Windows Remote Management"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

@@ -0,0 +1,665 @@
"""
Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'filepath_decision' block
filepath_decision(container=container)
return
def locate_files(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("locate_files() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Run a search to locate files. Contains custom code.
################################################################################
playbook_input_filepath = phantom.collect2(container=container, datapath=["playbook_input:filepath"])
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
parameters = []
# build parameters list for 'locate_files' call
for playbook_input_filepath_item in playbook_input_filepath:
for playbook_input_ip_or_hostname_item in playbook_input_ip_or_hostname:
parameters.append({
"script_str": playbook_input_filepath_item[0],
"ip_hostname": playbook_input_ip_or_hostname_item[0],
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
host_search = {}
# Treat ip_or_hostname and filePath as a paired unit and iterate through them,
# then create a dictionary for each host with a list of its filepaths
for playbook_input_filepath_item, playbook_input_ip_or_hostname_item in zip(playbook_input_filepath, playbook_input_ip_or_hostname):
if playbook_input_ip_or_hostname_item[0] in host_search.keys():
host_search[playbook_input_ip_or_hostname_item[0]].append(playbook_input_filepath_item[0])
else:
host_search[playbook_input_ip_or_hostname_item[0]] = [playbook_input_filepath_item[0]]
# Iterate through the host dictionary and generation one search string that checks all filepaths per host.
# This ensures that we are only connecting to each host once.
for k,v in host_search.items():
script_str = f"Test-Path {','.join(v)} | ConvertTo-Json"
parameters.append({
"ip_hostname": k,
"script_str": script_str
})
# Save the host_search dictionary into temporary data to access downstream.
# This makes it easier to compare the results of locate files with the filepaths and hosts
phantom.save_run_data(value=json.dumps(host_search), key="host_dictionary")
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="locate_files", assets=["winrm"], callback=file_search_decision)
return
def file_search_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("file_search_decision() called")
################################################################################
# Determine if at least one file was found
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["true", "in", "locate_files:action_result.data.*.std_out"]
])
# call connected blocks if condition 1 matched
if found_match_1:
generate_deletion_commands(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def generate_deletion_commands(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("generate_deletion_commands() called")
################################################################################
# Generate a prompt along with one deletion command per host.
################################################################################
locate_files_result_data = phantom.collect2(container=container, datapath=["locate_files:action_result.parameter.ip_hostname","locate_files:action_result.data.*.std_out"], action_results=results)
locate_files_parameter_ip_hostname = [item[0] for item in locate_files_result_data]
locate_files_result_item_1 = [item[1] for item in locate_files_result_data]
generate_deletion_commands__prompt_content = None
generate_deletion_commands__deletion_command = None
generate_deletion_commands__host = None
################################################################################
## Custom Code Start
################################################################################
generate_deletion_commands__prompt_content = ""
generate_deletion_commands__host = []
generate_deletion_commands__deletion_command = []
# Retrieve previously saved key
host_dictionary = json.loads(phantom.get_run_data(key="host_dictionary"))
# Iterate through the paired host and locate files action result
for hostname, action_result in zip(locate_files_parameter_ip_hostname, locate_files_result_item_1):
# Ensure at least one file was found for that host
if True in json.loads(action_result):
# Attach this host to list of deletion hosts
generate_deletion_commands__host.append(hostname)
# Begin building deletion powershell script and prompt message
deletion_string = "Remove-Item "
generate_deletion_commands__prompt_content += f"### {hostname}\n\n"
for filepath, result in zip(host_dictionary[hostname], json.loads(action_result)):
if result == True:
generate_deletion_commands__prompt_content += f"- {filepath}\n"
deletion_string += f"{filepath},"
# Remove trailing comma and attach one deletion command
deletion_string = deletion_string.rstrip(',')
deletion_string += ' | Write-Output "Files Deleted"'
generate_deletion_commands__deletion_command.append(deletion_string)
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="generate_deletion_commands:prompt_content", value=json.dumps(generate_deletion_commands__prompt_content))
phantom.save_run_data(key="generate_deletion_commands:deletion_command", value=json.dumps(generate_deletion_commands__deletion_command))
phantom.save_run_data(key="generate_deletion_commands:host", value=json.dumps(generate_deletion_commands__host))
deletion_confirmation(container=container)
return
def deletion_confirmation(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("deletion_confirmation() called")
################################################################################
# Prompt the user to confirm deletion
################################################################################
# set user and message variables for phantom.prompt call
user = "admin"
message = """SOAR found results for the following files. Please review the returned list and confirm if they should be deleted.\n\n{0}"""
# parameter list for template variable replacement
parameters = [
"generate_deletion_commands:custom_function:prompt_content"
]
# responses
response_types = [
{
"prompt": "Type 'confirm' to delete",
"options": {
"type": "message",
},
}
]
phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="deletion_confirmation", parameters=parameters, response_types=response_types, callback=deletion_decision)
return
def deletion_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("deletion_decision() called")
################################################################################
# Determine if user wants to delete files
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["deletion_confirmation:action_result.summary.responses.0", "==", "confirm"]
])
# call connected blocks if condition 1 matched
if found_match_1:
delete_files(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def delete_files(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("delete_files() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Iterate through host and deletion command. Contains custom code.
################################################################################
generate_deletion_commands__deletion_command = json.loads(phantom.get_run_data(key="generate_deletion_commands:deletion_command"))
generate_deletion_commands__host = json.loads(phantom.get_run_data(key="generate_deletion_commands:host"))
parameters = []
parameters.append({
"script_str": generate_deletion_commands__deletion_command,
"ip_hostname": generate_deletion_commands__host,
})
################################################################################
## Custom Code Start
################################################################################
parameters = []
for del_cmd, host in zip(generate_deletion_commands__deletion_command, generate_deletion_commands__host):
parameters.append({
"script_str": del_cmd,
"ip_hostname": host,
})
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="delete_files", assets=["winrm"], callback=join_dedup_hostnames)
return
def filepath_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("filepath_decision() called")
################################################################################
# Determine if filepath is present in playbook inputs
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["playbook_input:filepath", "!=", ""]
])
# call connected blocks if condition 1 matched
if found_match_1:
locate_files(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
join_dedup_hostnames(action=action, success=success, container=container, results=results, handle=handle)
return
def format_host_list_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_host_list_prompt() called")
################################################################################
# Format a list of the hosts. This will feed both env var prompt and shut down
# prompts.
################################################################################
template = """%%\n- {0}\n%%"""
# parameter list for template variable replacement
parameters = [
"dedup_hostnames:custom_function_result.data.*.item"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_host_list_prompt")
quarantine_prompt(container=container)
return
def quarantine_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("quarantine_prompt() called")
################################################################################
# Offer the user options to quarantine the affected endpoints
################################################################################
# set user and message variables for phantom.prompt call
user = "admin"
message = """Choose an action you would like to take on the following hosts and then type confirm. The same selected action will be performed on every host.\n\n### Available Actions:\n- Restrict Outbound Traffic\n(Sets a firewall policy to prevent all outbound traffic. This may disrupt domain authentication for all but cached credentials.)\n- Shutdown Host (This is a forced shutdown)\n\n### Target Hosts\n{0}"""
# parameter list for template variable replacement
parameters = [
"format_host_list_prompt:formatted_data"
]
# responses
response_types = [
{
"prompt": "Available Actions",
"options": {
"type": "list",
"choices": [
"Restrict Outbound Traffic",
"Shutdown",
"Restrict Outbound Traffic and Shutdown",
"Do Nothing"
],
},
},
{
"prompt": "Type \"confirm\"",
"options": {
"type": "message",
},
}
]
phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="quarantine_prompt", parameters=parameters, response_types=response_types, callback=quarantine_decision)
return
def quarantine_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("quarantine_decision() called")
################################################################################
# Determine which action the user selected
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Restrict Outbound Traffic"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 1 matched
if found_match_1:
block_outbound_traffic(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'elif' condition 2
found_match_2 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Shutdown"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 2 matched
if found_match_2:
shutdown(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'elif' condition 3
found_match_3 = phantom.decision(
container=container,
logical_operator="and",
conditions=[
["quarantine_prompt:action_result.summary.responses.0", "==", "Restrict Outbound Traffic and Shutdown"],
["quarantine_prompt:action_result.summary.responses.1", "==", "confirm"]
])
# call connected blocks if condition 3 matched
if found_match_3:
block_and_shutdown(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 4
join_format_custom_note(action=action, success=success, container=container, results=results, handle=handle)
return
def block_outbound_traffic(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("block_outbound_traffic() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Add firewall rule blocking outbound traffic
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'block_outbound_traffic' call
for dedup_hostnames_data_item in dedup_hostnames_data:
parameters.append({
"script_str": "New-NetFirewallRule -DisplayName Splunk_SOAR_Quarantine -Direction Outbound -Enabled True -LocalPort Any -RemoteAddress Any -Action Block",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="block_outbound_traffic", assets=["winrm"], callback=join_format_custom_note)
return
def shutdown(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("shutdown() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Shutdown machine
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'shutdown' call
for dedup_hostnames_data_item in dedup_hostnames_data:
parameters.append({
"script_str": "shutdown /f",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="shutdown", assets=["winrm"], callback=join_format_custom_note)
return
def block_and_shutdown(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("block_and_shutdown() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Add firewall rule and then shutdown machine
################################################################################
dedup_hostnames_data = phantom.collect2(container=container, datapath=["dedup_hostnames:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'block_and_shutdown' call
for dedup_hostnames_data_item in dedup_hostnames_data:
parameters.append({
"script_str": "New-NetFirewallRule -DisplayName Splunk_SOAR_Quarantine -Direction Outbound -Enabled True -LocalPort Any -RemoteAddress Any -Action Block; shutdown /f",
"ip_hostname": dedup_hostnames_data_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("run script", parameters=parameters, name="block_and_shutdown", assets=["winrm"], callback=join_format_custom_note)
return
def summary_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("summary_note() called")
################################################################################
# Leave a summary note
################################################################################
format_custom_note__output = json.loads(phantom.get_run_data(key="format_custom_note:output"))
################################################################################
## Custom Code Start
################################################################################
################################################################################
## Custom Code End
################################################################################
phantom.add_note(container=container, content=format_custom_note__output, note_format="markdown", note_type="general", title="WinRm Log4j Response")
return
def join_dedup_hostnames(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("join_dedup_hostnames() called")
# if the joined function has already been called, do nothing
if phantom.get_run_data(key="join_dedup_hostnames_called"):
return
# save the state that the joined function has now been called
phantom.save_run_data(key="join_dedup_hostnames_called", value="dedup_hostnames")
# call connected block "dedup_hostnames"
dedup_hostnames(container=container, handle=handle)
return
def dedup_hostnames(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("dedup_hostnames() called")
playbook_input_ip_or_hostname = phantom.collect2(container=container, datapath=["playbook_input:ip_or_hostname"])
playbook_input_ip_or_hostname_values = [item[0] for item in playbook_input_ip_or_hostname]
parameters = []
parameters.append({
"input_list": playbook_input_ip_or_hostname_values,
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/list_deduplicate", parameters=parameters, name="dedup_hostnames", callback=format_host_list_prompt)
return
def join_format_custom_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("join_format_custom_note() called")
# if the joined function has already been called, do nothing
if phantom.get_run_data(key="join_format_custom_note_called"):
return
# save the state that the joined function has now been called
phantom.save_run_data(key="join_format_custom_note_called", value="format_custom_note")
# call connected block "format_custom_note"
format_custom_note(container=container, handle=handle)
return
def format_custom_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_custom_note() called")
################################################################################
# Format a dynamic summary note from playbook.get_summary()
################################################################################
format_custom_note__output = None
################################################################################
## Custom Code Start
################################################################################
format_custom_note__output = ""
playbook_summary = phantom.get_summary()
if 'result' in playbook_summary.keys() and playbook_summary['result']:
for result_item in playbook_summary['result']:
format_custom_note__output += f"#### Action - {result_item['name']}: {result_item['message']}\n"
# Generate app run summary for each action
if 'app_runs' in result_item.keys() and result_item['app_runs']:
for app_run_item in result_item['app_runs']:
format_custom_note__output += f"- app_run_id: {app_run_item['app_run_id']}\n"
for k,v in app_run_item['parameter'].items():
if k != 'context':
format_custom_note__output += f" - {k}: {v}\n"
format_custom_note__output += f"- summary: {app_run_item['summary']}\n"
format_custom_note__output += "\n"
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="format_custom_note:output", value=json.dumps(format_custom_note__output))
summary_note(container=container)
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,18 @@
name: Internal Host WinRM Response
id: 32fd9db5-5201-4b2f-b2c2-9299c7b3495d
version: 1
date: '2021-12-14'
author: Kelby Shelton, Splunk
type: Investigate
description: Published in response to CVE-2021-44228, this playbook accepts a list of hosts and filenames to remediate on the endpoint. If filenames are provided, the endpoints will be searched and then the user can approve deletion. Then the user is prompted to quarantine the endpoint.
playbook: internal_host_winrm_log4j_respond
how_to_implement: The winrm asset requires Administrator access to gather certain files.
references: []
app_list:
- "Windows Remote Management"
tags:
platform_tags:
- Response
playbook_fields: []
product:
- Splunk SOAR
@@ -0,0 +1,679 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Use Cases",
"coa": {
"data": {
"description": "Published in response to CVE-2021-44228, this playbook and its sub-playbooks can be used to investigate and respond to attacks against hosts running vulnerable Java applications which use log4j.",
"edges": [
{
"id": "port_0_to_port_15",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "15",
"targetPort": "15_in"
},
{
"id": "port_15_to_port_19",
"sourceNode": "15",
"sourcePort": "15_out",
"targetNode": "19",
"targetPort": "19_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_20_to_port_21",
"sourceNode": "20",
"sourcePort": "20_out",
"targetNode": "21",
"targetPort": "21_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_20_to_port_22",
"sourceNode": "20",
"sourcePort": "20_out",
"targetNode": "22",
"targetPort": "22_in"
},
{
"conditions": [
{
"index": 1
}
],
"id": "port_20_to_port_23",
"sourceNode": "20",
"sourcePort": "20_out",
"targetNode": "23",
"targetPort": "23_in"
},
{
"conditions": [
{
"index": 1
}
],
"id": "port_20_to_port_24",
"sourceNode": "20",
"sourcePort": "20_out",
"targetNode": "24",
"targetPort": "24_in"
},
{
"id": "port_19_to_port_25",
"sourceNode": "19",
"sourcePort": "19_out",
"targetNode": "25",
"targetPort": "25_in"
},
{
"id": "port_25_to_port_20",
"sourceNode": "25",
"sourcePort": "25_out",
"targetNode": "20",
"targetPort": "20_in"
}
],
"hash": "78e9b912032aa57c87befaa5f816a31d048407ed",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"x": 530,
"y": -7.815970093361102e-14
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"x": 830,
"y": -7.815970093361102e-14
},
"15": {
"data": {
"advanced": {
"customName": "enumerate hosts",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "passthrough",
"repoName": "community"
},
"functionId": 5,
"functionName": "enumerate_hosts",
"id": "15",
"selectMore": false,
"type": "utility",
"utilities": {
"passthrough": {
"description": "Return the inputs as outputs. This is useful for publishing pieces of data for other blocks in the playbook to use.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_1",
"name": "input_1",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_2",
"name": "input_2",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_3",
"name": "input_3",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_4",
"name": "input_4",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_5",
"name": "input_5",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_6",
"name": "input_6",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_7",
"name": "input_7",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_8",
"name": "input_8",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_9",
"name": "input_9",
"placeholder": "",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "",
"inputType": "list",
"label": "input_10",
"name": "input_10",
"placeholder": "",
"renderType": "datapath",
"required": false
}
],
"label": "passthrough",
"name": "passthrough"
}
},
"utilityType": "custom_function",
"values": {
"passthrough": {
"input_1": "log4j_hosts",
"input_10": null,
"input_2": "",
"input_3": null,
"input_4": null,
"input_5": null,
"input_6": null,
"input_7": null,
"input_8": null,
"input_9": null
}
}
},
"errors": {},
"id": "15",
"type": "utility",
"userCode": "\n # use custom code to read a custom list of potential log4j hosts and/or ip addresses\n # and make a json to create an artifact for each one.\n # the expected format of the custom list is:\n # hostname1 | unix\n # 1.1.1.1 | windows\n \n # TODO remove this testing piece which deletes existing artifacts\n container_artifact_data = phantom.collect2(container=container, datapath=[\"artifact:*.id\",\"artifact:*.id\"])\n container_artifact_header_item_0 = [item[0] for item in container_artifact_data]\n for artifact_id in container_artifact_header_item_0:\n phantom.delete_artifact(artifact_id=artifact_id)\n \n \n # TODO: bring in a test splunk notable and clean up the fields in that as well\n\n custom_list_name = parameters[0]['input_1']\n \n success, message, rows = phantom.get_list(list_name=custom_list_name)\n \n # loop through the rows and create a list of artifact jsons to add\n # the two columns are expected to be the ip_or_hostname and the operating system family\n parameters = []\n unix_hosts = []\n windows_hosts = []\n unknown_hosts = []\n for row in rows:\n if row[0]:\n if row[1] != 'unix' and row[1] != 'windows':\n os_family = 'unknown'\n else:\n os_family = row[1]\n \n parameters.append({'input_1': {'cef_data': {'deviceHostname': row[0], 'operatingSystemFamily': os_family}}})\n \n\n",
"x": 510,
"y": 152
},
"19": {
"data": {
"advanced": {
"customName": "create artifacts",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "artifact_create",
"repoName": "community"
},
"functionId": 9,
"functionName": "create_artifacts",
"id": "19",
"selectMore": false,
"type": "utility",
"utilities": {
"artifact_create": {
"description": "Create a new artifact with the specified attributes.",
"fields": [
{
"dataTypes": [
"phantom container id"
],
"description": "Container which the artifact will be added to.",
"inputType": "item",
"label": "container",
"name": "container",
"placeholder": "container:id",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The name of the new artifact, which is optional and defaults to \"artifact\".",
"inputType": "item",
"label": "name",
"name": "name",
"placeholder": "artifact",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The label of the new artifact, which is optional and defaults to \"events\"",
"inputType": "item",
"label": "label",
"name": "label",
"placeholder": "events",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
""
],
"description": "The severity of the new artifact, which is optional and defaults to \"Medium\". Typically this is either \"High\", \"Medium\", or \"Low\".",
"inputType": "item",
"label": "severity",
"name": "severity",
"placeholder": "Medium",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The name of the CEF field to populate in the artifact, such as \"destinationAddress\" or \"sourceDnsDomain\". Required only if cef_value is provided.",
"inputType": "item",
"label": "cef_field",
"name": "cef_field",
"placeholder": "destinationAddress",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "The value of the CEF field to populate in the artifact, such as the IP address, domain name, or file hash. Required only if cef_field is provided.",
"inputType": "item",
"label": "cef_value",
"name": "cef_value",
"placeholder": "192.0.2.192",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The CEF data type of the data in cef_value. For example, this could be \"ip\", \"hash\", or \"domain\". Optional.",
"inputType": "item",
"label": "cef_data_type",
"name": "cef_data_type",
"placeholder": "ip",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "A comma-separated list of tags to apply to the created artifact, which is optional.",
"inputType": "item",
"label": "tags",
"name": "tags",
"placeholder": "tag1, tag2, tag3",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "Either \"true\" or \"false\", depending on whether or not the new artifact should trigger the execution of any playbooks that are set to active on the label of the container the artifact will be added to. Optional and defaults to \"false\".",
"inputType": "item",
"label": "run_automation",
"name": "run_automation",
"placeholder": "false",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "Optional parameter to modify any extra attributes of the artifact. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.",
"inputType": "item",
"label": "input_json",
"name": "input_json",
"placeholder": "{\"source_data_identifier\": \"1234\", \"data\": \"5678\"}",
"renderType": "datapath",
"required": false
}
],
"label": "artifact_create",
"name": "artifact_create"
}
},
"utilityType": "custom_function",
"values": {
"artifact_create": {
"cef_data_type": null,
"cef_field": null,
"cef_value": null,
"container": "container:id",
"input_json": "enumerate_hosts:custom_function_result.data.*.item",
"label": null,
"name": "Potential log4j Host",
"run_automation": null,
"severity": "high",
"tags": null
}
}
},
"errors": {},
"id": "19",
"type": "utility",
"userCode": "\n",
"x": 510,
"y": 304
},
"20": {
"data": {
"advanced": {
"customName": "os filter",
"customNameId": 0,
"description": "The operatingSystemFamily should be either unix, windows, or unknown. If it is unknown, both sets of playbooks should be called.",
"join": [],
"scope": "all"
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "==",
"param": "artifact:*.cef.operatingSystemFamily",
"value": "unix"
},
{
"conditionIndex": 0,
"op": "==",
"param": "artifact:*.cef.operatingSystemFamily",
"value": "unknown"
}
],
"conditionIndex": 0,
"customName": "unix_or_unknown",
"logic": "or"
},
{
"comparisons": [
{
"conditionIndex": 1,
"op": "==",
"param": "artifact:*.cef.operatingSystemFamily",
"value": "windows"
},
{
"conditionIndex": 1,
"op": "==",
"param": "artifact:*.cef.operatingSystemFamily",
"value": "unknown"
}
],
"conditionIndex": 1,
"customName": "windows_or_unknown",
"logic": "or"
}
],
"customDatapaths": {
"artifacts": {
"artifact:*.cef.operatingSystemFamily": {
"contains": [],
"isCustomDatapath": true,
"label": "artifact:*.cef.operatingSystemFamily",
"value": "artifact:*.cef.operatingSystemFamily"
}
}
},
"functionId": 1,
"functionName": "os_filter",
"id": "20",
"type": "filter"
},
"errors": {},
"id": "20",
"type": "filter",
"x": 570,
"y": 625
},
"21": {
"data": {
"advanced": {
"join": [],
"scope": "all"
},
"functionId": 2,
"functionName": "playbook_internal_host_ssh_investigate_2",
"id": "21",
"inputs": {
"ip_or_hostname": {
"datapaths": [
"filtered-data:os_filter:condition_1:artifact:*.cef.deviceHostname"
],
"deduplicate": true
}
},
"playbookName": "internal_host_ssh_investigate",
"playbookRepo": 2,
"playbookRepoName": "local",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "21",
"type": "playbook",
"x": 340,
"y": 805
},
"22": {
"data": {
"advanced": {
"join": [],
"scope": "all"
},
"functionId": 2,
"functionName": "playbook_internal_host_ssh_log4j_investigate_2",
"id": "22",
"inputs": {
"ip_or_hostname": {
"datapaths": [
"filtered-data:os_filter:condition_1:artifact:*.cef.deviceHostname"
],
"deduplicate": true
}
},
"playbookName": "internal_host_ssh_log4j_investigate",
"playbookRepo": 2,
"playbookRepoName": "local",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "22",
"type": "playbook",
"x": 0,
"y": 805
},
"23": {
"data": {
"advanced": {
"join": [],
"scope": "all"
},
"functionId": 2,
"functionName": "playbook_internal_host_winrm_investigate_2",
"id": "23",
"inputs": {
"ip_or_hostname": {
"datapaths": [
"filtered-data:os_filter:condition_2:artifact:*.cef.deviceHostname"
],
"deduplicate": true
}
},
"playbookName": "internal_host_winrm_investigate",
"playbookRepo": 2,
"playbookRepoName": "local",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "23",
"type": "playbook",
"x": 680,
"y": 805
},
"24": {
"data": {
"advanced": {
"join": [],
"scope": "all"
},
"functionId": 2,
"functionName": "playbook_internal_host_winrm_log4j_investigate_2",
"id": "24",
"inputs": {
"ip_or_hostname": {
"datapaths": [
"filtered-data:os_filter:condition_2:artifact:*.cef.deviceHostname"
],
"deduplicate": true
}
},
"playbookName": "internal_host_winrm_log4j_investigate",
"playbookRepo": 2,
"playbookRepoName": "local",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "24",
"type": "playbook",
"x": 1020,
"y": 805
},
"25": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "playbook_internal_host_splunk_investigate_log4j_1",
"id": "25",
"inputs": {
"ip_or_hostname": {
"datapaths": [
"artifact:*.cef.deviceHostname"
],
"deduplicate": true
}
},
"playbookName": "internal_host_splunk_investigate_log4j",
"playbookRepo": 2,
"playbookRepoName": "local",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "25",
"type": "playbook",
"x": 520,
"y": 404.5
}
},
"notes": "TODO: bring in a test splunk notable and add a host from that to the custom list in enumerate_hosts\n\n\n* In the block called \"fetch_hosts_from_custom_list\", change the custom list name from \"log4j_hosts\" if needed \n* If the operating system family (\"windows\" or \"unix\") is not known, both ssh and winrm will be attempted\n* If ssh and/or winrm are not the preferred endpoint management methods, these playbooks could be ported to use Google's GRR, osquery, CrowdStrike's RTR, Carbon Black's EDR API, or similar tools.\n\n* The artifact scope \"all\" is used throughout this playbook because the artifact list can be added to as the playbook progresses."
},
"input_spec": null,
"output_spec": null,
"playbook_type": "automation",
"python_version": "3",
"schema": "5.0.4",
"version": "5.1.0.70187"
},
"create_time": "2021-12-14T20:29:14.791691+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": []
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

+331
View File
@@ -0,0 +1,331 @@
"""
Published in response to CVE-2021-44228, this playbook and its sub-playbooks can be used to investigate and respond to attacks against hosts running vulnerable Java applications which use log4j.
"""
import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
phantom.debug('on_start() called')
# call 'enumerate_hosts' block
enumerate_hosts(container=container)
return
def enumerate_hosts(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("enumerate_hosts() called")
parameters = []
parameters.append({
"input_1": "log4j_hosts",
"input_2": None,
"input_3": None,
"input_4": None,
"input_5": None,
"input_6": None,
"input_7": None,
"input_8": None,
"input_9": None,
"input_10": None,
})
################################################################################
## Custom Code Start
################################################################################
# use custom code to read a custom list of potential log4j hosts and/or ip addresses
# and make a json to create an artifact for each one.
# the expected format of the custom list is:
# hostname1 | unix
# 1.1.1.1 | windows
# TODO remove this testing piece which deletes existing artifacts
container_artifact_data = phantom.collect2(container=container, datapath=["artifact:*.id","artifact:*.id"])
container_artifact_header_item_0 = [item[0] for item in container_artifact_data]
for artifact_id in container_artifact_header_item_0:
phantom.delete_artifact(artifact_id=artifact_id)
# TODO: bring in a test splunk notable and clean up the fields in that as well
custom_list_name = parameters[0]['input_1']
success, message, rows = phantom.get_list(list_name=custom_list_name)
# loop through the rows and create a list of artifact jsons to add
# the two columns are expected to be the ip_or_hostname and the operating system family
parameters = []
unix_hosts = []
windows_hosts = []
unknown_hosts = []
for row in rows:
if row[0]:
if row[1] != 'unix' and row[1] != 'windows':
os_family = 'unknown'
else:
os_family = row[1]
parameters.append({'input_1': {'cef_data': {'deviceHostname': row[0], 'operatingSystemFamily': os_family}}})
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/passthrough", parameters=parameters, name="enumerate_hosts", callback=create_artifacts)
return
def create_artifacts(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("create_artifacts() called")
id_value = container.get("id", None)
enumerate_hosts_data = phantom.collect2(container=container, datapath=["enumerate_hosts:custom_function_result.data.*.item"])
parameters = []
# build parameters list for 'create_artifacts' call
for enumerate_hosts_data_item in enumerate_hosts_data:
parameters.append({
"name": "Potential log4j Host",
"tags": None,
"label": None,
"severity": "high",
"cef_field": None,
"cef_value": None,
"container": id_value,
"input_json": enumerate_hosts_data_item[0],
"cef_data_type": None,
"run_automation": None,
})
################################################################################
## Custom Code Start
################################################################################
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/artifact_create", parameters=parameters, name="create_artifacts", callback=playbook_internal_host_splunk_investigate_log4j_1)
return
def os_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("os_filter() called")
################################################################################
# The operatingSystemFamily should be either unix, windows, or unknown. If it
# is unknown, both sets of playbooks should be called.
################################################################################
# collect filtered artifact ids and results for 'if' condition 1
matched_artifacts_1, matched_results_1 = phantom.condition(
container=container,
logical_operator="or",
conditions=[
["artifact:*.cef.operatingSystemFamily", "==", "unix"],
["artifact:*.cef.operatingSystemFamily", "==", "unknown"]
],
name="os_filter:condition_1",
scope="all")
# call connected blocks if filtered artifacts or results
if matched_artifacts_1 or matched_results_1:
playbook_internal_host_ssh_investigate_2(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
playbook_internal_host_ssh_log4j_investigate_2(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
# collect filtered artifact ids and results for 'if' condition 2
matched_artifacts_2, matched_results_2 = phantom.condition(
container=container,
logical_operator="or",
conditions=[
["artifact:*.cef.operatingSystemFamily", "==", "windows"],
["artifact:*.cef.operatingSystemFamily", "==", "unknown"]
],
name="os_filter:condition_2",
scope="all")
# call connected blocks if filtered artifacts or results
if matched_artifacts_2 or matched_results_2:
playbook_internal_host_winrm_investigate_2(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2)
playbook_internal_host_winrm_log4j_investigate_2(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2)
return
def playbook_internal_host_ssh_investigate_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("playbook_internal_host_ssh_investigate_2() called")
filtered_artifact_0_data_os_filter = phantom.collect2(container=container, datapath=["filtered-data:os_filter:condition_1:artifact:*.cef.deviceHostname"], scope="all")
filtered_artifact_0__cef_devicehostname = [item[0] for item in filtered_artifact_0_data_os_filter]
ip_or_hostname_combined_value = phantom.concatenate(filtered_artifact_0__cef_devicehostname, dedup=True)
inputs = {
"ip_or_hostname": ip_or_hostname_combined_value,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "local/internal_host_ssh_investigate", returns the playbook_run_id
playbook_run_id = phantom.playbook("local/internal_host_ssh_investigate", container=container, name="playbook_internal_host_ssh_investigate_2", inputs=inputs)
return
def playbook_internal_host_ssh_log4j_investigate_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("playbook_internal_host_ssh_log4j_investigate_2() called")
filtered_artifact_0_data_os_filter = phantom.collect2(container=container, datapath=["filtered-data:os_filter:condition_1:artifact:*.cef.deviceHostname"], scope="all")
filtered_artifact_0__cef_devicehostname = [item[0] for item in filtered_artifact_0_data_os_filter]
ip_or_hostname_combined_value = phantom.concatenate(filtered_artifact_0__cef_devicehostname, dedup=True)
inputs = {
"ip_or_hostname": ip_or_hostname_combined_value,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "local/internal_host_ssh_log4j_investigate", returns the playbook_run_id
playbook_run_id = phantom.playbook("local/internal_host_ssh_log4j_investigate", container=container, name="playbook_internal_host_ssh_log4j_investigate_2", inputs=inputs)
return
def playbook_internal_host_winrm_investigate_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("playbook_internal_host_winrm_investigate_2() called")
filtered_artifact_0_data_os_filter = phantom.collect2(container=container, datapath=["filtered-data:os_filter:condition_2:artifact:*.cef.deviceHostname"], scope="all")
filtered_artifact_0__cef_devicehostname = [item[0] for item in filtered_artifact_0_data_os_filter]
ip_or_hostname_combined_value = phantom.concatenate(filtered_artifact_0__cef_devicehostname, dedup=True)
inputs = {
"ip_or_hostname": ip_or_hostname_combined_value,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "local/internal_host_winrm_investigate", returns the playbook_run_id
playbook_run_id = phantom.playbook("local/internal_host_winrm_investigate", container=container, name="playbook_internal_host_winrm_investigate_2", inputs=inputs)
return
def playbook_internal_host_winrm_log4j_investigate_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("playbook_internal_host_winrm_log4j_investigate_2() called")
filtered_artifact_0_data_os_filter = phantom.collect2(container=container, datapath=["filtered-data:os_filter:condition_2:artifact:*.cef.deviceHostname"], scope="all")
filtered_artifact_0__cef_devicehostname = [item[0] for item in filtered_artifact_0_data_os_filter]
ip_or_hostname_combined_value = phantom.concatenate(filtered_artifact_0__cef_devicehostname, dedup=True)
inputs = {
"ip_or_hostname": ip_or_hostname_combined_value,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "local/internal_host_winrm_log4j_investigate", returns the playbook_run_id
playbook_run_id = phantom.playbook("local/internal_host_winrm_log4j_investigate", container=container, name="playbook_internal_host_winrm_log4j_investigate_2", inputs=inputs)
return
def playbook_internal_host_splunk_investigate_log4j_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("playbook_internal_host_splunk_investigate_log4j_1() called")
container_artifact_data = phantom.collect2(container=container, datapath=["artifact:*.cef.deviceHostname"])
container_artifact_cef_item_0 = [item[0] for item in container_artifact_data]
ip_or_hostname_combined_value = phantom.concatenate(container_artifact_cef_item_0, dedup=True)
inputs = {
"ip_or_hostname": ip_or_hostname_combined_value,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "local/internal_host_splunk_investigate_log4j", returns the playbook_run_id
playbook_run_id = phantom.playbook("local/internal_host_splunk_investigate_log4j", container=container, name="playbook_internal_host_splunk_investigate_log4j_1", callback=os_filter, inputs=inputs)
return
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# This function is called after all actions are completed.
# summary of all the action and/or all details of actions
# can be collected here.
# summary_json = phantom.get_summary()
# if 'result' in summary_json:
# for action_result in summary_json['result']:
# if 'action_run_id' in action_result:
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
# phantom.debug(action_results)
################################################################################
## Custom Code End
################################################################################
return
@@ -0,0 +1,39 @@
name: Log4j Investigate and Respond
id: e609d729-0076-421a-b8f7-9e545d000381
version: 1
date: '2021-12-14'
author: Philip Royer, Splunk
type: Investigate
description: Published in response to CVE-2021-44228, this playbook and its sub-playbooks can be used to investigate and respond to attacks against hosts running vulnerable Java applications which use log4j. Between the parent playbook and seven sub-playbooks, each potentially compromised host found in Splunk Enteprise can be investigated and the risk can be mitigated using SSH for unix systems and WinRM for Windows systems.
playbook: log4j_investigate_and_respond
how_to_implement: >
To start this playbook, create a custom list called "log4j_hosts" with a format as shown below
| hostname1 | unix |
| hostname2 | windows |
The first column should be an IP or hostname of a potentially affected log4j host, and the second should be the operating system family (either unix or windows). If the operating system is unknown it can be left blank. In the block called "fetch_hosts_from_custom_list", change the custom list name from "log4j_hosts" if needed. If the operating system family ("windows" or "unix") is not known, both ssh and winrm will be attempted. If ssh and/or winrm are not the preferred endpoint management methods, these playbooks could be ported to use Google's GRR, osquery, CrowdStrike's RTR, Carbon Black's EDR API, or similar tools. The artifact scope "all" is used throughout this playbook because the artifact list can be added to as the playbook progresses.
references:
- "https://github.com/Neo23x0/Fenrir/blob/master/fenrir.sh"
- "https://isc.sans.edu/diary/Log4j++Log4Shell+Followup%3A+What+we+see+and+how+to+defend+%28and+how+to+access+our+data%29/28122"
- "https://twitter.com/ElektroWolle/status/1469962895849140224?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1469962895849140224%7Ctwgr%5E%7Ctwcon%5Es1_c10&ref_url=https%3A%2F%2Fpublish.twitter.com%2F%3Fquery%3Dhttps3A2F2Ftwitter.com2FElektroWolle2Fstatus2F1469962895849140224widget%3DTweet"
- "https://blog.cloudflare.com/cve-2021-44228-log4j-rce-0-day-mitigation/"
app_list: []
tags:
platform_tags:
- Response
analytic_story:
- Log4Shell CVE-2021-44228
detections:
- Curl Download and Bash Execution
- Wget Download and Bash Execution
- Linux Java Spawning Shell
- Windows Java Spawning Shell
- Java Class File download by Java User Agent
- Outbound Network Connection from Java Using Default Ports
- Log4Shell JNDI Payload Injection Attempt
- Log4Shell JNDI Payload Injection with Outbound Connection
- Detect Outbound LDAP Traffic
playbook_fields: []
product:
- Splunk SOAR
+5 -5
View File
@@ -7,9 +7,9 @@ type: Investigation
description: This playbook gathers all of the events associated with the risk notable and imports them as artifacts. It also generates a custom markdown formatted note.
playbook: risk_notable_import_data
how_to_implement: >
'The Splunk search used to locate contributing events requires three fields in the notable artifact\: risk_object, info_min_time, and info_max_time. The query also performs some deduplication on contributing events and may need to be adjusted based on individual Enterprise Security environments. Mitre Tactics and Techniques appear if using the annotation framework in Splunk ES."
The Splunk search used to locate contributing events requires three fields in the notable artifact\: risk_object, info_min_time, and info_max_time. The query also performs some deduplication on contributing events and may need to be adjusted based on individual Enterprise Security environments. Mitre Tactics and Techniques appear if using the annotation framework in Splunk ES."
index=risk risk_object=\"{0}\" earliest=\"{1}\" latest="{2}\"
```index=risk risk_object=\"{0}\" earliest=\"{1}\" latest="{2}\"
| rex field=source \".*-\s(?<source>.*)\s+-\s+\w+\s+-\s+Rule\"
| fillnull value=\"unknown\" threat_object
| eval risk_message=coalesce(risk_message,source)
@@ -17,10 +17,10 @@ how_to_implement: >
| rename annotations.mitre_attack.mitre_technique_id as mitre_technique_id annotations.mitre_attack.mitre_tactic as mitre_tactic annotations.mitre_attack.mitre_technique as mitre_technique
| fields - annotations* risk_object_* date_* orig_* user_* src_user_* src_* dest_* dest_user_* info_* search_* splunk_* tag* risk_modifier* risk_rule* sourcetype timestamp index next_cron_time timeendpos timestartpos testmode linecount
| sort + _time
| \`uitime(_time)\`
| dedup source threat_object
| `uitime(_time)`
| dedup source threat_object```
A custom code block sorts the returned event data and produces a markdown formatted note into the note_content output field. This field is then available for use in downstream playbooks."'
A custom code block sorts the returned event data and produces a markdown formatted note into the note_content output field. This field is then available for use in downstream playbooks."
references:
- https://docs.splunk.com/Documentation/ESSOC/latest/user/Useplaybookpack
- http://docs.splunk.com/Documentation/ES/6.6.2/Admin/Configurecorrelationsearches#Use_security_framework_annotations_in_correlation_searches
+24
View File
@@ -0,0 +1,24 @@
name: Log4Shell CVE-2021-44228
id: b4453928-5a98-11ec-afcd-8de10b48fc52
version: 1
date: '2021-12-11'
author: Jose Hernandez
description: 'Log4Shell or CVE-2021-44228 is a Remote Code Execution (RCE) vulnerability in the Apache Log4j library, a widely used and ubiquitous logging framework for Java.
The vulnerability allows an attacker who can control log messages to execute arbitrary code loaded from attacker-controlled servers and we anticipate that most apps using the Log4j library will meet this condition.'
narrative: 'In late November 2021, Chen Zhaojun of Alibaba identified a remote code execution vulnerability. Previous work was seen in a 2016 Blackhat talk by Alvaro Munoz and Oleksandr Mirosh called ["A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land"](https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf). Reported under the CVE ID : CVE-2021-44228, released to the public on December 10, 2021. The vulnerability is exploited through improper deserialization of user input passed into the framework. It permits remote code execution and it can allow an attacker to leak sensitive data, such as environment variables, or execute malicious software on the target system.'
references:
- https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/
- https://www.fastly.com/blog/digging-deeper-into-log4shell-0day-rce-exploit-found-in-log4j
- https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/
- https://www.lunasec.io/docs/blog/log4j-zero-day/
- https://www.splunk.com/en_us/blog/security/log-jammin-log4j-2-rce.html
tags:
analytic_story:
- Log4Shell CVE-2021-44228
category:
- Adversary Tactics
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
usecase: Application Security
@@ -0,0 +1,12 @@
name: Curl Download and Bash Execution Unit Test
tests:
- name: Curl Download and Bash Execution
file: endpoint/curl_download_and_bash_execution.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: linux-sysmon_curlwget.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log
source: Syslog:Linux-Sysmon/Operational
sourcetype: sysmon_linux
@@ -0,0 +1,12 @@
name: Hunting for Log4Shell Unit Test
tests:
- name: Hunting for Log4Shell
file: endpoint/hunting_for_log4shell.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: log4shell-nginx.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/log4shell-nginx.log
source: /var/log/nginx/access.log
sourcetype: nginx:plus:kv
@@ -0,0 +1,13 @@
name: Java Class File download by Java User Agent Unit Test
tests:
- name: Java Class File download by Java User Agent
file: endpoint/java_class_file_download_by_java_user_agent.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: java.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/java/java.log
source: stream:http
sourcetype: stream:http
@@ -0,0 +1,12 @@
name: Outbound Network Connection from Java Using Default Ports Unit Test
tests:
- name: Outbound Network Connection from Java Using Default Ports
file: endpoint/outbound_network_connection_from_java_using_default_ports.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: linux-sysmon.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_java/linux-sysmon.log
source: Syslog:Linux-Sysmon/Operational
sourcetype: sysmon_linux
@@ -0,0 +1,12 @@
name: Wget Download and Bash Execution Unit Test
tests:
- name: Wget Download and Bash Execution
file: endpoint/wget_download_and_bash_execution.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: linux-sysmon_curlwget.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1105/atomic_red_team/linux-sysmon_curlwget.log
source: Syslog:Linux-Sysmon/Operational
sourcetype: sysmon_linux
@@ -0,0 +1,12 @@
name: Detect Outbound LDAP Traffic Unit Test
tests:
- name: Detect Outbound LDAP Traffic
file: network/detect_outbound_ldap_traffic.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-30d'
latest_time: 'now'
attack_data:
- file_name: stream_http_events.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/outbound_ldap/bro_conn.json
sourcetype: bro:conn:json
source: /opt/malware/conn.log
@@ -0,0 +1,12 @@
name: Log4Shell JNDI Payload Injection Attempt Unit Test
tests:
- name: Log4Shell JNDI Payload Injection Attempt
file: web/log4shell_jndi_payload_injection_attempt.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-24h'
latest_time: 'now'
attack_data:
- file_name: nginx.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log
source: nginx
sourcetype: nginx:plus:kv
@@ -0,0 +1,16 @@
name: Log4Shell JNDI Payload Injection with Outbound Connection Unit Test
tests:
- name: Log4Shell JNDI Payload Injection with Outbound Connection
file: web/log4shell_jndi_payload_injection_with_outbound_connection.yml
pass_condition: '| stats count | where count > 0'
earliest_time: '-360d'
latest_time: 'now'
attack_data:
- file_name: nginx.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_proxy_logs/log4j_proxy_logs.log
source: nginx
sourcetype: nginx:plus:kv
- file_name: stream.log
data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/log4j_network_logs/log4j_network_logs.log
source: stream:Splunk_IP
sourcetype: stream:ip