Branch was auto-updated.
@@ -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
|
||||
@@ -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,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
|
||||
#############
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
#############
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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
|
||||

|
||||
|
||||
#### 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
|
||||

|
||||
|
||||
#### 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
|
||||

|
||||
|
||||
#### 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 "jndilookup.class" 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
|
||||

|
||||
|
||||
#### 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
|
||||

|
||||
|
||||
#### Required field
|
||||
|
||||
|
||||
#### Reference
|
||||
|
||||
|
||||
|
||||
[*source*](https://github.com/splunk/security_content/tree/develop/playbooks/internal_host_winrm_log4j_respond.yml) \| *version*: **1**
|
||||
@@ -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 & Identities, as well as the Endpoint.Processes datamodel
|
||||
|
||||
#### Playbooks
|
||||

|
||||
|
||||
#### 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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ This playbook gathers all of the events associated with the risk notable and imp
|
||||
|
||||
|
||||
#### 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."
|
||||
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) | 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."'
|
||||
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}\" | rex field=source \".*-\s(?<source>.*)\s+-\s+\w+\s+-\s+Rule\" | fillnull value=\"unknown\" 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."
|
||||
|
||||
|
||||
#### 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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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'
|
||||
|
||||
|
||||
|
||||
#### 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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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'
|
||||
* [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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 "sh", "ksh", "zsh", "bash", "dash", "rbash", "fish", "csh', "tcsh', "ion", "eshell". 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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 "cmd.exe", "powershell.exe". 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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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 "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.
|
||||
|
||||
- **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'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 <=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 (>2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” or it can be mitigated in prior releases (<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**
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
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"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 254 KiB |
@@ -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"
|
||||
]
|
||||
}
|
||||
|
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
|
||||
|
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"
|
||||
]
|
||||
}
|
||||
|
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 \"\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"
|
||||
]
|
||||
}
|
||||
|
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 "jndilookup.class" 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 "
|
||||
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
|
||||
|
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": []
|
||||
}
|
||||
|
After Width: | Height: | Size: 184 KiB |
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||