IMPORTANT: This documentation is no longer updated. Refer to Elastic's version policy and the latest documentation.

Unusual Child Processes of RunDLL32

edit

Identifies a no-argument or malformed Rundll32 launch followed by child process execution. This unusual sequence can indicate Rundll32 abuse for proxy execution or payload handoff.

Rule type: eql

Rule indices:

  • logs-endpoint.events.process-*
  • winlogbeat-*
  • logs-windows.sysmon_operational-*
  • logs-crowdstrike.fdr*

Severity: high

Risk score: 73

Runs every: 30m

Searches indices from: now-60m (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References: None

Tags:

  • Domain: Endpoint
  • OS: Windows
  • Use Case: Threat Detection
  • Tactic: Defense Evasion
  • Data Source: Elastic Defend
  • Data Source: Sysmon
  • Data Source: Crowdstrike
  • Resources: Investigation Guide

Version: 214

Rule authors:

  • Elastic

Rule license: Elastic License v2

Investigation guide

edit

Triage and analysis

Investigating Unusual Child Processes of RunDLL32

Possible investigation steps

  • Which source events define the no-argument "rundll32.exe" parent and the spawned child?
  • Why: this asymmetric sequence has no single safe process identity; recover source events before interpreting grouped meaning or pivoting.
  • Focus: Timeline source events for the sequence, recording parent and child process.entity_id, child process.parent.entity_id, host.id, and user.id.
  • Implication: escalate when recovered events show one no-argument "rundll32.exe" handing off to an unexpected child; lower suspicion only when recovery shows a parser/quoting artifact and the child is signed, stable, and path-consistent for the same user and host.
  • Does the recovered "rundll32.exe" event truly lack a DLL, export, or Control_RunDLL-style target?
  • Why: normal Rundll32 proxy execution names a DLL/export, ordinal, script target, or Control Panel handler; this rule covers empty or malformed invocation that still spawns a child.
  • Focus: parent process.command_line, process.args_count, process.executable, and process.pe.original_file_name.
  • Implication: escalate when process.args_count and process.command_line confirm only the image path or a malformed target; lower suspicion only when source recovery proves a quoting/parser artifact and the exact parent-child command pattern is stable.
  • What did the recovered child process do, and does its identity fit that parent chain?
  • Focus: child process.executable, process.command_line, process.pe.original_file_name, code signature, and descendant process starts.
  • Hint: after recovering the child process.entity_id from source events, pivot manually on that ID for descendants; the final sequence alert may not preserve a child-specific entity ID.
  • Implication: escalate when the child is a shell, script host, network utility, unsigned payload, user-writable binary, or mismatched original file name; lower suspicion when the child is signed, path-consistent, and matches the exact recovered wrapper pattern. Identity alone does not clear the behavior.
  • What launched "rundll32.exe", and does the user-host context explain the handoff?
  • Focus: parent process.parent.executable, process.parent.command_line, process.Ext.ancestry, user.name, and user.domain.
  • Implication: escalate when the launcher is Office, a browser, archive utility, script host, temp-path executable, or a lineage unusual for that user.id and host.id; lower suspicion only when the same parent executable, command line, child path, signer, and host/user scope recur without artifact or network contradictions.
  • If library telemetry is available after source-event recovery, did the recovered process load a hidden or recently staged DLL?
  • Focus: library events for recovered host.id and each process.entity_id, checking dll.path, dll.hash.sha256, signer, trust, and dll.Ext.relative_file_creation_time.
  • Hint: query library events separately for the recovered parent and child IDs; missing library telemetry limits DLL corroboration but does not clear the process evidence.
  • Implication: escalate when a DLL loads from a user-writable, unrelated, unsigned, or recently created path; lower suspicion when library identity, signer, and path relationship fit the recovered parent-child workflow.
  • If file or network telemetry is available after source-event recovery, did the chain stage payloads or reach suspicious infrastructure?
  • Focus: file and network events for recovered host.id and each process.entity_id, checking file.path, file.Ext.windows.zone_identifier, DNS dns.question.name, connection destination.ip, and destination.port.
  • Hint: separate DNS lookup events from connection events before interpreting them. Missing network telemetry is unresolved, not benign.
  • Implication: escalate when the chain writes executable or scriptable artifacts, carries internet provenance, or connects to rare external infrastructure; lower suspicion when optional activity stays inside the recovered parent-child workflow.
  • If local evidence remains suspicious or unresolved, do related alerts show the same user, host, or child-process pattern?
  • Focus: recent alerts for user.id, host.id, child process.executable, child process.hash.sha256, or a distinctive process.command_line fragment.
  • Hint: use only after source recovery keeps the case suspicious or unresolved.
  • !{investigate{"description":"","label":"Alerts associated with the user","providers":[[{"excluded":false,"field":"event.kind","queryType":"phrase","value":"signal","valueType":"string"},{"excluded":false,"field":"user.id","queryType":"phrase","value":"{{user.id}}","valueType":"string"}]],"relativeFrom":"now-48h/h","relativeTo":"now"}}
  • !{investigate{"description":"","label":"Alerts associated with the host","providers":[[{"excluded":false,"field":"event.kind","queryType":"phrase","value":"signal","valueType":"string"},{"excluded":false,"field":"host.id","queryType":"phrase","value":"{{host.id}}","valueType":"string"}]],"relativeFrom":"now-48h/h","relativeTo":"now"}}
  • Implication: broaden response when the same user or host repeats Rundll32 proxy-execution, child payload, or related defense-evasion alerts; keep scope local when the suspicious pattern remains isolated and the recovered workflow is tightly explained.
  • Escalate when source recovery, invocation shape, child identity, launcher lineage, DLL/file/network evidence, or recurrence shows "rundll32.exe" proxying unauthorized child execution or payload delivery; close only when recovered process evidence and corroborators tightly bind one exact signed workflow on this host; if evidence is mixed or incomplete, preserve artifacts and escalate.

False positive analysis

  • No-argument "rundll32.exe" spawning a child is an operational anti-pattern. Close as benign only when source recovery proves a parser/quoting artifact or authorized reproduction, the child is signed and path-consistent, and no DLL, file, or network evidence contradicts that workflow. Align available inventory, vendor, or test records; otherwise treat prior recurrence for the same host.id and stable parent-child anchors as supporting evidence only.
  • Build exceptions from the minimum confirmed workflow: parent process.parent.executable, child process.executable, stable process.code_signature.subject_name, command-line shape, host/user scope, and recovered artifact anchors when present. Do not except a first occurrence, unresolved source recovery, missing contradictory-telemetry checks, or "rundll32.exe" alone.

Response and remediation

  • If confirmed benign:
  • Reverse temporary containment and document the recovered parent-child workflow, source-event IDs, signer, command-line pattern, and corroborating inventory, vendor record, or recurrence that established it.
  • If suspicious but unconfirmed:
  • Preserve a case export of Timeline source events, recovered process identifiers and command lines, child binary hash, and any recovered DLL, file, or network artifacts before cleanup.
  • Apply reversible containment such as temporary network restrictions or heightened monitoring on the affected host.id and user.id; use host isolation only when child-process or artifact evidence indicates active payload execution and the host role can tolerate isolation.
  • If confirmed malicious:
  • Preserve the recovered source events, process IDs, command lines, child hashes, DLL or file artifacts, and network indicators, then isolate the host or restrict the account based on the child execution, launcher lineage, artifact, or network evidence.
  • Block confirmed malicious child hashes, DLL hashes, staged payload paths, domains, and destination IPs, then review other hosts and users for the same parent-child or artifact pattern before eradication.
  • Remove only the malicious DLLs, scripts, or child payloads identified during investigation, remediate the parent launcher or delivery path that invoked "rundll32.exe", and investigate credential exposure if follow-on behavior suggests collection or lateral movement.
  • Post-incident hardening:
  • Keep process telemetry for "rundll32.exe" and child processes enabled, and enable file, network, or library telemetry where missing evidence limited the case.
  • Restrict unusual "rundll32.exe" child-process patterns where the business does not require them, and record any adjacent DLL/export, ordinal, Control Panel, or script-target variants observed in the case.

Setup

edit

Setup

This rule is designed for data generated by Elastic Defend, which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.

Setup instructions: https://ela.st/install-elastic-defend

Additional data sources

This rule also supports the following third-party data sources. For setup instructions, refer to the links below:

Rule query

edit
sequence with maxspan=1h
  [process where host.os.type == "windows" and event.type == "start" and
     (process.name : "rundll32.exe" or process.pe.original_file_name == "RUNDLL32.EXE") and
      (process.args_count == 1 and
        /* Excludes bug where a missing closing quote sets args_count to 1 despite extra args */
        not process.command_line regex~ """\".*\.exe[^\"].*""")
  ] by process.entity_id
  [process where host.os.type == "windows" and event.type == "start" and process.parent.name : "rundll32.exe"
  ] by process.parent.entity_id

Framework: MITRE ATT&CKTM