Detection rules › Panther
Panther rules: vpc
| Rule | Severity |
|---|---|
| Query.VPC.DNS.Tunneling | |
| VPC DNS Tunneling | medium |
Query.VPC.DNS.Tunneling
#Detect activity similar to DNS tunneling traffic in AWS VPC Logs
Rule specification
AnalysisType: scheduled_query
QueryName: "Query.VPC.DNS.Tunneling"
Enabled: false
Description: >
Detect activity similar to DNS tunneling traffic in AWS VPC Logs
SnowflakeQuery: |
SELECT
account_id,
region,
vpc_id,
srcAddr, -- outside
srcIds:instance as instance, -- inside
COUNT(1) as message_count,
ARRAY_AGG(DISTINCT query_name) as query_names
FROM
panther_logs.public.aws_vpcdns
WHERE
p_occurs_since(3600) -- 1 hour in seconds
AND
-- simple allowlisting
query_name NOT LIKE '%amazonaws.com'
GROUP BY
1,2,3,4,5
HAVING
message_count >= 1000 -- decent amount of activity in an hour
AND
ARRAY_SIZE(query_names) <= 2 -- only a small number of distinct domains (not likely a real dns server!)
DatabricksQuery: |
SELECT
account_id,
region,
vpc_id,
srcAddr, -- outside
srcIds:instance as instance, -- inside
COUNT(1) as message_count,
COLLECT_SET(query_name) as query_names
FROM
panther_logs.aws_vpcdns
WHERE
p_occurs_since(3600) -- 1 hour in seconds
AND
-- simple allowlisting
query_name NOT LIKE '%amazonaws.com'
GROUP BY
1,2,3,4,5
HAVING
message_count >= 1000 -- decent amount of activity in an hour
AND
SIZE(query_names) <= 2 -- only a small number of distinct domains (not likely a real dns server!)
Schedule:
RateMinutes: 60
TimeoutMinutes: 1
Stages and Predicates
Stage 1: source
Stage 2: filter
query_namedoes not match the pattern*amazonaws.com
Stage 3: having
message_countis at least1000
This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
query_name | ends_with | amazonaws.com | excludes:query_name field:"query_name" value:"amazonaws.com" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
message_count | ge |
| field:"message_count" kind:ge value:"1000" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
account_id | |
region | |
vpc_id | |
srcAddr | |
instance | srcIds:instance |
message_count | COUNT ( 1 ) |
query_names | ARRAY_AGG ( DISTINCT query_name ) |
VPC DNS Tunneling
#Detect dns tunneling traffic using a scheduled query
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Detection logic
def rule(_):
return True
Rule specification
AnalysisType: scheduled_rule
Filename: vpc_dns_tunneling.py
RuleID: "VPC.DNS.Tunneling"
DisplayName: "VPC DNS Tunneling"
Description: >
Detect dns tunneling traffic using a scheduled query
Reports:
MITRE ATT&CK:
- TA0005:T1599
Tags:
- Defense Evasion:Network Boundary Bridging
Enabled: false
ScheduledQueries:
- Query.VPC.DNS.Tunneling
Severity: Medium
Stages and Predicates
Rule logic
This rule alerts on rows returned by its scheduled query Query.VPC.DNS.Tunneling; its Python module (Detection logic above) shapes the alert rather than filtering.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"Anything": "any value"
}