PlaybookCONSTRUCTED
Web application compromise response plan: from the first odd request to a rebuilt server
A web shell, an exploited framework, or a server process doing things a web server never does. A plan for preserving the evidence that rotates fastest, finding the first malicious request, working out what the server could reach, and rebuilding so the same request fails next time.
version 1.0checked 2026-09-26windows · linux · cloud5 min read
T1190T1505.003T1059.003T1059.004T1552.001T1041
What this plan is for
A public-facing web application or its server has been compromised, or very probably has. Typical triggers:
- EDR reports the web server process (w3wp.exe, httpd, nginx, java, php-fpm) starting a shell or a scripting host.
- A file appeared in the web root that nobody deployed, or a scanner found a known web shell.
- A web application firewall or IDS alert on an exploit for a framework you run, followed by something that looks like success.
- A defacement, a redirect nobody configured, or a vendor advisory for a product you expose, marked as exploited in the wild.
The first minutes are in the web shell first 15 minutes checklist, and the first hour in the web shell on a public-facing server playbook. The hunt for the most telling symptom is web server spawns a shell.
Phase 1: preserve, fastest-rotating first
Goal: keep the evidence that disappears on its own, before anything is changed.
- Memory and live state, if the server is still running the attacker's process or connection: running processes with command lines and parents, network connections, and a memory image if you can take one without destabilising a production system.
- Web server access logs. They rotate, sometimes daily, and often live only on the server. IIS writes them under
%SystemDrive%\inetpub\logs\LogFilesby default; Apache and nginx usually under/var/log/apache2or/var/log/httpd, and/var/log/nginx. Take the load balancer, reverse proxy and WAF logs too, because they hold the real client address when the server only sees the proxy. - The web root, with timestamps intact. Copy it as an archive or image, not by opening files on the live server. Include configuration files.
- Application and framework logs, and the database's own logs if the application has one.
- For containers or autoscaled instances, snapshot the running instance or save the container's filesystem before it is recycled. An instance replaced by the autoscaler takes its evidence with it.
Phase 2: find the first malicious request
Goal: the moment the foothold was created, and the request that created it.
- Anchor on what you know. The web shell's creation time, the first suspicious child process of the web server, or the WAF alert.
- Read the access log around the anchor. Requests to the web shell's path give you the operator's address and user agent. Every earlier request from that address is part of the story.
- Look for the exploit shape. POST requests to paths that normally take GET, requests to static files that return 200 with large responses, long or encoded query strings, unusual methods, and error bursts followed by a success. The request immediately before the shell's creation time is usually the exploit or the upload.
- Match against known exploited vulnerabilities. Check the application's framework and every component against the CISA Known Exploited Vulnerabilities catalogue and the vendor's advisories. A match with a published exploit usually explains the request pattern.
- Rule in or out stolen credentials. An upload through a legitimate admin panel, using a real account, looks nothing like an exploit and needs the account investigated instead.
Phase 3: work out what the server could reach
Goal: the blast radius, from the server's own position.
| What to check | Why it matters |
|---|---|
| Every process the web server process started, over the whole window | The operator's commands, from EDR or Sysmon process creation, or auditd on Linux |
| Credentials in configuration files, environment variables and connection strings | They are the first thing read after a foothold. Rotate every one, whether or not you find evidence of use |
| The database the application uses | Queries run from the web server account outside the application's normal pattern, and bulk reads |
| Outbound connections from the server | Web servers rarely need to start outbound connections. Any to unfamiliar destinations is data transfer or command and control |
| Connections from the server to the internal network | A web server is a foothold into whatever it can reach. SMB, RDP, SSH or WinRM from it to internal hosts is lateral movement |
| Other servers built from the same image or code | The same vulnerability is almost certainly present on each of them |
Phase 4: eradicate by rebuilding
- Rebuild the server from a known-good image and a clean deployment of the application. Cleaning a compromised web server leaves you trusting that you found everything, and web shells are small and easy to miss.
- Fix the way in before exposing the rebuild. Patch the vulnerability, remove the vulnerable component, or close the admin panel to the internet. A rebuilt server with the same flaw is compromised again by the same request.
- Rotate every credential the old server held, including database accounts, API keys and certificates with private keys on the box.
- Check the rest of the estate for the same indicators and the same vulnerability.
Phase 5: verify
- Replay the exploit request against the rebuilt server in a controlled way, or confirm with a scanner that the vulnerable version is gone.
- Watch the new server for the operator's addresses, user agents and request patterns for an agreed period.
- Alert on the web server process starting shells or scripting hosts. It is the single most reliable detection for this whole class of incident, and it costs almost nothing.
What the write-up needs
The first malicious request and how it worked, the window, every command run through the foothold, what credentials and data were reachable, what left if anything did, and the change that makes the same request fail now.