Detection rules › Panther
Signal - VPC Flow Logs Allowed SSH
VPC Flow Logs observed inbound traffic on SSH port. This rule is a signal to be used in correlation rules.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Lateral Movement | T1021.004 Remote Services: SSH |
Rule body yaml
AnalysisType: rule
Filename: aws_vpc_ssh_allowed_signal.py
RuleID: "AWS.VPC.SSHAllowedSignal"
DisplayName: "Signal - VPC Flow Logs Allowed SSH"
Enabled: true
CreateAlert: false
LogTypes:
- AWS.VPCFlow
Tags:
- AWS
- Signal
Reports:
MITRE ATT&CK:
- TA0008:T1021.004 # Lateral Movement: Remote Services: SSH
Severity: Info
Description: >
VPC Flow Logs observed inbound traffic on SSH port.
This rule is a signal to be used in correlation rules.
Tests:
- Name: Public to Private IP on SSH Allowed
ExpectedResult: true
Log:
{
"dstPort": 22,
"dstAddr": "10.0.0.1",
"srcAddr": "1.1.1.1",
"instanceId": "i-0d4c7318592c6a2c7",
"action": "ACCEPT",
"p_log_type": "AWS.VPCFlow",
}
- Name: Public to Private IP on non-SSH
ExpectedResult: false
Log:
{
"dstPort": 443,
"dstAddr": "10.0.0.1",
"srcAddr": "1.1.1.1",
"instanceId": "i-0d4c7318592c6a2c7",
"action": "ACCEPT",
"p_log_type": "AWS.VPCFlow",
}
- Name: Private to Private IP on SSH
ExpectedResult: false
Log:
{
"dstPort": 22,
"dstAddr": "10.0.0.1",
"srcAddr": "10.10.10.1",
"instanceId": "i-0d4c7318592c6a2c7",
"action": "ACCEPT",
"p_log_type": "AWS.VPCFlow",
}
- Name: Public to Private IP on SSH Denied
ExpectedResult: false
Log:
{
"dstPort": 22,
"dstAddr": "10.0.0.1",
"srcAddr": "1.1.1.1",
"instanceId": "i-0d4c7318592c6a2c7",
"action": "REJECT",
"p_log_type": "AWS.VPCFlow",
}
Detection logic
Condition
not (destination_port ne "22" or action ne "ACCEPT")
This rule also runs imperative logic the parser cannot express as a filter; the conditions above are the structured part it could extract.
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
action | ne | ACCEPT |
destination_port | ne | 22 |
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field |
|---|
eventName |
eventSource |
awsRegion |
recipientAccountId |
sourceIPAddress |
userAgent |
userIdentity |