Detection rules › Splunk

Scheduled Task with Potential SSH Tunnel - Windows (Sysmon)

Group by
_time, host
Source
github.com/anvilogic-forge/armory

Threat actors have been observed using scheduled tasks to create reverse SSH tunnels to facilitate persistence on a compromised machine as reported by DFIR. This use case detects scheduled tasks created with commands indicating potential SSH tunnels. The regex filtering matches on the patterns <user>@<IP address> and <port number>:<IP Address> :<port number>

MITRE ATT&CK coverage

TacticTechniques
Execution
Persistence
Privilege Escalation
Command & Control

References

Telemetry coverage

ProviderRecord / event type
SysmonEvent ID 1: Process creation

Rule body

id: '25326.47104'
title: Scheduled Task with Potential SSH Tunnel - Windows
description: Threat actors have been observed using scheduled tasks to create reverse
  SSH tunnels to facilitate persistence on a compromised machine as reported by DFIR.
  This use case detects scheduled tasks created with commands indicating potential
  SSH tunnels. The regex filtering matches on the patterns <user>@<IP address> and
  <port number>:<IP Address> :<port number>. Living Off the Land Binary and Scripts
  (LOLBAS) (LOLBIN)
logic_format: Splunk
logic: '`get_endpoint_data` `get_endpoint_data_sysmon` (TERM(EventCode=1) OR "<EventID>1<")
  "@" "/create" ("-L" OR "-R" OR "-N" OR "-D" OR "-C" OR "IdentitiesOnly=yes" OR "StrictHostKeyChecking=no"
  OR "ssh") | where match(process, "\w+@\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") and match(process,
  "\d{1,5}:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}") and match(process, "(?i)\-(L|R|N|D|C)|IdentitiesOnly=yes|StrictHostKeyChecking=no|ssh")
  | table _time, host, user, process, process_*, parent_process_name, parent_process_*,
  signature_id | bin span=1s | stats values(*) as * by _time, host '
techniques:
- execution:scheduled task/job
- command-and-control:protocol tunneling
technique_id: 
- T1053
- T1572
data_category:
- Windows Sysmon
references:
- https://thedfirreport.com/2023/10/30/netsupport-intrusion-results-in-domain-compromise/

Stages and Predicates

Stage 1: search

`get_endpoint_data` `get_endpoint_data_sysmon` (TERM(EventCode=1) OR "<EventID>1<") "@" "/create" ("-L" OR "-R" OR "-N" OR "-D" OR "-C" OR "IdentitiesOnly=yes" OR "StrictHostKeyChecking=no" OR "ssh")

Stage 2: where

| where match(process, "\w+@\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") and match(process, "\d{1,5}:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}") and match(process, "(?i)\-(L|R|N|D|C)|IdentitiesOnly=yes|StrictHostKeyChecking=no|ssh")

Stage 3: table

| table _time, host, user, process, process_*, parent_process_name, parent_process_*, signature_id

Stage 4: bucket

| bin span=1s

Stage 5: stats

| stats values(*) as * by _time, host

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventCodeeq
  • 1 corpus 241 (splunk 225, kusto 15, elastic 1)
field:"EventID" kind:eq value:"1"
processregex_match
    • "(?i)\-(L|R|N|D|C)
    • IdentitiesOnly=yes
    • StrictHostKeyChecking=no
    • ssh"
    corpus 3 (splunk 3)
  • "\d{1,5}:\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}:\d{1,5}" corpus 3 (splunk 3)
  • "\w+@\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}" corpus 3 (splunk 3)
field:"CommandLine" kind:regex_match

Search terms

These SPL tokens match against raw event text.

StageTerm
1"<EventID>1<"
1"@"
1"/create"
1"-L"
1"-R"
1"-N"
1"-D"
1"-C"
1"IdentitiesOnly=yes"
1"StrictHostKeyChecking=no"
1"ssh"