malware · cryptomining · rootkit · linux · kernel · monero · privilege-escalation · cve-2026-31431 · container-escape
Rootpacket: A Linux Cryptojacking Toolkit That Hides in the Kernel
Kinryū Labs analysed Rootpacket, a Linux cryptojacking toolkit that ships a kernel rootkit to fake CPU and memory usage, escalates to root through CVE-2026-31431 (an AF_ALG page-cache flaw that also escapes containers to the host), masquerades as an Intel driver, and disables the same exposed services rival miners use to get in.
By Davis Zheng·
TLP:CLEAR. Cleared for public release. Captured by the Kinryū Labs honeypot sensor network. Indicators below are defanged.
Executive summary
- ~45%CPU top shows while it runs near 100%
- 3persistence mechanisms
- 7.8CVSS, CVE-2026-31431 (AF_ALG page-cache LPE)
- hostroot from an unprivileged container
Rootpacket is a multi-component cryptojacking toolkit for Linux. It bundles a kernel-level rootkit for stealth, a privilege-escalation exploit for CVE-2026-31431 in the Linux AF_ALG crypto interface, a UPX-packed XMRig 6.26.0 Monero miner renamed xrandom, and a competitor-elimination script. The code is written largely in Turkish (variable names, comments, status strings), which points to a Turkish-speaking operator.
The toolkit runs in one of two modes. In root mode it loads a loadable kernel module (LKM) rootkit disguised as intel_uncore_freq_aux, installs it through DKMS so it survives kernel upgrades, registers a systemd service, and clears the box of rivals. When it cannot get root, it falls back to a userland mode that persists through crontab and runs the miner as a daemon. The miner connects to pool.supportxmr.com:443 over stratum+ssl and mines Monero with RandomX.
The component worth dwelling on is the rootkit. While the miner pins the processor near 100 percent, the rootkit rewrites /proc/stat so that top and htop report a calm 40 to 50 percent, and it oscillates that figure using jiffies so the load looks real rather than pegged at a constant. It does the same to /proc/meminfo, and it filters directory listings to hide its own processes and files.
- The objective is cryptojacking (high confidence). The toolkit ships XMRig 6.26.0, a hardcoded Monero wallet, and a
pool.supportxmr.commining configuration, with the XMRig developer donation turned off so all proceeds go to the operator. - The privilege escalation is CVE-2026-31431 ("Copy Fail"), a deterministic page-cache write in the Linux AF_ALG
algif_aeadpath (CVSS 7.8, disclosed April 2026). Because the page cache is shared host-wide, the same write escapes a container to root the host, so an infected container is a compromised host (high confidence). - The operator is well above the typical drop-and-mine crew (high confidence). A custom LKM rootkit with ftrace hooks, DKMS persistence that auto-rebuilds for new kernels, a working CVE-2026-31431 page-cache exploit, and layered systemd/DKMS/cron persistence are a level of engineering most cryptojackers never reach.
- The operator is likely Turkish-speaking (moderate confidence). Turkish variable names, comments, and status messages such as
ROOT ele gecirildi!run through the toolkit. - Rootpacket is built to own a host exclusively and keep it. Its
killservice.shremoves rival miners and then disables the externally exposed services that cryptojackers use for initial access, including the Docker API on 2375/2376, the same vector we documented in our RedTail writeup. These crews are fighting over the same misconfigured boxes.
Toolkit architecture
Rootpacket is a modular dropper. The pieces:
setup.sh Entry point. Checks privilege level, picks a deployment mode.
getroot Privilege escalation. Exploits CVE-2026-31431 (AF_ALG) for local root.
xrandom UPX-packed XMRig 6.26.0, renamed to dodge name-based detection.
kernel/
stealth.c LKM rootkit, compiled via DKMS, disguised as an Intel driver.
install.sh DKMS persistence engine.
killservice.sh Competitor elimination and "hardening".
rootpacket.tar.gz An inner copy of the whole toolkit, packaged for redistribution.
Root mode. setup.sh runs getroot if it is not already root, copies xrandom to /opt/kernel-kd/, creates a systemd service, runs kernel/install.sh to compile and load the rootkit through DKMS, runs killservice.sh to clear the competition, and starts the miner as a persistent service.
Userland fallback. When root is out of reach, setup.sh copies xrandom to ~/.xrandom/, writes a launcher with a PID lock, installs a crontab entry that fires at reboot and every minute, and launches the miner with setsid so it survives the parent shell.
| Feature | Root mode | Userland mode |
|---|---|---|
| Miner location | /opt/kernel-kd/xrandom | ~/.xrandom/xrandom |
| Persistence | systemd (kernel-kd.service) | crontab (@reboot + */1 * * * *) |
| Rootkit | Yes (LKM via DKMS) | No |
| Competitor kill | Yes (killservice.sh) | No |
| Runs as | root (systemd) | current user (setsid daemon) |
getroot: CVE-2026-31431, root by page-cache corruption
getroot is a statically linked, unstripped ELF64 x86-64 binary built from getroot.c. It exploits CVE-2026-31431 (“Copy Fail”), a logic flaw in the Linux kernel’s AF_ALG algif_aead interface disclosed on 29 April 2026 (CVSS 7.8). The bug gives a deterministic, attacker-controlled 4-byte write into the kernel page cache, and getroot uses it to patch a SUID binary in memory and walk out as root.
| Property | Value |
|---|---|
| Type | ELF 64-bit LSB executable, x86-64, statically linked, not stripped |
| CVE | CVE-2026-31431 “Copy Fail” (CVSS 7.8, AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Subsystem | AF_ALG algif_aead, AEAD template authencesn(hmac(sha256),cbc(aes)) |
| Affected | Linux 4.14 to 6.19.11 (the flaw shipped in 2017, commit 72548b093ee3); fixed in 6.18.22, 6.19.12, 7.0+ |
| Target | /usr/bin/su — its in-memory .text is patched in the page cache |
| Reliability | Deterministic, no race condition |
| Usage / fallback | ./getroot <cmd> [args...]; if the exploit does not land, it runs the command with current privileges anyway |
The mechanism. A 2017 in-place optimisation in the AEAD code left the splice’d page-cache pages sitting in both the source and the destination scatterlist. When the authencesn template writes its 4-byte ESN scratch value at the attacker-chosen offset assoclen + cryptlen, that write lands inside the page-cache page of a user-readable file. The HMAC check then fails and recvmsg() returns EBADMSG, but the kernel never rolls the write back. getroot parses the ELF headers of /usr/bin/su to compute the file offset of its entry point, then loops splice → sendmsg (carrying the 4 bytes to write in the AAD) → recvmsg, once per 4-byte chunk of shellcode, patching /usr/bin/su in the page cache. It then execves /usr/bin/su: the kernel loads the now-corrupted page, the shellcode runs SUID-root, and getroot confirms getuid() == 0 before running the operator’s command (printing the Turkish [+] ROOT ele gecirildi!). The on-disk file is never touched, so file-integrity monitoring sees nothing.
Container escape to the host. The Linux page cache is host-global; containers do not get their own. A process inside an unprivileged container that splices the host’s /usr/bin/su corrupts the host’s cached copy, so the execve yields root on the host, not just in the container. An infected container is therefore a compromised host, and setup.sh goes on to load the kernel rootkit into the host. Stopping and removing the container is not enough; the host has to be rebuilt.
We ran getroot once in an isolated VM (Kali, kernel 6.6.15). It executed the full AF_ALG sequence but did not obtain root on that build and fell back to running the command unprivileged, which fits an exploit that targets specific kernel layouts. We did not run the miner.
xrandom: the miner
xrandom is a renamed, UPX-packed copy of XMRig 6.26.0, the open-source Monero miner.
| Property | Value |
|---|---|
| Real identity | XMRig 6.26.0 |
| Packing | UPX 4.2.4 (2.8 MB packed, 10.1 MB unpacked) |
| Algorithm | RandomX (rx/0) |
| Pool | pool.supportxmr.com:443 over stratum+ssl |
| Wallet | 46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ |
| Donate level | 0 (XMRig developer donation disabled) |
Mining over port 443 with TLS lets the traffic blend in with ordinary HTTPS at a glance, though the stratum handshake has a different TLS fingerprint to anyone looking closely.
stealth.c: the kernel rootkit
This is the most developed part of the toolkit. It is an LKM rootkit that uses ftrace function hooking to intercept kernel functions and erase the malware’s footprint, and it masquerades as an Intel hardware driver throughout.
| Property | Value |
|---|---|
| Module name | intel_uncore_freq_aux |
| Fake metadata | MODULE_AUTHOR("Intel Corporation"), MODULE_DESCRIPTION("Intel Uncore Frequency Control Driver"), MODULE_VERSION("1.2.0") |
| Hooking | ftrace via kallsyms_lookup_name (resolved through a kprobe on kernels 5.7 and later) |
| Control | sysfs at /sys/kernel/intel_uncore_freq/ (enabled, cpu_lo, cpu_hi, mem_lo, mem_hi, hide_tag) |
What it hooks and why:
- CPU masking. It hooks
show_statto rewrite/proc/stat, faking utilisation between configurable bounds (40 to 50 percent by default) and oscillating with jiffies so the number moves like a real load instead of sitting flat. - Memory masking. It hooks
meminfo_proc_showto rewrite/proc/meminfo, fakingMemFree,MemAvailable,Buffers,Cached,Active, andInactive. - Process hiding. It hooks
iterate_dirto filter/proclistings, hiding PIDs whose names match a hardcoded set:stealth,masscan,sshruns,ransomx,cpumask,xrandom,cpm_,kcpm,mask_helper,ftrhook,kintel_aux. An operator can add more names at runtime through/sys/kernel/intel_uncore_freq/hide_tag. - File hiding. It hides paths matching
stealth,cpumask,kintel_aux,intel_uncore_freq_aux, and the sysfs directory itself. - Self-hiding. On load it removes itself from
/proc/modulesand/sys/module/withlist_del_init, deletes its sysfs kobject, and increments its own refcount withtry_module_getsormmodwill not unload it.
That hide-list is also a tell: alongside the miner it conceals masscan, sshruns, and ransomx, so the operator is likely running a scanner and may have more than a miner in the kit.
The practical effect is that an administrator watching top sees a busy-but-normal machine, finds no rogue process, and cannot see the kernel module that is doing the lying. The tells are physical and out-of-band: the box runs hot, the fans spin up, and power draw climbs, none of which the rootkit can fake.
Persistence: three mechanisms, split by mode
Rootpacket’s persistence depends on the mode it lands in. In root mode it layers two mechanisms that reinforce each other; in userland mode it falls back to a third.
| # | Mechanism | Mode | Detail |
|---|---|---|---|
| 1 | systemd service | root | kernel-kd.service, Type=simple, Restart=always, RestartSec=3 |
| 2 | DKMS module | root | Installs the rootkit under /lib/modules/$(uname -r)/extra/; survives kernel upgrades |
| 3 | crontab | user | @reboot plus every minute (* * * * *), with a PID lock and setsid |
The DKMS entry is the stubborn one: it installs the rootkit through the kernel’s own module-build system, so a routine kernel upgrade rebuilds and re-arms it rather than removing it.
killservice.sh: clearing and closing the box
The script calls itself “cryptojacker hardening” in its banner, and that description is accurate from the operator’s point of view. It runs in three phases.
Phase 1: shut down exposed services. It targets services listening on 0.0.0.0 that are common cryptojacking entry points, stopping, disabling, and masking each one, setting chmod 000 on the binaries, and adding iptables DROP rules:
| Service | Port |
|---|---|
| Redis | 6379 |
| Docker | 2375/2376 |
| PostgreSQL | 5432 |
| MongoDB | 27017 |
| Elasticsearch | 9200/9300 |
| Memcached | 11211 |
| Hadoop YARN | 8088 |
| Jenkins | 8080 |
| Confluence | 8090 |
The Docker line is the connective tissue to our RedTail report: Rootpacket closes the exact 2375/2376 door that RedTail walks through. An operator who lands first mines the host and then locks out the next crew, hardening the box against the techniques they would have used.
Phase 2: remove rival miners. It kills processes, deletes files, cleans cron jobs, and purges SSH keys tied to known cryptojacking families, including XMRig, Kinsing (kdevtmpfsi), TeamTNT (tntrecht, mdrfckr), sustes, watchdogs, and minerd, along with scanners like masscan, pnscan, and zgrab.
Phase 3: remove userland rootkits. It strips known malicious LD_PRELOAD entries (libprocesshider.so, libjdk.so, libpamx.so, a fake libselinux.so.3, and xhide) from /etc/ld.so.preload and deletes the libraries, clearing out competitors’ userland rootkits that might interfere with its own.
Attribution
The toolkit’s Turkish-language variable names, comments, and status strings (for example ROOT ele gecirildi!, “root obtained”) point to a Turkish-speaking operator with moderate confidence. We found a distribution or staging URL at linuxutil5.pages[.]dev, hosted on Cloudflare Pages, which fits the pattern of staging payloads on free, reputable infrastructure to blend in. The inner rootpacket.tar.gz, a self-contained copy of the whole toolkit, gives the operator a ready package to push to the next host.
Indicators of compromise
Network
| Indicator | Context |
|---|---|
pool.supportxmr.com / pool.supportxmr.com:443 | Primary Monero mining pool, stratum+ssl |
linuxutil5.pages[.]dev | Distribution / staging (Cloudflare Pages) |
api.xmrig.com, randomx.xmrig.com:443 | XMRig API and benchmark endpoints |
donate.v2.xmrig.com, donate.ssl.xmrig.com | XMRig developer-donation pools (present, donation disabled) |
stratum+ssl:// to port 443 | Outbound TLS mining traffic |
Monero wallet: 46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ
Files (SHA-256)
| File | SHA-256 | MD5 |
|---|---|---|
rootpacket.tar.gz (outer) | e2d0dab6b29df89d123fe8581047a03ac9b89ae8fa0d1f334b5aefbb93152857 | |
getroot | dda96d8a4bcc39dc7679347a4386bf1024152d2ccc46d333725ad0cda855d952 | |
xrandom (packed) | ec3ef3dce99fa6cbc480f0f0b0c292676afed68704c44396271c7dc6afea2937 |
Build IDs: getroot 148d8d902efd93ed892a541972fbcea3a99d05a3, xrandom d7a91225bdd2e3ab67cabded9d7809bcc724401f.
Host artifacts
| Path | Context |
|---|---|
/opt/kernel-kd/xrandom | Miner binary (root mode) |
~/.xrandom/xrandom, ~/.xrandom/run.sh | Miner and launcher (userland mode) |
/tmp/.xrandom.lock | PID lock (userland mode) |
/etc/systemd/system/kernel-kd.service | Malicious systemd unit |
/usr/src/intel_uncore_freq_aux-1.2.0/ | DKMS source for the rootkit |
/sys/kernel/intel_uncore_freq/ | Rootkit sysfs control interface |
/lib/modules/*/extra/intel_uncore_freq_aux.ko | Compiled rootkit module |
Behavioural
- A process named
xrandomrunning as root or the current user. /proc/statCPU figures that disagree with hardware performance counters (perf stat), or with fan speed and power draw.- A systemd service
kernel-kd(enabled,Type=simple,Restart=always). - A cron entry tagged
# xrandom-userland-autostart. - A kernel module
intel_uncore_freq_auxthat loads at boot but is absent fromlsmod.
Detection
If the rootkit is not loaded
systemctl status kernel-kd.service
ls -la /opt/kernel-kd/ ~/.xrandom/
dkms status | grep intel_uncore_freq
crontab -l | grep xrandom
lsmod | grep intel_uncore
If the rootkit is loaded
The userland views are compromised, so detection has to come from below or beside the rootkit:
- Compare
/proc/statCPU against hardware counters withperf stat. A large gap is the tell. - Watch for ftrace hooks on
show_stat,meminfo_proc_show, anditerate_dir. - Treat a discrepancy between reported CPU and real power, heat, or fan speed as a strong signal.
Catching the privilege escalation
- An
AF_ALG,SOCK_SEQPACKETsocket opened by a process that is not a known crypto tool (cryptsetup,openssl,gpg,systemd-cryptsetup) is the core tell. The full order issocket(AF_ALG)→bind→setsockopt(SOL_ALG)→accept→pipe→splice→sendmsg→splice→recvmsg(repeated), thenexecve(/usr/bin/su). - Compare each SUID binary’s on-disk bytes against its page-cache view.
sha256sumreads through the cache and shows the corrupted copy, so read the disk directly withdd if=<file> iflag=directand hash that, then diff. A mismatch on a SUID binary is page-cache corruption.
Candidate YARA
rule Rootpacket_Cryptojacker
{
meta:
description = "Rootpacket Linux cryptojacking toolkit"
reference = "Kinryu Labs CTI 2026-06-16"
strings:
$wallet = "46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ" ascii
$svc = "kernel-kd" ascii
$cron = "xrandom-userland-autostart" ascii
$mod = "intel_uncore_freq_aux" ascii
condition:
$wallet or 2 of ($svc, $cron, $mod)
}
Remediation
- Remove the rootkit from a known-clean state. Boot from live or recovery media. Delete
/lib/modules/*/extra/intel_uncore_freq_aux.ko*and rundkms remove intel_uncore_freq_aux/1.2.0 --all, then delete/usr/src/intel_uncore_freq_aux-1.2.0/and rebuild the initramfs (update-initramfs -u,dracut -f, ormkinitcpio -P). The DKMS entry must go or it rebuilds. - Remove the service:
systemctl stop kernel-kd; systemctl disable kernel-kd; rm /etc/systemd/system/kernel-kd.service; systemctl daemon-reload. - Remove the miner:
rm -rf /opt/kernel-kd/ ~/.xrandom/ /tmp/.xrandom.lock, thenpkill -9 -f xrandom. - Clean cron of the
# xrandom-userland-autostartlines. - Restore what killservice.sh broke. It sets
chmod 000on Redis, Docker, PostgreSQL, MongoDB, and other binaries and adds iptables DROP rules. Reinstall the affected packages and review the firewall. - Hunt laterally. The inner
rootpacket.tar.gzis built for redistribution, so check other hosts for the same indicators, and review logs for exploitation of the services inkillservice.shto find the way in. - Close CVE-2026-31431. Patch to a fixed kernel (6.18.22, 6.19.12, 7.0+, or your distro’s backport). Where you cannot patch at once, disable the vulnerable interface:
echo 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.confthenrmmod algif_aead. For containers, blockAF_ALG(family 38) in the seccomp profile. - Assume host compromise from a container. Because the page-cache write crosses the container boundary, treat any host that ran
setup.sh, even from inside a container, as fully compromised. Rebuild the host rather than just removing the container.
MITRE ATT&CK mapping
| Tactic | Technique |
|---|---|
| Initial Access | T1190 Exploit Public-Facing Application (Redis, Docker, MongoDB, Elasticsearch, Jenkins, Hadoop YARN, implied) |
| Execution | T1059.004 Unix Shell |
| Privilege Escalation | T1068 Exploitation for Privilege Escalation (CVE-2026-31431, AF_ALG algif_aead); T1611 Escape to Host (shared page cache) |
| Persistence | T1543.002 Systemd Service; T1053.003 Cron; T1547.006 Kernel Modules (DKMS) |
| Defense Evasion | T1014 Rootkit; T1036.005 Masquerading: Match Legitimate Name; T1027.002 Software Packing (UPX); T1070.004 File Deletion; T1564.001 Hidden Files |
| Discovery | T1057 Process Discovery (rival hunting) |
| Lateral Movement | T1570 Lateral Tool Transfer (inner redistribution package) |
| Impact | T1496 Resource Hijacking (Monero mining) |
Methodology and analyst notes
- Analysis was primarily static (string extraction, disassembly, source review, structural analysis) on Kali Linux x86-64. We also ran
getrootonce in an isolated VM (kernel 6.6.15) to watch its behaviour: it attempted the AF_ALG sequence, did not obtain root on that build, and fell back to running the command unprivileged. The miner was not run, and nothing was uploaded. - The privilege-escalation component is CVE-2026-31431, identified from the
authencesn(hmac(sha256),cbc(aes))template bound to the AF_ALG socket, the/usr/bin/supage-cache target, and thesplice/sendmsg/recvmsgwrite loop in the binary. - Samples (the toolkit and its components) are available to other researchers and defenders on request. Email [email protected] with a short note on who you are and what you need them for.