Skip to content

Add DNS PTR-Based Host Discovery Detection - #4332

Open
MehrabBakhtar wants to merge 3 commits into
splunk:developfrom
MehrabBakhtar:develop
Open

MehrabBakhtar wants to merge 3 commits into
splunk:developfrom
MehrabBakhtar:develop

Conversation

@MehrabBakhtar

Copy link
Copy Markdown

Summary

Add a detection for potential host discovery through high-volume DNS PTR queries.

Use the Network Resolution data model with tstats.

Identify source systems generating 80 or more unique PTR queries.

Include implementation guidance, false-positive considerations, and MITRE ATT&CK mapping to T1018 (Remote System Discovery).

Testing

Validated the detection using contentctl-ng build.

Confirmed the content build completed successfully.

status: experimental
type: Anomaly
description: This detection identifies source systems generating a high number of unique DNS PTR queries, which may indicate host discovery or reverse DNS reconnaissance. This activity may be associated with tools such as Nmap when reverse DNS lookups are performed for discovered or scanned hosts.
data_source: []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We require a data source to be used here except in edge cases. What data did you test against?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested the detection using Windows DNS logs (MSAD:NT6:DNS). I couldn't find a matching data source definition in the repository, so I've uploaded sanitized JSON log samples for review.
The detection can also work with Zeek DNS and Stream DNS logs, provided the required fields are mapped to the Network_Resolution data model.
The goal is to identify a high number of distinct PTR queries generated by a single source. Nmap may perform reverse DNS lookups during host discovery, making this behavior useful for detecting potential network reconnaissance when appropriate thresholds and noise filtering are applied.

1791704186_3984387.json

Comment on lines +40 to +44
tests:
- name: Manual Validation
description: Manually validate that a source generating at least 80 unique DNS PTR queries is returned by the detection.
test_type: experimental
attack_data: []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discourage having rules without data. Please upload your test data to https://github.com/splunk/attack_data and link it here.

Else, upload the log samples here and we will take care of it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are sample log events showing the burst of PTR queries generated during host discovery:

1791704186_3984387.json

{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"236.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"235.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"234.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"237.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"238.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"243.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"250.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"221.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"248.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"11.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"253.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"3.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"1.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"245.29.16.172.in-addr.arpa","record_type":"PTR"}}

Comment on lines +27 to +28
references:
- https://attack.mitre.org/techniques/T1018/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We highly recommend putting useful references where possible. Could link to some public reference that talk about PTR/Attacks in that sense?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

references:

Added the official Nmap DNS Resolution documentation (https://nmap.org/book/host-discovery-dns.html). This confirms that Nmap, by default, initiates a reverse-DNS PTR query for every host that responds to host discovery probes. This effectively pairs each discovery attempt with a corresponding resolution request, creating the predictable pattern that this detection is designed to identify.

Comment thread detections/network/dns_ptr_based_host_discovery.yml Outdated
description: This detection identifies source systems generating a high number of unique DNS PTR queries, which may indicate host discovery or reverse DNS reconnaissance. This activity may be associated with tools such as Nmap when reverse DNS lookups are performed for discovered or scanned hosts.
data_source: []
search: |-
| tstats `security_content_summariesonly` min(_time) as firsttime max(_time) as lasttime dc(DNS.query) AS unique_queries FROM datamodel=Network_Resolution WHERE DNS.record_type="PTR" BY DNS.src

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output will contain src and queries, try and bring other useful to the output as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detection uses a threshold of 80 unique PTR queries per source to identify potential host discovery activity.
I avoided collecting all queried DNS names by default to keep the search efficient, as values(DNS.query) may increase resource usage and result size.
However, if you believe displaying the queried names would be more useful, we can modify the query as follows:
| tstats security_content_summariesonly min(_time) as firsttime max(_time) as lasttime dc(DNS.query) AS unique_queries values(DNS.query) as all_dns_queries FROM datamodel=Network_Resolution WHERE DNS.record_type="PTR" BY DNS.src

I'm happy to adjust the output based on your preference.

Co-authored-by: Nasreddine Bencherchali <nbencher@cisco.com>

@MehrabBakhtar MehrabBakhtar left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! This is my very first contribution to this project, so I really appreciate your patience and help.
I've addressed the feedback and updated the references and log samples. Looking forward to your next comments/feedback!

status: experimental
type: Anomaly
description: This detection identifies source systems generating a high number of unique DNS PTR queries, which may indicate host discovery or reverse DNS reconnaissance. This activity may be associated with tools such as Nmap when reverse DNS lookups are performed for discovered or scanned hosts.
data_source: []

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested the detection using Windows DNS logs (MSAD:NT6:DNS). I couldn't find a matching data source definition in the repository, so I've uploaded sanitized JSON log samples for review.
The detection can also work with Zeek DNS and Stream DNS logs, provided the required fields are mapped to the Network_Resolution data model.
The goal is to identify a high number of distinct PTR queries generated by a single source. Nmap may perform reverse DNS lookups during host discovery, making this behavior useful for detecting potential network reconnaissance when appropriate thresholds and noise filtering are applied.

1791704186_3984387.json

description: This detection identifies source systems generating a high number of unique DNS PTR queries, which may indicate host discovery or reverse DNS reconnaissance. This activity may be associated with tools such as Nmap when reverse DNS lookups are performed for discovered or scanned hosts.
data_source: []
search: |-
| tstats `security_content_summariesonly` min(_time) as firsttime max(_time) as lasttime dc(DNS.query) AS unique_queries FROM datamodel=Network_Resolution WHERE DNS.record_type="PTR" BY DNS.src

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detection uses a threshold of 80 unique PTR queries per source to identify potential host discovery activity.
I avoided collecting all queried DNS names by default to keep the search efficient, as values(DNS.query) may increase resource usage and result size.
However, if you believe displaying the queried names would be more useful, we can modify the query as follows:
| tstats security_content_summariesonly min(_time) as firsttime max(_time) as lasttime dc(DNS.query) AS unique_queries values(DNS.query) as all_dns_queries FROM datamodel=Network_Resolution WHERE DNS.record_type="PTR" BY DNS.src

I'm happy to adjust the output based on your preference.

Comment on lines +27 to +28
references:
- https://attack.mitre.org/techniques/T1018/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

references:

Added the official Nmap DNS Resolution documentation (https://nmap.org/book/host-discovery-dns.html). This confirms that Nmap, by default, initiates a reverse-DNS PTR query for every host that responds to host discovery probes. This effectively pairs each discovery attempt with a corresponding resolution request, creating the predictable pattern that this detection is designed to identify.

Comment on lines +40 to +44
tests:
- name: Manual Validation
description: Manually validate that a source generating at least 80 unique DNS PTR queries is returned by the detection.
test_type: experimental
attack_data: []

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are sample log events showing the burst of PTR queries generated during host discovery:

1791704186_3984387.json

{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"236.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"235.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"234.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"237.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"238.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"243.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"250.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"221.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"248.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"11.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"253.29.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"3.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"1.30.16.172.in-addr.arpa","record_type":"PTR"}}
{"preview":false,"result":{"_time":"2026-10-11T11:06:24.000+0330","src":"172.19.26.167","query":"245.29.16.172.in-addr.arpa","record_type":"PTR"}}

@nasbench nasbench added this to the v6.10.0 milestone Oct 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants