Security Incident Report: XMRig Cryptominer

Rooting out a kernel-level crypto-miner dropper on my Proxmox VE host

Posted by XiaoKang00010 on August 29, 2026

Security Incident Report: XMRig Cryptominer

A persistent Monero miner that kept coming back — even after deleting its files, killing its process, and changing the root password. The culprit turned out to be a malicious kernel module.

1. Executive Summary

On 2026-08-29 I detected and fully eradicated a persistent XMRig cryptocurrency miner from my Proxmox VE 8 host (kernel 7.0.14-8-pve). The infection was more sophisticated than a typical miner: it used an unsigned, out-of-tree kernel module (nf_conntrack_kernel) as a self-healing re-dropper that re-created the miner binary and relaunched it from kernel space every ~18 minutes — surviving process kills, file deletion, password rotation, and every userspace-level cleanup.

Root cause was a WAN-exposed Proxmox management interface (pveproxy, port 8006) combined with a weak root password, which granted the attacker full root access.

Every component of the infection was mapped and removed. This report documents the technical details, indicators of compromise (IOCs), and the remediation steps taken.

2. Incident Timeline

Time (CST) Event
~Aug 20 Initial compromise; attacker stages payloads under /var/tmp/xmrig/
~Aug 22 Attacker adds a (malformed) persistence entry to root’s crontab
Aug 29 ~18:11 Host reboots; miner reappears shortly after (~18:36), proving boot-time persistence
Aug 29 ~19:14 Miner killed, binaries deleted, LD_PRELOAD injection stripped
Aug 29 ~19:18 Miner respawns — first clue that a re-dropper was active
Aug 29 ~19:24 Root password rotated
Aug 29 ~19:36 Miner respawns again — confirming the re-dropper is on-box, not the attacker reconnecting
Aug 29 ~19:49 Malicious kernel module nf_conntrack_kernel identified, unloaded, and removed; cleanup verified

3. Root Cause

The host’s Proxmox web management interface (pveproxy, port 8006) was exposed to the WAN, and the root account used a weak password. The attacker obtained root credentials, then gained a root shell via the Proxmox root@pam authentication path.

This single point of failure let the attacker install a kernel-level rootkit — which is why the infection proved so resilient to conventional cleanup.

4. Infection Chain

4.1 Payloads

The attack dropped four distinct components:

Component Path Details
Kernel-module dropper /lib/modules/7.0.14-8-pve/kernel/net/ipv4/netfilter/nf_conntrack_kernel.ko 337,792 B; unsigned (taint OE); version 0.1; no description/author; exposes params worker, delay, path
LD_PRELOAD hider /usr/local/lib/kthreadd32.so 16,536 B; MD5 a964ca6f9e18a7ec30c047ddff02b458; hooks readdir/readdir64 to hide processes named “kthreadd64”
Miner binary /sbin/kthreadd64, /usr/sbin/kthreadd64 8,297,712 B; static, stripped ELF; MD5 8f4fff0ded94f1141768220906abfbb8
Staging directory /var/tmp/xmrig/ config.json, miner.log, SHA256SUMS, xmrig (8,350,992 B, XMRig 6.26.0)

4.2 Persistence

The miner persisted through two layers:

  1. /etc/profile.d/bash_completion.sh had an injected export LD_PRELOAD="/usr/local/lib/kthreadd32.so" — loading the hider library into new shells to conceal the miner process from ps/ls.
  2. /etc/modules contained the line nf_conntrack_kernel (prefixed by a fake # AUTO GENERATED BY KERNEL SYSTEM MODULE comment). At boot, systemd-modules-load loaded the kernel module, which used call_usermodehelper() to periodically re-drop the miner binary and relaunch it.

The second layer is what made the infection self-healing: because the miner was re-created and executed from the kernel, it was invisible to process-list and file-level cleanup. It also lived in the root cgroup (0::/) with a near-empty environment — the classic signature of call_usermodehelper().

4.3 Mining Configuration

The miner connected to two pools with the command line:

/sbin/kthreadd64 --cpu-priority=5 --donate-level=0 \
  -o 89.117.109.224:143 \
  -u 4B7vsy8ccUwQufiyMN9jgoDphPUDzGUvBhE4f19U5z3WMPZqx2gjHrv2PxpuBSZRHAdD5qfEnPiApdFk4fhHZGVwU1YG1L2.worker86/[email protected] \
  --coin=monero -k

5. Indicators of Compromise (IOCs)

Files

IOC Hash / Size
nf_conntrack_kernel.ko 337,792 B, unsigned (out-of-tree)
/usr/local/lib/kthreadd32.so MD5 a964ca6f9e18a7ec30c047ddff02b458
/sbin/kthreadd64, /usr/sbin/kthreadd64 MD5 8f4fff0ded94f1141768220906abfbb8

Network & Identity

Type Value
Mining pool 89.117.109.224:143
Mining pool 107.155.109.94:443
Monero wallet 4B7vsy8ccUwQufiyMN9jgoDphPUDzGUvBhE4f19U5z3WMPZqx2gjHrv2PxpuBSZRHAdD5qfEnPiApdFk4fhHZGVwU1YG1L2
Attacker email [email protected]
Worker ID worker86

6. Remediation

The following actions fully neutralized the infection:

  1. Unloaded the kernel modulermmod nf_conntrack_kernel.
  2. Removed boot persistence — deleted the module entry from /etc/modules.
  3. Deleted the .ko file and rebuilt the module index (depmod -a).
  4. Blacklisted the module in /etc/modprobe.d/ (blacklist + install … /bin/false) so it cannot be loaded again.
  5. Killed the miner and deleted /sbin/kthreadd64 and /usr/sbin/kthreadd64.
  6. Removed the LD_PRELOAD hider (kthreadd32.so) and stripped the injection from bash_completion.sh.
  7. Removed the staging directory /var/tmp/xmrig/.
  8. Blocked the C2 IPs via a persistent systemd unit (block-mining-ips.service), using iptables on both INPUT and OUTPUT.
  9. Rotated the root password.

7. Lessons Learned & Recommendations

  1. Never expose the Proxmox management interface (port 8006) to the WAN. Access it over a VPN or SSH tunnel instead.
  2. Use strong, unique passwords — or better, key-based authentication and 2FA — for any internet-facing service.
  3. A root compromise cannot be trusted away. A kernel-level rootkit means the attacker had full control of the host; the only way to be truly certain is a clean reinstall from known-good media.
  4. Rotate all secrets that lived on the compromised host — API tokens, credentials, and keys stored on disk should all be considered exposed.
  5. Defense in depth: even a strong password is no substitute for network-layer access control.