Investigating a web shell: forensic triage and timeline
A step-by-step forensic workflow for a suspected web shell: preservation, artifact collection on IIS and Linux, timestamp analysis, timeline building and scoping the intrusion.
Finding a web shell is the beginning of an investigation, not the end. The file proves compromise; the questions that matter are how did they get in, what did they do, where else are they, and are they still here? This guide gives a practical workflow that answers those questions while preserving evidence that may later be needed for legal, regulatory or insurance purposes.
Phase 0 — Don't destroy the evidence
The instinct to delete the file immediately is strong. Resist it.
| Do | Don't |
|---|---|
| Contain at the network layer (block attacker IPs, restrict egress, isolate via EDR) | Delete the shell or reboot the server |
| Capture volatile data (memory, running processes, network connections) | Run AV "clean" actions that quarantine and alter files |
| Hash and copy the suspect file with metadata | Open the file in an editor on the live server |
| Record every action with a UTC timestamp | Rely on memory for what was done when |
| Coordinate with legal and communications | Tell the intruder you've noticed (e.g., by defacing their shell) |
If the business impact of leaving the server running is unacceptable, capture memory and a disk image first, then take it offline.
Phase 1 — Collection
Volatile data
- Memory image — essential for in-memory implants (injected .NET assemblies, Java filters/agents, native IIS modules) and for recovering commands that never touched disk.
- Process list with command lines, parent relationships and loaded modules for worker processes.
- Network connections from the worker processes.
Web server artifacts
| Platform | Collect |
|---|---|
| IIS | The suspect file(s); C:\inetpub\logs\LogFiles\ (all sites and nodes); %windir%\System32\inetsrv\config\applicationHost.config; every web.config; Temporary ASP.NET Files; HTTPERR logs (%windir%\System32\LogFiles\HTTPERR) |
| Exchange | Above plus Exchange HTTP proxy logs (%ExchangeInstallPath%Logging\HttpProxy\), ECP/OWA logs, MSExchange Management event log |
| Apache / nginx | Document roots; access.log* and error.log* including rotated/compressed; virtual host configs; .htaccess files; PHP config and PHP-FPM pool configs |
| Tomcat / Java | webapps/, work/, conf/, logs/ (access valve and catalina.*); JVM arguments (-javaagent) |
| Upstream | Load balancer, reverse proxy, CDN and WAF logs for the same period |
Operating system artifacts
- Windows:
$MFT,$UsnJrnl:$J,$LogFile, Security/System/Application and Sysmon event logs, PowerShell operational logs, Prefetch, Amcache, ShimCache, scheduled tasks, services, local accounts. - Linux:
auditdlogs,/var/log/auth.logorsecure, shell histories, cron and systemd units,/tmpand/dev/shm,statoutput with birth times for web files.
Tools such as KAPE (Windows) and UAC (Unix-like) collect these in a forensically sound, repeatable way; Velociraptor does it across a fleet.
Phase 2 — Analyse the shell safely
Handle the file as malware: analyse on an isolated system, never execute it, and store it in password-protected archives. Establish:
- Hashes (SHA-256) for sharing and fleet-wide sweeps.
- Capabilities — command execution, file management, database access, tunnelling, reflection-based loading.
- Authentication — a hard-coded password or key suggests a specific operator or toolkit; record it (securely) because it can help identify related shells.
- Obfuscation — decode layers statically to understand behaviour, but do not publish or reuse the decoded code.
- Family — compare against threat-intelligence reporting; family attribution helps predict next steps.
Phase 3 — Establish the anchor time
Everything pivots on when the shell really appeared.
On NTFS
Parse the MFT (for example with MFTECmd) and compare the file's two timestamp sets:
| Attribute | Modifiable by user-mode tools? | Use |
|---|---|---|
$STANDARD_INFORMATION ($SI) | Yes — SetFileTime and timestomping tools | What Explorer and dir show |
$FILE_NAME ($FN) | Not directly | Usually reflects the true creation/move |
Red flags: $SI creation earlier than $FN creation; $SI timestamps with zeroed sub-second precision; a file "created" years ago in a directory created last week. The USN journal independently records FileCreate, DataExtend and RenameNewName events with timestamps and is often the most reliable source.
On Linux
Use stat to read Birth (on filesystems and kernels that expose it), Change (ctime) and Modify (mtime). A shell whose mtime has been set to match neighbouring files will still carry a recent ctime. auditd records, if enabled, give the exact creating process.
From telemetry
EDR or Sysmon file-creation events give the creation time and the creating process — the strongest possible anchor.
Phase 4 — Build the timeline
Normalise everything to UTC and merge. Plaso (log2timeline.py / psort.py) parses most of these sources into a single super-timeline; smaller, targeted timelines built from MFT, web logs and process events in Timeline Explorer or a notebook are often faster to reason about.
A typical reconstructed sequence looks like this (illustrative):
| Time (UTC) | Source | Event |
|---|---|---|
| T-0:05:12 | Web log | Burst of requests from IP A to a vulnerable endpoint; several 500 responses |
| T-0:00:03 | Web log | Successful request from IP A to the vulnerable endpoint |
| T 0:00:00 | USN / Sysmon 11 | w3wp.exe creates new .aspx file in a web-served folder |
| T+0:00:40 | Web log | First POST to the new .aspx from IP A, empty referer |
| T+0:00:41 | Sysmon 1 | w3wp.exe → cmd.exe /c whoami |
| T+0:03:10 | Sysmon 1 | w3wp.exe → cmd.exe → nltest /dclist: |
| T+1d | Web log | POSTs resume from IP B with same user agent |
| T+1d | Security 4624 | Logon type 3 from web server to file server with service account |
Key questions the timeline should answer:
- Initial access — what request, from where, immediately preceded creation?
- Operator activity — every request to the shell, and every child process it produced.
- Credential exposure — which secrets were on the server (config files, app pool identities, cached credentials) and were they accessed?
- Expansion — additional shells, new accounts, persistence mechanisms, lateral movement.
- Data access — database queries, archive creation, large responses.
Phase 5 — Scope
Web shell intrusions frequently involve more than one shell — attackers plant backups in case one is found. Sweep broadly:
- Hash and YARA sweeps across all web servers, not just the affected one (see YARA and Sigma rules).
- Log pivots — every request from the attacker's IPs and user agents, across all sites and all retained logs.
- Behavioural hunts — process-tree analytics and rare-URI log hunts across the estate.
- Configuration drift — new IIS modules, handler mappings,
.htaccessdirectives, Java agents, scheduled tasks. - Identity — use of the web server's service accounts elsewhere; new admin accounts in the application and the directory.
- Farm members and replicas — load-balanced nodes, disaster-recovery copies and backups may contain the same shell.
Documenting findings
Record for each finding: artifact path and hash, source of evidence, UTC timestamp, analyst, and confidence. Keep original evidence read-only and work from copies. A clean chain of custody matters if the incident leads to regulatory notification, insurance claims or law-enforcement referral.
Handing over to eradication
Only when the timeline and scope are understood should you move to removal — the subject of eradication and hardening. Eradicating on a partial picture is the most common reason intruders return through a second shell a week later.