Possible CWP security issue - root compromise, OMRIG miner and port 2304 exposed

Started by Wonder, October 05, 2026, 02:28:05 PM

Previous topic - Next topic

Gani Karaoğlu

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 Guide

Hey 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 it
If 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 it
Order 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 recommend
A 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

max

My server had the exact hack also. as soon as I saw it i wiped it instead of messing around. I had ssh off entirely. I will read more here as how they got into it I had it locked down good. test123zz was found and fake Index.php

akinsayo

It would be nice if CWP admin can have a kind of tool to scan and deal with this kind of issue for users not too techie. Would be really really nice.

Administrator

cwp has already fixed all and this problem were in cwp 1.26 or lower.
if infected (alerts in cwp) our system admins cleans your servers very fast, you only need to open a support ticket

also in each new cwp version we improve cleaning script so infected servers gets cleaned.

Latest cwp versions are now much more secure compared to other control panels.

Our new moto is security and stability first, as you can see we release new updates every day with improvements and bugs found or reported by our clients or 3rd party security experts.

Also forum is monitored by our devs for bugs/issues so those also get resolved in new versions.

Also we are bringing many new tools in future versions as you can see in our Edge-Latest version.


itoma

I can confirm this campaign on one of my servers too. The entry point was the CWP API (port 2304): attacker commands were injected through API calls and executed as root. The server is cleaned up and secured now.

Everyone should check their API log, even if you are already on the latest CWP version. Updating closes the hole, but it does not show whether you were hit before:

grep -nE '146\.103\.45\.130|184\.107\.106\.86|80\.78\.31\.62|212\.132\.98\.170|/home/x;|;ls;|base64 -d' /var/log/cwp/cwp_api.log

Any match means commands were executed on your server, and it should be treated as compromised.

Recommendations:

close port 2304 and all panel ports in CSF TCP_IN, or allow them only for your own IPs;
restrict outbound traffic (TCP_OUT) to what your server really needs, because this campaign uses common ports such as mail ports to send data out;
rotate all credentials if you find a match.