ENGINEERING

CWPdoor: a backdoored cwpsrv hides inside Control Web Panel. Three commands to check yours

XLab found a backdoored build of cwpsrv, the web server behind the Control Web Panel (CWP, formerly CentOS Web Panel) admin interface, and BleepingComputer reported it on November 5. XLab calls it CWPdoor. It first showed up on June 29, and XLab counted more than 340,000 CWP instances exposed to the internet in the past month.

A fake updater script, cwpsrv_update.sh, replaces /usr/local/cwpsrv/bin/cwpsrv with a trojanized 1.15.10 or 1.24.0 build. It keeps the original as cwpsrv.prev-<date>-<time>, puts the file timestamps back and wipes the shell history. The backdoor does nothing until a request arrives with three headers, X-Ngx-Integrity-Time, -Data and -Sig. The command is AES-encrypted and RSA-signed, and the backdoor keeps that request out of the access log. So the panel works normally, and the logs look clean.

Check one server

These are XLab’s checks, as root on the CWP server:

strings /usr/local/cwpsrv/bin/cwpsrv | grep X-Ngx-Integrity   # any output: trojanized
ss -axp | grep integrity                                      # a socket named ngx_http_integrity_helper
ls -l /usr/local/cwpsrv/bin/cwpsrv.prev-*                     # a backup left by the fake updater

strings comes from binutils, which a minimal server may not have. grep -a X-Ngx-Integrity /usr/local/cwpsrv/bin/cwpsrv does the same job without it.

XLab also published MD5s for the two trojanized builds (965aea67fb40de1bab5169ada993349f for 1.15.10, d3f4e95113d49ab3991b45e457bda75b for 1.24.0) and its command-and-control address, 136.0.141.71. A clean hash doesn’t clear you. Another build could carry the same backdoor, so the strings check matters more than the hash.

If you find it

  1. Take the server off the network, or at least block the CWP admin ports.
  2. Reinstall cwpsrv from CWP and update CWP.
  3. Rotate the panel, root and hosting account passwords and the SSH keys. The attacker could run anything as the web server.
  4. Look for other malware. XLab’s evidence also held a libkeyutils.so.1.5.2, so check for files like that which no package owns (rpm -qf <file>).

Doing it with RFF

The RFF Script Library has a CWPdoor compromise check for Linux. It hashes cwpsrv against XLab’s samples, searches it for the X-Ngx-Integrity strings, looks for the helper socket, the cwpsrv.prev-* backups, cwpsrv_update.sh, an unowned libkeyutils.so.1.5.2 and connections to the C2, and reports the cwpsrv version. On a server without CWP it reports “not installed” in a second. I didn’t run the real backdoor in the lab. I tested the check in a Rocky 9 container on my lab VM against a harmless stand-in for each indicator: a fake cwpsrv holding the strings, a dummy socket and a dummy backup file.

RFF is free for your first 100 endpoints: getrff.com.

Sources

One email per new post, nothing else. Unsubscribe in one click. Or use the RSS feed.

Comments

Comments use GitHub Discussions, so you'll need a GitHub account to post. Corrections are especially welcome.