shelltrap.com
en de

Guides

Find webshells on a CyberPanel server manually

A root-level triage playbook with find, grep, YARA and clamscan for CyberPanel hosts, including the honest limits of every one of those commands.

Illustration — Find webshells on a CyberPanel server manually

This is the sweep we run before anything else when a CyberPanel host is suspected of hosting a webshell. Everything below uses tools that are already on the box. Everything below also has a limit, and the limits are the reason the article is longer than the command list.

Work as root, on the server, and read before you delete.

Where to look on CyberPanel

CyberPanel puts each site’s document root at /home/<domain>/public_html. That makes server-wide sweeps easy, and it means one careless glob can walk every customer’s data at once — so keep -xdev on your find invocations and use grep -r (which follows symlinks only when they are named on the command line) rather than grep -R.

You are reading customer files as root. Have a documented operational reason for doing it, and keep the output where the rest of your incident notes live.

1. PHP where PHP has no business being

The single highest-value check on a WordPress host. A .php file below an uploads directory is not a configuration quirk:

find /home/*/public_html/wp-content/uploads -xdev -type f \
  \( -name '*.php' -o -name '*.phtml' -o -name '*.phar' -o -name '*.php[0-9]' \) -print

Extend the same idea to the other auto-loading location that never shows up in the WordPress admin UI:

ls -la /home/*/public_html/wp-content/mu-plugins/ 2>/dev/null

2. Recently written files

MITRE’s Linux detection analytic for web shells (AN1109) names file creation in the web directory as the primary signal, so start with what changed:

find /home/example.com/public_html -xdev -type f -name '*.php' \
  -newermt '-7 days' \
  -printf '%TY-%Tm-%Td %TH:%TM  %10s  %p\n' | sort

Then run it again against the inode change time. mtime is set with touch in one command; ctime is not:

find /home/example.com/public_html -xdev -type f -newerct '-7 days' \
  -printf '%CY-%Cm-%Cd %CH:%CM  %10s  %p\n' | sort

A file whose mtime is two years old and whose ctime is Tuesday is worth opening.

3. Obfuscation markers

Grep finds the lazy half of the population:

grep -rIl --include='*.php' -E \
 'eval[[:space:]]*\(|assert[[:space:]]*\(|base64_decode[[:space:]]*\(|gzinflate[[:space:]]*\(|str_rot13[[:space:]]*\(|create_function[[:space:]]*\(|\$_(GET|POST|REQUEST|COOKIE)[[:space:]]*\[[^]]*\][[:space:]]*\(' \
 /home/example.com/public_html

Expect noise. WordPress core and common libraries use base64_decode legitimately, and the last alternative in that pattern — a variable function call built from request data — matches real templating code as well as real backdoors. We list the specific core files that trip heuristics of this shape in false positives in malware scanning .

Expect misses, too. Concatenated identifiers ("ev"."al"), character-code arithmetic and multi-stage loaders all defeat a literal pattern. Grep is a filter, not a verdict.

4. Handler abuse in .htaccess

Captured exploit traffic shows attackers uploading an .htaccess that makes a harmless extension execute as PHP, so read every one of them:

grep -rIls --include='.htaccess' -E \
  'AddType|AddHandler|SetHandler|php_value|php_flag|ForceType' \
  /home/*/public_html

Anything that maps .txt, .jpg, .ico or .log to a PHP handler is an incident.

5. Known-good comparison

The NSA’s repository on mitigating web shells is unambiguous about which method works best, verbatim :

The most effective method of discovering most web shells is to compare files on a production web server with a known-good version of that application, typically a fresh install of the application where available updates have been applied.

For WordPress you get most of that for free, as the site’s own user:

sudo -u example wp core verify-checksums --path=/home/example.com/public_html
sudo -u example wp plugin verify-checksums --all --path=/home/example.com/public_html

This covers core and plugins distributed through wordpress.org. It does not cover themes, premium plugins, or anything the attacker added that was never part of a package — which is why it complements the find sweeps rather than replacing them.

6. YARA

YARA is where obfuscation-aware detection starts:

yara -r -w -f /opt/rules/webshells.yar /home/example.com/public_html

Two cautions before you adopt a rule set. First, licensing: rule collections are frequently mixed-licence artefacts, and a rule that is fine for personal use may not be fine inside a commercial hosting service. The corpus at bartblaze/PHP-backdoors — obfuscated and deobfuscated samples, CC0 — is a good way to test a rule set against both halves of the problem before you trust it, and its README points at the community YARA webshell rules as the starting point. Check the licence of whatever you pick.

Second, false positives. The NSA repository describes its own extended rules — the ones that detect obfuscation and encoding — as “likely to produce a significant number of false positive results.” That is the trade every heuristic layer makes, stated by a source with no product to sell.

7. ClamAV

clamscan -r -i --max-filesize=25M --max-scansize=100M /home/example.com/public_html

Useful, and frequently misunderstood. ClamAV’s own documentation states, verbatim:

ClamAV is not a traditional anti-virus or endpoint security suite.

There is no official claim of PHP webshell coverage on clamav.net, checked 4 September 2026. Webshell detection with ClamAV comes from third-party signature feeds — which makes the freshness of your chosen feed the thing to audit, not the scanner. When we measured the free feed that most self-built stacks use, cdn.rfxn.com/downloads/rfxn.yara returned Last-Modified: Sun, 24 May 2026 14:33:02 GMT:

curl -sI https://cdn.rfxn.com/downloads/rfxn.yara | grep -i last-modified

Re-run that yourself before you rely on it; a feed can resume at any time, and a stale date on the day you read this article is not the same as a stale date today. We go through the whole free stack in ClamAV alone is not enough for webshells .

The limits, stated plainly

  • A sweep is a point in time. Patchstack’s measured weighted median time to first exploitation in 2025 was five hours. Whatever you find today says nothing about tomorrow morning.
  • Timestamps lie. Ordering by mtime alone will hide a competent attacker’s file.
  • Literal patterns lose to obfuscation, and broad heuristics produce false positives — you get to pick which failure mode you want, and both need a human.
  • One account is not the server. If a customer is reinfected after a clean-up, the backdoor may be in a neighbouring account; see shared hosting cross-account risk .
  • Finding is not fixing. The order of operations for cleaning up afterwards is in the server-side backdoor removal checklist .

What this means for CyberPanel operators

  1. Script the three cheap checks — PHP under uploads, .htaccess handlers, ctime in the last seven days — and run them from cron with output mailed to you. They cost nothing and they catch the majority of routine drops.
  2. Pick a YARA rule set deliberately, check its licence for commercial use, and validate it against a public corpus before it touches customer data.
  3. Audit the freshness of any signature feed you depend on, and alert on it. A feed that quietly stops updating fails silently.
  4. Treat the manual sweep as incident response, not as monitoring. Continuous coverage needs something watching writes as they happen; the setup for that on CyberPanel is in the installation docs .

Shelltrap runs these checks continuously instead of on the day you get suspicious, with per-domain policies and explainable findings. See what it does .

Frequently asked

Can I trust file modification times?

Not on their own. mtime is trivially set with touch. The inode change time is harder to forge from userspace, so search with -newerct as well as -newermt and treat a file whose mtime is old but whose ctime is recent as suspicious.

Is clamscan enough on its own?

No. ClamAV’s own documentation states it is not a traditional anti-virus or endpoint security suite, and there is no official claim of PHP webshell coverage. Webshell detection with ClamAV depends on third-party signature feeds, so the freshness of the feed you chose is the thing to check.

How long does a manual sweep stay valid?

Until the next write. Patchstack measured a weighted median time to first exploitation of five hours in 2025, so a sweep is a point-in-time answer, not a state you can maintain by repeating it weekly.

Sources

Every number, date and vendor claim in this article links to one of these.

  1. nsacyber/Mitigating-Web-Shells (NSA repository) — accessed 2026-09-04
  2. ClamAV documentation — accessed 2026-09-04
  3. Linux Malware Detect signature feed, rfxn.yara (measured with curl -I) — accessed 2026-09-04
  4. bartblaze/PHP-backdoors — public corpus and its pointer to YARA webshell rules — accessed 2026-09-04
  5. Patchstack, State of WordPress Security in 2026 (covering 2025) — accessed 2026-09-04
  6. MITRE ATT&CK T1505.003 — Server Software Component: Web Shell — accessed 2026-09-04

More from the research desk

Shelltrap watches the files this article is about

Real-time detection, an upload gate in front of your PHP, explainable verdicts, and nothing leaving your server.