Most of the fixes have already been pointed out in this thread. I originally wrote my post in Turkish, partly for Turkish users who have a hard time following English — here's the English version.Fileless XMRig Miner on CWP — Detection, Cleanup, and Prevention GuideHey all. My AlmaLinux 8 + CWP box got hit by this campaign too, so I figured I'd share — looks like plenty of people are dealing with the same thing. Short version: a fileless XMRig (Monero) miner running as root, with no file on disk. It hid for weeks by disguising itself as a kernel thread and as fake systemd services. The good news: because I keep outbound ports locked down in CSF, the miner could never reach its pool — so it earned the guy exactly zero

Below is how I spotted it, how I cleaned it, and what I'd recommend.
What is it, how does it work?What I caught was XMRig; the RandomX algorithm in its config.json makes it clear it's mining Monero. Three things kept me from seeing it for months:
• No file on disk. It runs from an in-memory file (memfd), so you can't see it with ls, signature scanners like ClamAV/maldet won't find it, and even rpm -V comes back clean.
• It runs inside a separate network namespace (netns), so its connection doesn't show up in normal ss/netstat output.
• In the process list it hides under kernel-thread-looking names like [kworker/...], [netns], [kaluad]. For persistence it also creates fake systemd units that look like system services.
Worst part: this thing runs as
root (UID 0). So it's not a single hacked site — the server is compromised at the kernel level. The miner kept trying to reach its pool, but the firewall blocked the outbound connection so it never got through.
What to look for (IOCs)These IOCs are from my case. But they rotate names/IPs often, so instead of searching for exact names, look for the pattern: fake names that look like system services, port 3333, and blocked outbound connections coming from root.
Type - Value / Indicator
• Mining pool 146.103.45.130:3333 (Singapore)
• C2 server 212.132.98.170
• Outbound port 3333/tcp (stratum)
• Fake systemd services dbus-monitor-srv, systemd-logind-helpers, polkitd-helpers, auth-policykit, defunct
• Fake binaries /usr/bin/dbus-monitor-srv, /usr/bin/polkitd-helpers, /usr/bin/config.json, /usr/sbin/netd, /usr/sbin/authd, /usr/sbin/udevd-sync, /usr/lib/systemd/system/defunct.dat
• In the process list fake kernel threads like [kworker/...], [netns], [kaluad] whose parent is NOT PID 2 (kthreadd)
• Clearest sign tens of thousands of *TCP_OUT Blocked* entries to port 3333 in the CSF logs, with UID=0
• Web shell files test123zz, 404.php, cwp_login_********.php (inside client public_html)
• Extra fake binary /usr/sbin/bootcfg
• Extra fake threads [kstrp], [card0-crtc8]
• Download / persistence sources raw.githubusercontent.com (Kyy-Shell), gs.thc.org, memek.cc
• Exfiltration host 184.107.106.86
• Suspected entry port 2304 (CWP External API)
The bottom half of the table belongs to the campaign's web shell + GSocket stage. Some of it I saw on my own server, some was shared by others hit by the same campaign — you may not have every one of them.
How to find itIf you're seeing similar signs, these checks will surface the miner. They're all read-only, won't break anything, run them without worry.
1. Check the outbound block logs (fastest). A high count to a single port and single IP, from UID=0, is the miner beacon:
grep -h 'TCP_OUT Blocked' /var/log/messages* | grep -oE 'DPT=[0-9]+' | sort | uniq -c | sort -rn | head
2. Processes running from a deleted or memfd binary (the clearest sign of a fileless miner):
ls -l /proc/*/exe 2>/dev/null | grep -iE 'deleted|memfd'
3. Fake kernel threads (bracketed name but parent is not PID 2 / kthreadd):
ps -eo pid,ppid,user,cmd --no-headers | awk '$4 ~ /^\[/ && $2 != 2 && $1 != 2'
4. systemd services whose executable doesn't belong to any package: for f in /etc/systemd/system/*.service /usr/lib/systemd/system/*.service; do b=$(grep -m1 -oP '^ExecStart=[-@+!]*\K\S+' "$f" 2>/dev/null); [ -n "$b" ] && [ -e "$b" ] && ! rpm -qf "$b" >/dev/null 2>&1 && echo "$f -> $b"; done
5. High CPU and current outbound connections (a miner eats CPU):
ps -eo pid,user,pcpu,etimes,comm --sort=-pcpu | head
ss -tnp state established | grep -vE '127.0.0.1|::1'
6. Kernel-level backdoor check (this file shouldn't normally exist):
cat /etc/ld.so.preload 2>/dev/null || echo 'none - good'
How I cleaned itOrder matters: collect evidence first, then kill. Do it the other way around and you'll kill the process but the persistence mechanism brings it back five minutes later — and you lose the trail. Replace <PID> in the commands with the process you actually found.
1. Freeze and collect evidence. SIGSTOP the process and copy its /proc:
IR=/root/ir-$(date +%F-%H%M); mkdir -p $IR && chmod 700 $IR
kill -STOP <PID>
cp /proc/<PID>/exe $IR/miner.bin; sha256sum $IR/miner.bin | tee $IR/sha256.txt
cat /proc/<PID>/maps > $IR/maps; tr '\0' '\n' < /proc/<PID>/environ > $IR/environ
ss -tunap > $IR/ss.txt; ps auxwwf > $IR/ps.txt
2. Stop and mask the fake services (so they don't come back on reboot):
for s in dbus-monitor-srv systemd-logind-helpers polkitd-helpers auth-policykit defunct; do systemctl disable --now $s.service; systemctl mask $s.service; done
3. Kill the processes (CONT first, then KILL):
for p in <PID list>; do kill -CONT $p 2>/dev/null; kill -9 $p; done
4. Quarantine the malicious files (don't delete; keep evidence and hashes):
Q=$IR/quarantine; mkdir -p $Q
for f in /usr/bin/dbus-monitor-srv /usr/bin/polkitd-helpers /usr/bin/config.json /usr/sbin/netd /usr/sbin/authd /usr/sbin/udevd-sync /usr/lib/systemd/system/defunct.dat; do [ -e "$f" ] && mv "$f" $Q/; done
chmod -R 000 $Q
5. Block the pool and C2 IPs: csf -d 146.103.45.130 "XMRig pool"
csf -d 212.132.98.170 "C2"
6. Check for leftovers and reboot. Run systemctl daemon-reload, confirm no suspicious process/reference remains, then do a planned reboot. memfd processes live only in memory; a reboot clears them for sure and proves the persistence is actually gone (by not coming back).
Warning: Once a box has been rooted, you can never fully trust it again. Cleanup removes the immediate danger, but the safest path is to move to a clean server and retire the old one.
How did it get in?Honestly, I couldn't pin down the exact entry (it was spread over weeks, logs had rotated). But the thing people in this thread suspect most is the CWP External API, i.e. port 2304. Also, it's not a single piece: first a web shell drops (test123zz, 404.php, cwp_login_********.php into public_html), then a GSocket-based root backdoor (defunct, auth-policykit), and the miner last. The entry-point candidates:
CWP panel vulns. The CWP UI runs as root, so an RCE there gives you root directly. Known, actively exploited criticals:
• CVE-2022-44877 (
https://thehackernews.com/2023/01/alert-hackers-actively-exploiting.html) — Unauthenticated RCE; command injection in the login (login/index.php) parameter. CVSS 9.8. Actively exploited in the wild since January 2023. Patched around 0.9.8.1147 — verify your own version.
• CVE-2025-48703 (
https://www.helpnetsecurity.com/2025/11/05/control-web-panel-cve-2025-48703-exploited/) — OS command injection (CWE-78) in the t_total parameter of the filemanager changePerm API. CVSS 9.0. Affects all versions before 0.9.8.1205 (June 2025). The injection needs no authentication; it only needs a valid (non-root) username, which is easy to guess on a hosting server. Added to CISA's actively-exploited list on November 4, 2025.
• There are other CWP RCEs too, like CVE-2023-42121 (
https://nvd.nist.gov/vuln/detail/CVE-2023-42121). Bottom line: keep CWP on the latest version.
CWP External API (port 2304). This is where everyone in the thread points. The service can listen as root on 0.0.0.0:2304; if you don't use it, turn it off in the CWP panel, and if you do, open it only to trusted IPs and keep 2304 closed to the outside in CSF TCP_IN (it shouldn't be in the list by default anyway).
PHP / site side. On Linux, PHP itself is rarely the direct entry (e.g. CVE-2024-4577 mostly hits Windows/CGI). The real trouble is outdated WordPress and plugins: a PHP web shell drops through them, the attacker runs code as the site user first, then escalates to root via a local bug. Disabling functions like exec, system, shell_exec, passthru, proc_open, popen via disable_functions greatly limits what a web shell can do even if one lands.
What I'd recommendA firewall that restricts outbound traffic leaves the miner earning nothing, even as root. In order of importance:
• Restrict outbound connections in CSF. Instead of the default "allow everything," limit TCP_OUT/UDP_OUT to only the ports you need. Mining pools use ports like 3333, 4444, 5555, 7777, 14444; if those are closed the miner can't reach the pool. This is the one thing that kept earnings at zero in my case.
• Keep CWP updated. Panel RCEs are the biggest door. Enable auto-updates, check the version regularly.
• PHP disable_functions. Turn off the dangerous exec functions (previous section). Separately for each PHP version.
• Watch critical files with auditd — into /etc/audit/rules.d/hardening.rules:
-w /etc/passwd -p wa -k identity
-w /root/.ssh/ -p wa -k rootssh
-w /etc/systemd/system/ -p wa -k systemd
-w /var/spool/cron/ -p wa -k cron
• Kernel hardening (sysctl): kernel.yama.ptrace_scope=1, fs.protected_regular=2, fs.protected_fifos=2 — makes cross-process memory reads and /tmp attacks harder.
• SSH: key-only (PermitRootLogin prohibit-password), non-standard port, low MaxAuthTries.
• Behavior-based monitoring. Signature scanners (ClamAV/maldet) can't see a fileless/memfd miner. Wazuh (file integrity + logs) and Falco (abnormal syscall/process behavior) are far better at catching this kind of threat.
• Clean rebuild. If you've been rooted, the safest long-term path is to move to a clean server and shut the old one down.
Sources: • CVE-2022-44877 — critical CWP RCE under active exploitation (The Hacker News):
https://thehackernews.com/2023/01/alert-hackers-actively-exploiting.html • CVE-2025-48703 — Control Web Panel actively exploited (Help Net Security):
https://www.helpnetsecurity.com/2025/11/05/control-web-panel-cve-2025-48703-exploited/ • CVE-2025-48703 — technical details (Wiz):
https://www.wiz.io/vulnerability-database/cve/cve-2025-48703 • CVE-2023-42121 — NVD:
https://nvd.nist.gov/vuln/detail/CVE-2023-42121 • CWP forum — IOC discussion for this campaign (root compromise, XMRig, port 2304):
https://forum.centos-webpanel.com/centos-webpanel-bugs/possible-cwp-security-issue-root-compromise-omrig-miner-and-port-2304-exposed/msg54340/#msg54340