---
analysis: A simple rule for Dubbo exploitation or rootkit loading would generate excessive
  noise in large Linux environments. This hunt uses a gated logic to only perform
  forensic analysis on hosts with the target software, applies prevalence baseline
  counting to filter common maintenance scripts, and uses an agent to weigh multiple
  independent indicators before recommending isolation.
blind_spots:
- id: no-inventory-telemetry
  question: whether Apache Dubbo is present on servers that do not report inventory
  requires: hb_software_inventory for all Linux servers
  risk: A host without inventory reporting might be a target but will cause the lead
    query to return silence, skipping forensic analysis.
  stage: initial-access-dubbo-exploit
- id: ebpf-rootkit-stealth
  question: whether an eBPF rootkit is active without a traditional LKM load
  requires: eBPF probe registration telemetry
  risk: VoidLink supports eBPF rootkits which may not appear as a module file on disk
    or a traditional .ko load event in hb_module_activity.
  stage: rootkit-and-privilege-escalation
- id: no-agent-coverage
  question: whether VoidLink activity occurs on unmanaged or shadow IT systems
  requires: Endpoint agent on high-value servers
  risk: The behavioural queries only cover systems where telemetry is collected; unmanaged
    servers exploited via Dubbo remain invisible.
coverage:
- stage: initial-access-dubbo-exploit
  status: covered
  steps:
  - lead-dubbo-inventory
  - suspicious-java-children
- stage: implant-execution-and-sideloading
  status: covered
  steps:
  - suspicious-java-children
- stage: rootkit-and-privilege-escalation
  status: covered
  steps:
  - unsigned-kernel-modules
- reason: Belongs to another part of the 'VoidLink' series.
  stage: internal-scanning-recon
  status: out_of_scope
- reason: Belongs to another part of the 'VoidLink' series.
  stage: cloud-api-discovery
  status: out_of_scope
- reason: Belongs to another part of the 'VoidLink' series.
  stage: mesh-c2-communications
  status: out_of_scope
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: promote-to-detection
  justification: VoidLink is a sophisticated, defense-contractor grade framework targeting
    Linux environments. Identifying its deployment through initial exploit patterns
    and kernel persistence is essential for protecting server infrastructure from
    persistent compromise.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An adversary has exploited a Java-based Apache Dubbo service to deploy
  a ZigLang-based VoidLink implant and maintained stealth using an unsigned kernel-level
  rootkit.
labels:
- hunt
- attack.t1190
- attack.t1204.002
- attack.t1574.002
name: 'VoidLink: Exploitation and Kernel-Level Implant Deployment'
parameters:
  lookback_days:
    default: '14'
    description: Days of history to examine for process and module activity.
    from:
      kind: manual
      observed: '2024-01-01'
      ref: VoidLink analysis lookback
    type: number
  rare_threshold:
    default: '5'
    description: The maximum number of hosts a process path can appear on to be considered
      rare.
    type: number
  scope_hosts:
    default: []
    description: List of hostnames from the software inventory lead to focus behavioral
      queries.
    type: list[host]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://blog.talosintelligence.com/voidlink/
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Focus on Linux servers running Java middleware, particularly those with
  internet exposure. The hunt starts with a wide software scan and then uses specific
  behavioural triggers to narrow the volume.
references:
- name: "Cisco Talos \u2014 VoidLink"
  url: https://blog.talosintelligence.com/voidlink/
related:
- hunt: voidlink-internal-recon-and-lateral-movement
  reason: This hunt focuses on initial deployment; a follow-on hunt is needed for
    internal scanning using FSCAN and mesh-C2 traffic.
  relation: follows
scenario:
  stages:
  - name: Apache Dubbo Java Serialization Exploitation
    observables:
    - Apache Dubbo project
    - Java serialization vulnerabilities
    - Pre-obtained credentials
    slug: initial-access-dubbo-exploit
    tactic: initial-access
    techniques:
    - T1190
  - name: VoidLink Implant Execution
    observables:
    - ZigLang-based implant binary
    - DLL sideloading on Windows
    - C-based plugins loaded via ELF linker
    - VoidLink compile-on-demand framework
    slug: implant-execution-and-sideloading
    tactic: execution
    techniques:
    - T1204.002
    - T1574.002
  - name: Persistence and Privilege Escalation
    observables:
    - eBPF rootkit
    - Loadable Kernel Module (LKM) rootkit
    - Container privilege escalation
    - Docker/Kubernetes sandbox escape
    slug: rootkit-and-privilege-escalation
    tactic: persistence
    techniques:
    - T1574.002
  - name: Internal Network Reconnaissance
    observables:
    - FSCAN
    - SOCKS server on compromised hosts
    - Scanning of entire Class C networks
    - Internal and external network scanning
    slug: internal-scanning-recon
    tactic: discovery
    techniques:
    - T1090.003
  - name: Cloud and Container Asset Discovery
    observables:
    - Kubernetes API interactions
    - Docker API interactions
    - Cloud-aware gathering of environment info
    slug: cloud-api-discovery
    tactic: discovery
  - name: Peer-to-Peer Mesh C2
    observables:
    - GoLang backend
    - Mesh Peer-to-Peer (P2P) routing
    - Dead-letter queue routing
    - Encrypted/obfuscated exfiltration traffic
    slug: mesh-c2-communications
    tactic: command-and-control
    techniques:
    - T1071
    - T1090.003
    - T1041
  summary: UAT-9921 utilizes the VoidLink modular framework, targeting Linux and Windows
    systems by exploiting Java serialization vulnerabilities in Apache Dubbo or using
    stolen credentials. The ZigLang-based implant deploys plugins for eBPF-based rootkits
    and container escapes, while conducting internal reconnaissance with FSCAN and
    establishing a peer-to-peer mesh command-and-control network.
series:
  index: 1
  slug: voidlink
  title: VoidLink
  total: 2
severity: high
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
tlp: clear
type: investigation
---


# VoidLink: Exploitation and Kernel-Level Implant Deployment

This hunt targets the initial stages of a VoidLink intrusion. It identifies servers running Apache Dubbo, which is a reported entry point for UAT-9921. If the software is present, the hunt triggers a gated forensic fan-out to find suspicious child processes spawning from Java and unsigned kernel modules that indicate rootkit activity. An agent then synthesizes the inventory context with the behavioural findings to identify compromised hosts.

## lead-dubbo-inventory
<!-- Lead: Identify Apache Dubbo software -->
Identify the subset of the fleet running Apache Dubbo, which UAT-9921 targets for remote code execution.

```sqlite target=endpoint role=scoping
~~~yaml
expected: Hosts running Dubbo. If none are found, the likelihood of this specific
  exploit chain is low, though manual deployments may still exist.
reads:
- device_hostname
- package_name
- package_version
- vendor_name
silence: not_evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, package_name, package_version, vendor_name FROM hb_software_inventory WHERE LOWER(package_name) LIKE '%dubbo%'
```

## evaluate-scoping
<!-- Evaluate software lead -->
```agent target=hunter
cite: required
context:
- lead-dubbo-inventory
max_iterations: 3
objective: Confirm the presence of Apache Dubbo and identify target servers for forensic
  analysis.
success_criteria: A list of hostnames to populate the scope_hosts parameter.
tools:
- endpoint
```

## gate-to-forensics
<!-- Gate: Proceed on software match -->
if: `evaluate-scoping.rows > 0`
then: → forensic-fan-out
else: → close-out

## forensic-fan-out
<!-- Forensic Fan-Out -->
parallel:
- → suspicious-java-children
- → unsigned-kernel-modules
join: → triage-synthesis

## suspicious-java-children
<!-- Rare child processes spawned by Java -->
Detect the transition from Java serialization exploitation to execution of an implant, focusing on rare binaries in temporary directories.

```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, scope_hosts=scope_hosts, rare_threshold=rare_threshold)
~~~yaml
baseline:
  compare: new_this_window
  window: '{{lookback_days}}d'
expected: Rare binaries spawned by Java in world-writable paths. A small host count
  indicates a targeted deployment rather than legitimate maintenance.
prevalence:
  by: device_hostname
  key:
  - process_path
  rare_below: 5
reads:
- device_hostname
- process_path
- parent_process_name
- time
silence: evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT LOWER(process_path) AS binary_path, parent_process_name, COUNT(DISTINCT device_hostname) AS host_count FROM hb_process_activity WHERE LOWER(parent_process_name) LIKE '%java%' AND (LOWER(process_path) LIKE '%/tmp/%' OR LOWER(process_path) LIKE '%/dev/shm/%' OR LOWER(process_path) LIKE '%/var/tmp/%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2 HAVING host_count <= {{rare_threshold}}
```

## unsigned-kernel-modules
<!-- Unsigned kernel modules in suspicious paths -->
Identify potential LKM rootkits deployed by VoidLink to hide its presence and the C2 server.

```sqlite target=endpoint role=baseline params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: Unsigned modules loaded from temporary or hidden paths. Legitimate kernel
  modules are typically signed and live in /lib/modules/.
prevalence:
  by: device_hostname
  key:
  - module_name
  rare_below: 3
reads:
- device_hostname
- module_path
- module_name
- module_signed
- time
silence: not_evidence_of_absence
source: hb_module_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, module_path, module_name, module_signed, time FROM hb_module_activity WHERE module_signed = 0 AND (LOWER(module_path) LIKE '%/tmp/%' OR LOWER(module_path) LIKE '%/.%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## triage-synthesis
<!-- Synthesize VoidLink evidence -->
```agent target=hunter
cite: required
context:
- evaluate-scoping
- suspicious-java-children
- unsigned-kernel-modules
max_iterations: 6
objective: Determine if any host showing Dubbo software also exhibits rare Java child
  processes or suspicious kernel modules.
success_criteria: A per-host verdict of malicious | suspicious | benign, citing specific
  binary paths and module names.
tools:
- endpoint
```

## route-on-verdict
<!-- Route on verdict -->
if~: "the triage verdict is malicious for at least one host running Dubbo" (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: no-agent-coverage)
else: → close-out

## isolate-host
<!-- Isolate host -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host immediately. Preserve any artifacts in temporary directories and perform a memory dump to capture the rootkit state.
```
→ analyst-review

## analyst-review
<!-- Analyst review -->
```manual target=analyst
Review the cited child processes and unsigned modules. Confirm if the rare binaries use ZigLang or C as reported. Investigate the command line of the Java parent to identify the serialization exploit attempt.
```
→ end

## close-out
<!-- Close out -->
```manual target=analyst
Record the hosts scanned and the absence of matching behaviour. If many false positives occurred from legitimate Java child processes, update the rare_threshold or add exclusions for known maintenance scripts.
```
→ end
