How web shells get planted: vulnerability classes
A conceptual map of the vulnerability classes that let attackers drop web shells — file uploads, RCE, file-write primitives, stolen admin access and more — with the defensive control for each.
A web shell is a consequence. Before an attacker can place one, they need a way to get attacker-controlled content into a location the server will execute. This guide maps those routes at a conceptual level so you can prioritise controls and know where to look first during an investigation. It deliberately contains no exploit code.
The two preconditions
Every web shell deployment satisfies two conditions:
- Write — the attacker can create or modify a file (or register a module, or inject code into memory) on the server.
- Execute — the server will interpret that content as code when it is requested.
Defensive design is largely about breaking one of the two. If uploads land in a directory where scripts never execute, a write primitive alone is not enough. If the application runs from a read-only file system, an execution bug cannot easily persist as a file.
Vulnerability classes at a glance
| Class | What goes wrong (conceptually) | Primary control |
|---|---|---|
| Unrestricted file upload | Application accepts a file with an executable extension or content and stores it under the webroot | Allow-list types, store outside webroot, no-exec upload dirs |
| Remote code execution (RCE) | Input reaches an interpreter, deserializer or command runner | Patching, input validation, safe deserialization, WAF virtual patching |
| Arbitrary file write / path traversal | Attacker controls a path used for writing (export, log, archive extraction) | Canonicalise paths, restrict write locations, least-privilege FS permissions |
| Server-side template injection | User input is rendered as a template and evaluated | Never render user input as template source; sandbox engines |
| Authentication bypass in admin features | An admin endpoint that installs plugins, themes or edits files becomes reachable without auth | Patching, restrict admin interfaces to management networks |
| Stolen or weak admin credentials | Legitimate CMS or panel features (plugin upload, theme editor) are used as intended by an intruder | MFA, disable in-app file editors, credential hygiene |
| Misconfigured HTTP methods / WebDAV | PUT or WebDAV writes are allowed on executable paths | Disable WebDAV and PUT unless required; separate storage |
| Supply chain | A compromised plugin, package or update ships the backdoor | Vendor vetting, integrity verification, dependency pinning |
| Chained edge-device bugs | Auth bypass plus command injection in VPNs, gateways, file-transfer servers | Rapid patching, exposure reduction, integrity checking tools from vendor |
Unrestricted file upload
This is the textbook case. An application offers an upload feature — avatars, attachments, résumé submissions — and fails to ensure the stored file cannot be executed. Typical weaknesses, described conceptually:
- Deny-list filtering that blocks
.phpbut not alternative extensions the server also maps to the interpreter (e.g..phtml,.php5,.pharon some PHP setups, or.ashx/.asmxalongside.aspxon IIS). - Trusting client-supplied metadata such as the
Content-Typeheader or a file name, rather than validating on the server. - Double extensions and parser discrepancies, where the application's validation and the web server's handler mapping disagree about what the "real" extension is.
- Storing uploads inside the webroot under a predictable path, with the original file name preserved.
- Archive extraction ("zip slip") where entries with
../path components are written outside the intended folder.
The durable fix is architectural rather than a better filter: store uploads outside the webroot or in object storage, serve them through a handler that sets a safe Content-Type and Content-Disposition, rename files to random identifiers, and configure upload directories so the web server never executes scripts there. The hardening guide includes server configuration for nginx, Apache and IIS.
Remote code execution in the application or framework
When an attacker can execute code, writing a web shell is a one-step follow-up that converts a transient exploit into durable access. RCE classes that have repeatedly led to web shell deployment include:
- Insecure deserialization — attacker-controlled serialized objects in Java, .NET (
ViewState,BinaryFormatter) or PHP trigger gadget chains. .NETViewStateabuse becomes possible when the server's machine keys are leaked, which is why the 2025 SharePoint "ToolShell" campaign focused on stealing them. - Expression-language and OGNL injection in Java frameworks — the class behind the 2017 Apache Struts vulnerability exploited in the Equifax breach.
- Command injection where input is concatenated into a shell command.
- Server-side request forgery (SSRF) chained with internal APIs — the pattern behind the 2021 Exchange ProxyLogon and ProxyShell chains.
Patching is the primary control. Because exploitation of newly disclosed bugs in internet-facing products often begins within days, treat edge-facing CVEs listed in CISA's Known Exploited Vulnerabilities catalogue as emergency changes, and assume compromise if a server was exposed and unpatched during a known exploitation window.
Arbitrary file write and path traversal
Some vulnerabilities do not give code execution directly but let an attacker control where data is written. Conceptually:
- An export or backup feature writes a file whose path or name is attacker-influenced. ProxyShell used exactly this: a mailbox export was directed to a path under the IIS webroot with an
.aspxextension. - A logging feature writes attacker-controlled strings into a file that is later included or executed ("log poisoning").
- A path traversal in an upload or extraction routine escapes the intended directory.
Controls: canonicalise and validate every file path against an allow-listed base directory, run the application under an identity that cannot write to its own code directories, and monitor those directories for change.
Abuse of legitimate admin features
Many CMS and hosting platforms let administrators install plugins, upload themes or edit template files from the browser. With a stolen admin password — from phishing, credential stuffing or reuse — an intruder needs no vulnerability at all. The resulting file is created by the application itself, so it looks "legitimate" in file-system telemetry.
Controls:
| Platform feature | Hardening |
|---|---|
| In-browser theme/plugin file editor | Disable it (for example, WordPress supports DISALLOW_FILE_EDIT and DISALLOW_FILE_MODS in wp-config.php) |
| Plugin/extension installation | Restrict to a deployment pipeline; make code directories read-only at runtime |
| Admin login | Enforce MFA, restrict by network, rate-limit and alert on new admin sessions |
| Admin accounts | Review regularly; alert on newly created administrators |
Misconfigured HTTP methods and WebDAV
If WebDAV authoring or the HTTP PUT method is enabled on a path that also executes scripts, an attacker can simply upload a file. This is less common on modern stacks but still appears on legacy IIS and Tomcat deployments (Tomcat's readonly default servlet parameter exists precisely to prevent it). Audit enabled methods and remove authoring modules you do not use.
Edge appliances and file-transfer products
A recurring theme since 2021 is exploitation of appliances and managed products with web front ends: VPN gateways, application delivery controllers, managed file-transfer servers and collaboration suites. Publicly reported examples include Citrix NetScaler (CVE-2023-3519), Progress MOVEit Transfer (CVE-2023-34362) and Ivanti Connect Secure (CVE-2023-46805 chained with CVE-2024-21887), all of which saw web shells or web-based implants deployed. These systems:
- are exposed to the internet by design;
- often do not support third-party EDR agents;
- may run a vendor-controlled OS where defenders have limited visibility.
Controls are therefore procedural: minimise exposure of management interfaces, subscribe to vendor advisories, apply mitigations immediately, and run vendor-provided integrity checking tools after any critical advisory — then assume compromise and investigate if the device was exposed during the exploitation window.
Supply chain and deployment pipeline
A web shell can arrive through a trusted channel: a backdoored plugin from a compromised developer account, a tampered package, or a CI/CD pipeline with weak access control. Here the "vulnerability" is trust. Controls include pinning and verifying dependencies, reviewing third-party plugins before installation, restricting who can publish to production, and comparing deployed code against the repository.
Prioritising controls
If you can only do a few things, these break the largest number of routes:
- Patch internet-facing software fast, with emergency handling for known-exploited CVEs.
- Make code directories read-only to the runtime identity; deploy only through a pipeline.
- Never execute from upload directories, and preferably keep uploads out of the webroot entirely.
- Protect admin interfaces with MFA and network restrictions.
- Monitor for new executable files in web-served paths — covered in file integrity detection.
Using this map during an investigation
When you find a web shell, the vulnerability class often determines where evidence of initial access lives:
| Suspected route | Where to look first |
|---|---|
| File upload | Application upload logs; web logs for the upload endpoint just before the shell's creation time |
| RCE / deserialization | Web logs for unusual requests to the vulnerable endpoint; application error logs; process creation by the worker around creation time |
| Arbitrary file write | Logs of the export/backup feature; the process that wrote the file |
| Admin abuse | Authentication logs for admin logins; CMS audit logs |
| Edge appliance | Vendor integrity-check output; appliance logs forwarded to your SIEM |
The forensic investigation guide walks through that pivot in detail.