Detection rules › Splunk

Windows PowerShell Script Block With Malicious String

Status
production
Severity
medium
Group by
dest, signature, signature_id, user_id, vendor_product
Author
Steven Dick
Source
github.com/splunk/security_content

The following analytic detects the execution of multiple offensive toolkits and commands by leveraging PowerShell Script Block Logging (EventCode=4104). This method captures and logs the full command sent to PowerShell, allowing for the identification of suspicious activities including several well-known tools used for credential theft, lateral movement, and persistence. If confirmed malicious, this could lead to unauthorized access, privilege escalation, and potential compromise of sensitive information within the environment.

Known false positives

  • No false positives have been identified at this time. commands with overlap.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

name: Windows PowerShell Script Block With Malicious String
id: 0f09cedd-10f1-4b9f-bdea-7a8b06ea575d
version: 7
creation_date: '2025-01-13'
modification_date: '2026-05-13'
author: Steven Dick
status: production
type: TTP
description: The following analytic detects the execution of multiple offensive toolkits and commands by leveraging PowerShell Script Block Logging (EventCode=4104). This method captures and logs the full command sent to PowerShell, allowing for the identification of suspicious activities including several well-known tools used for credential theft, lateral movement, and persistence. If confirmed malicious, this could lead to unauthorized access, privilege escalation, and potential compromise of sensitive information within the environment.
data_source:
    - Powershell Script Block Logging 4104
search: '`powershell` ScriptBlockText=* EventCode=4104 | stats count min(_time) as firstTime max(_time) as lastTime list(ScriptBlockText) as command values(Guid) as Guid values(Opcode) as Opcode values(Name) as Name values(Path) as Path values(ProcessID) as ProcessID values(ScriptBlockId) as ScriptBlockId values(ScriptBlockText) as ScriptBlockText by dest signature signature_id user_id vendor_product | eval command = mvjoin(command,"\n") | lookup malicious_powershell_strings command | where isnotnull(match) | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)` | `windows_powershell_script_block_with_malicious_string_filter`'
how_to_implement: The following analytic requires PowerShell operational logs to be imported. Modify the powershell macro as needed to match the sourcetype or add index. This analytic is specific to 4104, or PowerShell Script Block Logging.
known_false_positives: No false positives have been identified at this time. commands with overlap.
references:
    - https://attack.mitre.org/techniques/T1059/001/
    - https://github.com/PowerShellMafia/PowerSploit
    - https://github.com/PowerShellEmpire/
    - https://github.com/S3cur3Th1sSh1t/PowerSharpPack
finding:
    title: The user $user_id$ ran a known malicious PowerShell string matching *$match$* on $dest$
    entity:
        field: dest
        type: system
        score: 50
threat_objects:
    - field: signature_id
      type: signature
analytic_story:
    - Malicious PowerShell
asset_type: Endpoint
mitre_attack_id:
    - T1059.001
product:
    - Splunk Enterprise
    - Splunk Enterprise Security
    - Splunk Cloud
category: endpoint
security_domain: threat

Stages and Predicates

Stage 1: search

`powershell` ScriptBlockText=* EventCode=4104

Stage 2: stats

| stats count min(_time) as firstTime max(_time) as lastTime list(ScriptBlockText) as command values(Guid) as Guid values(Opcode) as Opcode values(Name) as Name values(Path) as Path values(ProcessID) as ProcessID values(ScriptBlockId) as ScriptBlockId values(ScriptBlockText) as ScriptBlockText by dest signature signature_id user_id vendor_product

Stage 3: eval

| eval command = mvjoin(command,"\n")

Stage 4: lookup

| lookup malicious_powershell_strings command
Lookup table
malicious_powershell_strings
Key field
command

Stage 5: where

| where isnotnull(match)

Stage 6: search

| `security_content_ctime(firstTime)`

Stage 7: search

| `security_content_ctime(lastTime)`

Stage 8: search

| `windows_powershell_script_block_with_malicious_string_filter`

Indicators

These rows show field, operator, and value matches.