BIPI
BIPI

Web Shell Hunting: From IIS Log Anomalies to Memory-Resident Implants

Cybersecurity

A practitioner walkthrough of finding China Chopper, Behinder, Godzilla, and Antsword on production web tiers, file-system signals, encoded POST patterns, YARA rules, and how in-memory shells slip past most hunts.

By Arjun Raghavan, Security & Systems Lead, BIPI · July 2, 2024 · 8 min read

#web-shell#dfir#threat-hunting

Web shells are the quietest foothold attackers still rely on in 2024. The shell itself is small, the requests look like normal HTTP, and on a busy IIS or nginx fleet a single rogue .aspx file lives happily for months. Hunting for them is less about magic and more about disciplined log pivots, file-system triage, and YARA across the right paths.

Know the families you are hunting

China Chopper is still the workhorse: a one-line dynamic-execution shell, typically under a kilobyte, driven by a Windows GUI client that ships base64-wrapped commands in a single POST parameter. Behinder (Ice Scorpion) and Godzilla added AES or XOR over the payload to defeat naive WAF inspection, so the request body looks like random binary. Antsword is a JSPM/PHP-friendly client with plugin support that frequently shows up against Tomcat and ThinkPHP.

If you cannot recognise the wire shape of each family you will miss them. Behinder traffic, for example, has very regular Content-Length values clustered around the AES block size, and almost no Referer header. China Chopper requests carry an oddly short Accept header and a body that is almost entirely one URL-encoded parameter.

File-system signals that still work

Start cheap. Walk the web root and flag files whose mtime sits inside a window of suspicious activity but whose ctime predates it (timestomp tell). Pull a list of script files (.aspx, .ashx, .jsp, .jspx, .php) under upload, image, temp, and any writable WebDAV path. Any script extension under a directory that should only hold static assets is a finding until proven otherwise.

Log patterns: IIS, Apache, nginx

On IIS, the W3C logs in C:\inetpub\logs\LogFiles are the cheapest forensic source you have. Group by cs-uri-stem and look for endpoints that only ever receive POST, never GET, from a small number of source IPs. China Chopper operators rarely change their User-Agent string between sessions, so a unique UA tied to a single URI is gold. On Apache and nginx, the same logic applies against access.log: filter to 200 responses with POST method, then sort by request count per cs-uri-stem ascending. The shells live in the long tail.

Pair this with response size analysis. A real application endpoint has a response-size distribution. A web shell, used interactively, produces wildly variable response sizes against a single URI. RITA, Zeek's http.log, and even a quick pandas notebook over the access logs will surface that variance.

YARA, but on the right paths

Run YARA across the web roots and any writable application directory, not the whole disk. The neo23x0 webshell rule pack, Thor Lite, and the Florian Roth signature sets cover the public families well. Tune for false positives in CMS plugins (WordPress and Joomla ship enough dynamic dispatch to make any naive rule scream). For Behinder and Godzilla the high-signal rules look for the AES key constants and the specific class names the loaders use.

In-memory web shells and how to find them

For IIS, dump w3wp.exe with procdump and look for loaded assemblies that do not correspond to anything in the application's bin directory. The CLR loaded-modules list, extracted via Volatility 3's windows.dlllist or directly from a memory image, will show the rogue assembly name. For Tomcat, list the registered filters and servlets via JMX or a heap dump; a filter named something like SystemFilter or AsyncListener that has no matching class file on disk is the implant.

Velociraptor has artifacts for both IIS module enumeration and JVM introspection that scale this across a fleet. Run them, do not script it by hand at 2 a.m.

Scope before you eradicate

The biggest mistake is deleting the shell first. Once it is gone you lose the ability to map every IP that touched it, every command it served, and every secondary tool the attacker dropped. Snapshot the host, preserve the logs (IIS rolls weekly by default, archive them now), pull memory, then enumerate every other host that talked to the same C2. Only then do you remove the file, rotate the application pool identity, and patch the upload primitive that let it land in the first place.

Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.