Detection rules › Panther
VPC Flow Logs Unapproved Outbound DNS Traffic
Alerts if outbound DNS traffic is detected to a non-approved DNS server. DNS is often used as a means to exfiltrate data or perform command and control for compromised hosts. All DNS traffic should be routed through internal DNS servers or trusted 3rd parties.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Command & Control | T1071 Application Layer Protocol |
Rule body yaml
AnalysisType: rule
Filename: aws_vpc_unapproved_outbound_dns.py
RuleID: "AWS.VPC.UnapprovedOutboundDNS"
DisplayName: "VPC Flow Logs Unapproved Outbound DNS Traffic"
Enabled: false
LogTypes:
- AWS.VPCFlow
- OCSF.NetworkActivity
Tags:
- AWS
- DataModel
- Configuration Required
- Security Control
- Command and Control:Application Layer Protocol
Reports:
MITRE ATT&CK:
- TA0011:T1071
Reference: https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html
Severity: Medium
Description: >
Alerts if outbound DNS traffic is detected to a non-approved DNS server. DNS is often used as a means to exfiltrate data or perform command and control for compromised hosts. All DNS traffic should be routed through internal DNS servers or trusted 3rd parties.
Runbook: >
Investigate the host sending unapproved DNS activity for signs of compromise or other malicious activity. Update network configurations appropriately to ensure all DNS traffic is routed to approved DNS servers.
SummaryAttributes:
- srcaddr
- dstaddr
- dstport
Tests:
- Name: Approved Outbound DNS Traffic
ExpectedResult: false
Log:
{
"dstPort": 53,
"dstAddr": "1.1.1.1",
"srcAddr": "10.0.0.1",
"p_log_type": "AWS.VPCFlow",
}
- Name: Unapproved Outbound DNS Traffic
ExpectedResult: true
Log:
{
"dstPort": 53,
"dstAddr": "100.100.100.100",
"srcAddr": "10.0.0.1",
"p_log_type": "AWS.VPCFlow",
}
- Name: Outbound Non-DNS Traffic
ExpectedResult: false
Log:
{
"dstPort": 80,
"dstAddr": "100.100.100.100",
"srcAddr": "10.0.0.1",
"p_log_type": "AWS.VPCFlow",
}
- Name: Approved Outbound DNS Traffic - OCSF
ExpectedResult: false
Log:
{
"dst_endpoint": { "ip": "1.1.1.1", "port": 53 },
"src_endpoint": { "ip": "10.0.0.1" },
"p_log_type": "OCSF.NetworkActivity",
}
- Name: Unapproved Outbound DNS Traffic - OCSF
ExpectedResult: true
Log:
{
"dst_endpoint": { "ip": "100.100.100.100", "port": 53 },
"src_endpoint": { "ip": "10.0.0.1" },
"p_log_type": "OCSF.NetworkActivity",
}
Detection logic
Condition
not (destination_port ne "53" and destination_port ne "5353")
destination_ip is_not_null
destination_ip not in ["1.1.1.1", "8.8.8.8"]
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 |
|---|---|---|
destination_port | ne | 53 |
destination_port | ne | 5353 |
destination_ip | in | 1.1.1.1, 8.8.8.8 |
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.
| Field | Kind | Values |
|---|---|---|
destination_ip | is_not_null |
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 |