Detection rules › Splunk

Internal Port Scan - Critical Ports (Windows Event Log)

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

After gaining an initial foothold, threat actors may attempt to identify services operating on hosts within the network, often using legitimate port scanning software. This use case detects when more than 5 of the following ports have been scanned from a single internal source IP within one minute: 21 (FTP), 22 (SSH), 23 (Telnet), 25 (SMTP), 80 (HTTP), 8080 (Alternative HTTP), 139 (NetBIOS/SMB), 389 (LDAP), 443 (HTTPS), 8443 (Alternative HTTPS), 445 (Microsoft-DS/SMB), 3306 (MySQL), 3389 (RDP).

MITRE ATT&CK coverage

TacticTechniques
DiscoveryT1046 Network Service Discovery

References

Event coverage

Rule body yaml

id: '26208.48343'
title: Internal Port Scan - Critical Ports
description: 'After gaining an initial foothold, threat actors may attempt to identify
  services operating on hosts within the network, often using legitimate port scanning
  software. This use case detects when more than 5 of the following ports have been
  scanned from a single internal source IP within one minute: 21 (FTP), 22 (SSH),
  23 (Telnet), 25 (SMTP), 80 (HTTP), 8080 (Alternative HTTP), 139 (NetBIOS/SMB), 389
  (LDAP), 443 (HTTPS), 8443 (Alternative HTTPS), 445 (Microsoft-DS/SMB), 3306 (MySQL),
  3389 (RDP). '
logic_format: Splunk
logic: '`get_endpoint_data` `get_endpoint_data_winevent` (TERM(EventCode=5152) OR
  "<EventID>5152<" OR TERM(EventCode=5156) OR "<EventID>5156<") | where match(src_ip,
  "(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})")
  and match(dest_port, "^(21|22|23|25|80|8080|139|389|443|8443|445|3306|3389)$") and
  not match(process_path, "(?i)\x5csplunkuniversalforwarder\x5cbin\x5csplunkd\.exe")
  | table _time, host, user, signature_id, process, process_*, dest_port, dest_ip,
  src_ip | bin span=60s | stats values(*) as * by _time, host | streamstats dc(dest_port)
  as dc_dest_port by _time, src_ip| where dc_dest_port>5 '
techniques:
- discovery:network service discovery
technique_id: 
- T1046
data_category:
- Windows event logs
references:
- https://www.fortinet.com/content/dam/fortinet/assets/threat-reports/rhysida-ransomware-intrusion.pdf?utm_source=blog&utm_medium=blog&utm_campaign=rhysida-ransomware
- https://www.advanced-port-scanner.com/

Stages and Predicates

Stage 1: search

`get_endpoint_data` `get_endpoint_data_winevent` (TERM(EventCode=5152) OR "<EventID>5152<" OR TERM(EventCode=5156) OR "<EventID>5156<")

Stage 2: where

| where match(src_ip, "(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})") and match(dest_port, "^(21|22|23|25|80|8080|139|389|443|8443|445|3306|3389)$") and not match(process_path, "(?i)\x5csplunkuniversalforwarder\x5cbin\x5csplunkd\.exe")

Stage 3: table

| table _time, host, user, signature_id, process, process_*, dest_port, dest_ip, src_ip

Stage 4: bucket

| bin span=60s

Stage 5: stats

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

Stage 6: streamstats

| streamstats dc(dest_port) as dc_dest_port by _time, src_ip

Stage 7: where

| where dc_dest_port>5

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
process_pathmatch"(?i)\x5csplunkuniversalforwarder\x5cbin\x5csplunkd\.exe"

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
EventCodeeq
  • 5152
  • 5156 corpus 15 (splunk 13, kusto 2)
dc_dest_portgt
  • 5
dest_portmatch
  • "^(21|22|23|25|80|8080|139|389|443|8443|445|3306|3389)$"
src_ipmatch
  • "(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})"

Search terms

Bare-string tokens in the SPL search body. Splunk matches each token against _raw (the untyped raw event text) anywhere it appears, not against a specific field. These don't surface in the Indicators table because they aren't predicates on a known field.

StageTerm
1TERM
1"<EventID>5152<"
1TERM
1"<EventID>5156<"