Attackers write ASPX shells as short eval-style stubs, full file managers or loaders that decrypt and reflectively load a second stage. Static content matching catches the lazy majority, file-creation telemetry catches the drop regardless of content, and request analysis catches shells that have been obfuscated beyond recognition. Use all three.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| eval with Request.Item, Request.Form or Request[...] in a script file | File scan, YARA | T1505.003 |
| System.Diagnostics.Process, Assembly.Load or Convert.FromBase64String in web content | File scan, YARA | T1620 |
| Script file created in a web path by a process that is not your deployment tooling | Sysmon 11, EDR | T1505.003 |
| Short, constant-length responses to POSTs on a single script | IIS or proxy logs | T1071.001 |
| Compilation of unfamiliar code under the ASP.NET temporary files directory | File events | T1027.004 |
Content Patterns
Most commodity shells call a handful of APIs that legitimate pages seldom combine. A small YARA rule is a good scheduled scan for web roots. This one is an illustrative starting point, not a replacement for a maintained rule set:
rule HUNT_ASPX_WebShell_Generic
{
meta:
description = "Generic ASPX web shell content patterns (hunt, tune/validate)"
reference = "Original starting point; compare with Neo23x0 signature-base"
strings:
$page = "<%@ Page" nocase
$eval = /eval\s*\(\s*Request/ nocase
$item = "Request.Item[" nocase
$form = "Request.Form[" nocase
$proc = "System.Diagnostics.Process" nocase
$load = "Assembly.Load" nocase
$b64 = "Convert.FromBase64String" nocase
$unsafe = "\"unsafe\"" nocase
condition:
filesize < 200KB and $page and
( $eval or ($item and $unsafe) or (2 of ($proc, $load, $b64) and ($form or $item)) )
}
Treat a match as a lead. Many administrative pages legitimately use Process or Assembly.Load, so scope the scan to directories that should only hold your application’s own pages.
File Creation and Request Behaviour
// Sentinel / Defender (KQL) - ASPX created outside your deployment path
DeviceFileEvents
| where ActionType in ("FileCreated", "FileModified")
| where FileName endswith_cs ".aspx" or FileName endswith_cs ".ashx"
| where FolderPath has_any ("inetpub", "wwwroot", "aspnet_client", "App_Data")
| where InitiatingProcessFileName !in~ ("msdeploy.exe", "msbuild.exe") // tune/validate
| summarize first=min(Timestamp), writes=count()
by DeviceName, FolderPath, FileName, SHA256, InitiatingProcessFileName
- Hash every script file in your web roots on a schedule and alert on any hash that is not in your deployment manifest.
- Obfuscated and compiled shells will evade string rules. Fall back on file-creation provenance, request anomalies and the child processes the shell must eventually launch.
- Review the ASP.NET temporary files directory for assemblies compiled from pages you do not recognise; it is a useful forensic breadcrumb after a shell has been deleted.
- Alert when a web-facing application pool identity writes to its own content directory; most applications never do.
Compare local rules with the Neo23x0 signature-base web shell YARA set, SigmaHQ web shell file-creation rules and Elastic’s web shell detections. Baseline your own environment: deployment tools, CMS plugins and upload features all write script-like files for legitimate reasons.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts