System Public IP Discovery via DNS Query

Identifies DNS queries to known public IP address lookup web services from suspicious Windows processes, which can reveal external IP or internet-connectivity discovery before follow-on activity.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2025/08/20"
  3integration = ["endpoint", "windows", "sentinel_one_cloud_funnel", "crowdstrike"]
  4maturity = "production"
  5updated_date = "2026/05/06"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies DNS queries to known public IP address lookup web services from suspicious Windows processes, which
 11can reveal external IP or internet-connectivity discovery before follow-on activity.
 12"""
 13from = "now-9m"
 14index = [
 15    "endgame-*",
 16    "logs-endpoint.events.network-*",
 17    "logs-sentinel_one_cloud_funnel.*",
 18    "logs-crowdstrike.fdr*",
 19    "logs-windows.forwarded*",
 20    "logs-windows.sysmon_operational-*",
 21    "winlogbeat-*"
 22]
 23language = "eql"
 24license = "Elastic License v2"
 25name = "System Public IP Discovery via DNS Query"
 26references = ["https://attack.mitre.org/techniques/T1016/"]
 27risk_score = 73
 28rule_id = "642ce354-4252-4d43-80c9-6603f16571c1"
 29severity = "high"
 30tags = [
 31    "Domain: Endpoint",
 32    "OS: Windows",
 33    "Use Case: Threat Detection",
 34    "Tactic: Discovery",
 35    "Tactic: Command and Control",
 36    "Resources: Investigation Guide",
 37    "Data Source: Elastic Endgame",
 38    "Data Source: Elastic Defend",
 39    "Data Source: SentinelOne",
 40    "Data Source: Crowdstrike",
 41    "Data Source: Sysmon",
 42]
 43timestamp_override = "event.ingested"
 44type = "eql"
 45
 46query = '''
 47network where host.os.type == "windows" and dns.question.name != null and process.name != null and
 48(
 49  process.name : ("MSBuild.exe", "mshta.exe", "wscript.exe", "powershell.exe", "pwsh.exe", "msiexec.exe", "rundll32.exe",
 50  "bitsadmin.exe", "InstallUtil.exe", "RegAsm.exe", "vbc.exe", "RegSvcs.exe", "python.exe", "regsvr32.exe", "dllhost.exe",
 51  "node.exe", "javaw.exe", "java.exe", "*.pif", "*.com", "curl.exe", "bun.exe") or
 52
 53  (?process.code_signature.trusted == false or ?process.code_signature.exists == false) or
 54
 55  ?process.code_signature.subject_name : ("AutoIt Consulting Ltd", "OpenJS Foundation", "Python Software Foundation") or
 56
 57  ?process.executable : (
 58    "?:\\Users\\Public\\*.exe", "?:\\ProgramData\\*.exe", "?:\\Users\\*\\Downloads\\*.exe",
 59    "\\Device\\HarddiskVolume*\\Users\\Public\\*.exe", "\\Device\\HarddiskVolume*\\ProgramData\\*.exe", "\\Device\\HarddiskVolume*\\Users\\*\\Downloads\\*.exe"
 60  )
 61 ) and
 62 dns.question.name :
 63         (
 64          "ip-api.com",
 65          "checkip.dyndns.org",
 66          "api.ipify.org",
 67          "api.ipify.com",
 68          "whatismyip.akamai.com",
 69          "bot.whatismyipaddress.com",
 70          "ifcfg.me",
 71          "ident.me",
 72          "ipof.in",
 73          "ip.tyk.nu",
 74          "icanhazip.com",
 75          "curlmyip.com",
 76          "wgetip.com",
 77          "eth0.me",
 78          "ipecho.net",
 79          "ip.appspot.com",
 80          "api.myip.com",
 81          "geoiptool.com",
 82          "api.2ip.ua",
 83          "api.ip.sb",
 84          "ipinfo.io",
 85          "checkip.amazonaws.com",
 86          "wtfismyip.com",
 87          "iplogger.*",
 88          "freegeoip.net",
 89          "freegeoip.app",
 90          "geoplugin.net",
 91          "myip.dnsomatic.com",
 92          "www.geoplugin.net",
 93          "api64.ipify.org",
 94          "ip4.seeip.org",
 95          "*.geojs.io",
 96          "*portmap.io",
 97          "api.db-ip.com",
 98          "geolocation-db.com",
 99          "httpbin.org",
100          "myip.opendns.com"
101         ) and
102not (
103  process.executable : (
104    "?:\\ProgramData\\Microsoft\\Windows Defender\\platform\\*\\*.exe",
105    "\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\platform\\*\\*.exe"
106  ) and user.id == "S-1-5-18"
107)
108'''
109
110note = """## Triage and analysis
111
112### Investigating System Public IP Discovery via DNS Query
113
114#### Possible investigation steps
115
116- Does the alert-local DNS event show request-only, successful resolution, or lookup failure for a public-IP service?
117  - Why: request events show intent to resolve the service; result events plus `dns.resolved_ip` show resolver response, not a connection.
118  - Focus: `dns.question.name`, `event.action`, `dns.resolved_ip`, `dns.Ext.status`, and `@timestamp`.
119  - Implication: escalate faster when a suspicious process resolves a service that reports public egress IP; lower concern only when the lookup failed or stayed request-only and identity, lineage, and network checks all fit the same recognized connectivity test.
120
121- Is the alerting binary a recognized tool or a suspicious LOLBin/script host in this context?
122  - Focus: alert or recovered process identity: `process.name`, `process.executable`, `process.hash.sha256`, `process.code_signature.subject_name`, and `process.code_signature.trusted`.
123  - Implication: escalate when the lookup comes from a LOLBin, scripting runtime, unsigned binary, user-writable path, or signer mismatch; lower concern when a stable signed updater, endpoint-management, or managed connectivity-check component owns the exact binary. Identity alone does not close the alert.
124
125- Does the launch chain explain why this process needed external-IP discovery?
126  - Focus: recovered process start and parent context on `host.id` and `process.entity_id`: `process.command_line`, `process.parent.executable`, `process.parent.command_line`, `user.id`, and `process.Ext.session_info.logon_type`. $investigate_2
127  - Implication: escalate when Office, a browser child, a script host, a service session, or an unexpected remote session launched the lookup; lower concern when parent, command line, user, and session all match one recognized troubleshooting, updater, endpoint-management, or managed connectivity-check workflow.
128
129- Did the process connect to the resolved public-IP service or pivot to other external infrastructure?
130  - Focus: same-process network events on `host.id` and `process.entity_id`, separating DNS results from connections and correlating `dns.resolved_ip` to `destination.ip`, `destination.port`, and `destination.as.organization.name`. $investigate_3
131  - Hint: Missing network telemetry is unresolved, not benign. When present, treat `dns.question.name` as DNS evidence and `destination.ip` as connection evidence, including direct public-IP connections that bypass DNS.
132  - Implication: escalate when the process reaches the resolved service, contacts unrelated public infrastructure, or later connects directly to public IPs without DNS; lower concern only when connection telemetry shows no related external connection or an environment-confirmed proxy path aligned with the same workflow.
133
134- Did the same process launch follow-on commands that turn the lookup into staging, discovery, or C2 preparation?
135  - Focus: child process starts where `process.parent.entity_id` matches `process.entity_id`: `process.name`, `process.command_line`, `process.executable`, and `process.code_signature.subject_name`. $investigate_4
136  - Implication: escalate when shells, downloaders, installers, reconnaissance commands, or persistence tooling follow the lookup; lower concern when no child activity appears and earlier identity and lineage support one recognized connectivity check.
137
138- If local evidence stays suspicious or unresolved, do related alerts show the same binary-and-domain tuple around this user or host?
139  - Focus: related alert history for `user.id` and `host.id`: `dns.question.name`, `process.hash.sha256`, `process.code_signature.subject_name`, and recovered `process.parent.executable`. Review user and host alerts only after local DNS result, lineage, and follow-on network checks stay suspicious or unresolved.
140    - $investigate_0
141    - $investigate_1
142  - Implication: broaden the case when the same hash, signer, parent, and public-IP service recur across other hosts for the same user or other users on the same host; keep response local when related alerts remain limited to one confirmed maintenance cohort.
143
144- Based on DNS outcome, binary identity, launch chain, same-process network behavior, child processes, and scope, what disposition is supported?
145  - Implication: escalate on unauthorized public-IP discovery plus suspicious lineage, external egress, child commands, or spread; close only when DNS outcome, binary identity, parent chain, user/session context, connection behavior, child activity, and scope bind one recognized workflow with no contradictions; preserve mixed or incomplete cases and escalate.
146
147### False positive analysis
148
149- Administrative troubleshooting, software updater, endpoint-management, and managed connectivity-check workflows may query public-IP services to confirm egress or NAT behavior. Confirm that identity (`process.executable`, `process.hash.sha256`, `process.code_signature.subject_name`), lineage (`process.parent.executable`, `process.parent.command_line`), user/session context, DNS evidence (`dns.question.name`, `dns.resolved_ip`), and any connection evidence converge on the same exact workflow. Without organizational confirmation, close only when telemetry proves the exact component and workflow; otherwise treat the pattern as candidate exception evidence.
150- Before creating an exception, require a stable `process.hash.sha256` or `process.code_signature.subject_name`, `process.parent.executable`, the specific `dns.question.name`, and scope anchor (`host.id`, `host.name`, or `user.id`). Avoid exceptions on `dns.question.name` alone, `process.name` alone, or the full public-IP service list because benign tooling and malware use the same services.
151
152### Response and remediation
153
154- If confirmed benign, document the exact evidence that proved the workflow: binary identity, parent chain, user/session context, DNS result, connection behavior, and recurrence scope. Then reverse any temporary containment and build a narrow exception only for that confirmed workflow.
155- If suspicious but unconfirmed, preserve the alert, process start, DNS result, same-process connection events, child process starts, and related alert history before containment. Apply reversible containment such as temporary domain or DNS blocking, outbound restrictions for the affected process or host, or heightened monitoring on the affected `host.id` or `user.id`; escalate to host isolation only if follow-on child processes, suspicious external egress, or broader spread appears and host criticality allows it.
156- If confirmed malicious, isolate the host or restrict egress when binary identity, lineage, DNS, connection, or child-process evidence shows unauthorized internet discovery or pre-C2 activity. Block confirmed malicious `dns.question.name`, `dns.resolved_ip`, `destination.ip`, `process.hash.sha256`, and related domains, then scope other hosts and users for the same indicators before terminating processes or deleting artifacts.
157- Eradicate only the scripts, binaries, scheduled tasks, run keys, or configuration changes identified during the investigation after scoping related hosts and users. Remediate the launcher, user context, or deployment path that introduced the public-IP lookup.
158- Post-incident hardening: restrict unsigned or user-writable scripting and LOLBin execution where feasible, keep endpoint DNS and network telemetry enabled, and document any connectivity-check pattern or visibility gap for future triage.
159"""
160
161setup = """## Setup
162
163This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
164
165Setup instructions: https://ela.st/install-elastic-defend
166
167### Additional data sources
168
169This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
170
171- [CrowdStrike](https://ela.st/crowdstrike-integration)
172- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
173- [Sysmon Event ID 22 - DNS Query](https://ela.st/sysmon-event-22-setup)
174"""
175
176[rule.investigation_fields]
177field_names = [
178    "@timestamp",
179    "host.id",
180    "user.id",
181    "process.entity_id",
182    "process.executable",
183    "process.command_line",
184    "process.parent.executable",
185    "process.parent.command_line",
186    "process.code_signature.trusted",
187    "process.code_signature.subject_name",
188    "dns.question.name",
189    "dns.Ext.status",
190    "dns.resolved_ip",
191    "destination.ip",
192    "event.action",
193]
194
195[transform]
196
197[[transform.investigate]]
198label = "Alerts associated with the user"
199description = ""
200providers = [
201  [
202    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
203    { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
204  ]
205]
206relativeFrom = "now-48h/h"
207relativeTo = "now"
208
209[[transform.investigate]]
210label = "Alerts associated with the host"
211description = ""
212providers = [
213  [
214    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
215    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
216  ]
217]
218relativeFrom = "now-48h/h"
219relativeTo = "now"
220
221[[transform.investigate]]
222label = "Process events for the DNS-querying process"
223description = ""
224providers = [
225  [
226    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
227    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
228    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
229  ]
230]
231relativeFrom = "now-1h"
232relativeTo = "now"
233
234[[transform.investigate]]
235label = "Network events for the DNS-querying process"
236description = ""
237providers = [
238  [
239    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
240    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
241    { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" }
242  ]
243]
244relativeFrom = "now-1h"
245relativeTo = "now"
246
247[[transform.investigate]]
248label = "Child processes spawned by the DNS-querying process"
249description = ""
250providers = [
251  [
252    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
253    { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
254    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
255  ]
256]
257relativeFrom = "now-1h"
258relativeTo = "now"
259
260[[rule.threat]]
261framework = "MITRE ATT&CK"
262
263[[rule.threat.technique]]
264id = "T1016"
265name = "System Network Configuration Discovery"
266reference = "https://attack.mitre.org/techniques/T1016/"
267
268[[rule.threat.technique.subtechnique]]
269id = "T1016.001"
270name = "Internet Connection Discovery"
271reference = "https://attack.mitre.org/techniques/T1016/001/"
272
273[rule.threat.tactic]
274id = "TA0007"
275name = "Discovery"
276reference = "https://attack.mitre.org/tactics/TA0007/"
277
278[[rule.threat]]
279framework = "MITRE ATT&CK"
280
281[[rule.threat.technique]]
282id = "T1071"
283name = "Application Layer Protocol"
284reference = "https://attack.mitre.org/techniques/T1071/"
285
286[[rule.threat.technique.subtechnique]]
287id = "T1071.004"
288name = "DNS"
289reference = "https://attack.mitre.org/techniques/T1071/004/"
290
291[rule.threat.tactic]
292id = "TA0011"
293name = "Command and Control"
294reference = "https://attack.mitre.org/tactics/TA0011/"

Triage and analysis

Investigating System Public IP Discovery via DNS Query

Possible investigation steps

  • Does the alert-local DNS event show request-only, successful resolution, or lookup failure for a public-IP service?

    • Why: request events show intent to resolve the service; result events plus dns.resolved_ip show resolver response, not a connection.
    • Focus: dns.question.name, event.action, dns.resolved_ip, dns.Ext.status, and @timestamp.
    • Implication: escalate faster when a suspicious process resolves a service that reports public egress IP; lower concern only when the lookup failed or stayed request-only and identity, lineage, and network checks all fit the same recognized connectivity test.
  • Is the alerting binary a recognized tool or a suspicious LOLBin/script host in this context?

    • Focus: alert or recovered process identity: process.name, process.executable, process.hash.sha256, process.code_signature.subject_name, and process.code_signature.trusted.
    • Implication: escalate when the lookup comes from a LOLBin, scripting runtime, unsigned binary, user-writable path, or signer mismatch; lower concern when a stable signed updater, endpoint-management, or managed connectivity-check component owns the exact binary. Identity alone does not close the alert.
  • Does the launch chain explain why this process needed external-IP discovery?

    • Focus: recovered process start and parent context on host.id and process.entity_id: process.command_line, process.parent.executable, process.parent.command_line, user.id, and process.Ext.session_info.logon_type. $investigate_2
    • Implication: escalate when Office, a browser child, a script host, a service session, or an unexpected remote session launched the lookup; lower concern when parent, command line, user, and session all match one recognized troubleshooting, updater, endpoint-management, or managed connectivity-check workflow.
  • Did the process connect to the resolved public-IP service or pivot to other external infrastructure?

    • Focus: same-process network events on host.id and process.entity_id, separating DNS results from connections and correlating dns.resolved_ip to destination.ip, destination.port, and destination.as.organization.name. $investigate_3
    • Hint: Missing network telemetry is unresolved, not benign. When present, treat dns.question.name as DNS evidence and destination.ip as connection evidence, including direct public-IP connections that bypass DNS.
    • Implication: escalate when the process reaches the resolved service, contacts unrelated public infrastructure, or later connects directly to public IPs without DNS; lower concern only when connection telemetry shows no related external connection or an environment-confirmed proxy path aligned with the same workflow.
  • Did the same process launch follow-on commands that turn the lookup into staging, discovery, or C2 preparation?

    • Focus: child process starts where process.parent.entity_id matches process.entity_id: process.name, process.command_line, process.executable, and process.code_signature.subject_name. $investigate_4
    • Implication: escalate when shells, downloaders, installers, reconnaissance commands, or persistence tooling follow the lookup; lower concern when no child activity appears and earlier identity and lineage support one recognized connectivity check.
  • If local evidence stays suspicious or unresolved, do related alerts show the same binary-and-domain tuple around this user or host?

    • Focus: related alert history for user.id and host.id: dns.question.name, process.hash.sha256, process.code_signature.subject_name, and recovered process.parent.executable. Review user and host alerts only after local DNS result, lineage, and follow-on network checks stay suspicious or unresolved.
      • $investigate_0
      • $investigate_1
    • Implication: broaden the case when the same hash, signer, parent, and public-IP service recur across other hosts for the same user or other users on the same host; keep response local when related alerts remain limited to one confirmed maintenance cohort.
  • Based on DNS outcome, binary identity, launch chain, same-process network behavior, child processes, and scope, what disposition is supported?

    • Implication: escalate on unauthorized public-IP discovery plus suspicious lineage, external egress, child commands, or spread; close only when DNS outcome, binary identity, parent chain, user/session context, connection behavior, child activity, and scope bind one recognized workflow with no contradictions; preserve mixed or incomplete cases and escalate.

False positive analysis

  • Administrative troubleshooting, software updater, endpoint-management, and managed connectivity-check workflows may query public-IP services to confirm egress or NAT behavior. Confirm that identity (process.executable, process.hash.sha256, process.code_signature.subject_name), lineage (process.parent.executable, process.parent.command_line), user/session context, DNS evidence (dns.question.name, dns.resolved_ip), and any connection evidence converge on the same exact workflow. Without organizational confirmation, close only when telemetry proves the exact component and workflow; otherwise treat the pattern as candidate exception evidence.
  • Before creating an exception, require a stable process.hash.sha256 or process.code_signature.subject_name, process.parent.executable, the specific dns.question.name, and scope anchor (host.id, host.name, or user.id). Avoid exceptions on dns.question.name alone, process.name alone, or the full public-IP service list because benign tooling and malware use the same services.

Response and remediation

  • If confirmed benign, document the exact evidence that proved the workflow: binary identity, parent chain, user/session context, DNS result, connection behavior, and recurrence scope. Then reverse any temporary containment and build a narrow exception only for that confirmed workflow.
  • If suspicious but unconfirmed, preserve the alert, process start, DNS result, same-process connection events, child process starts, and related alert history before containment. Apply reversible containment such as temporary domain or DNS blocking, outbound restrictions for the affected process or host, or heightened monitoring on the affected host.id or user.id; escalate to host isolation only if follow-on child processes, suspicious external egress, or broader spread appears and host criticality allows it.
  • If confirmed malicious, isolate the host or restrict egress when binary identity, lineage, DNS, connection, or child-process evidence shows unauthorized internet discovery or pre-C2 activity. Block confirmed malicious dns.question.name, dns.resolved_ip, destination.ip, process.hash.sha256, and related domains, then scope other hosts and users for the same indicators before terminating processes or deleting artifacts.
  • Eradicate only the scripts, binaries, scheduled tasks, run keys, or configuration changes identified during the investigation after scoping related hosts and users. Remediate the launcher, user context, or deployment path that introduced the public-IP lookup.
  • Post-incident hardening: restrict unsigned or user-writable scripting and LOLBin execution where feasible, keep endpoint DNS and network telemetry enabled, and document any connectivity-check pattern or visibility gap for future triage.

References

Related rules

to-top