← Digital forensicshunting web shells on your own server

hunting web shells on your own server

$find /var/www -name '*.php' -mtime -7

why web shells are the quiet nightmare

a web shell is just a file, usually php, sitting on your server pretending to be part of your site. someone uploads it once through a vulnerable contact form or an outdated plugin, and after that they don't need to "hack" anything again. they just visit the file in a browser and now they have a command line into your server. no malware alert, no popup, nothing. it just sits there in your file list looking boring until you actually check it.

here's the good news: if you run the server, you have every tool you need to find it. you just have to know where to look.

step 1: find what changed recently

attackers usually drop their shell and move on, so the first move is spotting any php file that was touched recently when you weren't touching anything.

find /var/www -name '*.php' -mtime -7

let's break that down:

find /var/www starts the search in your web root, wherever your site files actually live.
-name '*.php' only shows php files, since that's the most common language for web shells on a lamp stack.
-mtime -7 filters to files modified in the last 7 days.

if you didn't push a deploy or update plugins this week and php files are showing up anyway, that's your starting list of suspects. adjust the number for your own update schedule, if you deploy daily this command is noisy, if you deploy once a month it's a flashlight pointed right at the problem.

step 2: php where php shouldn't be

uploads folders exist to hold images, pdfs, maybe a zip file. they should never execute code. if you see a .php file sitting in /wp-content/uploads/ or any folder meant for user-submitted files, that is a massive red flag on its own, age doesn't even matter at that point.

a quick way to check:

find /var/www -path '*/uploads/*' -name '*.php'

anything that command returns needs your eyes on it immediately.

step 3: grep for the usual suspects

web shells lean on a small set of php functions to actually do damage, run system commands, or hide their real payload. search your suspect files for these:

grep -l -E 'eval\(|base64_decode\(|shell_exec\(' /var/www -r

eval( runs whatever string gets handed to it as code, which is exactly how shells stay hidden, the real malicious code is often obfuscated and only "unwrapped" at runtime.
base64_decode( is frequently paired with eval to disguise the payload as gibberish text instead of readable php.
shell_exec( hands commands straight to the server's operating system.

none of these are automatically evil, plenty of legit code uses them, but combined with an unexpected file in an unexpected place, it's basically a confession.

step 4: check who's been visiting it

once you've got a suspect file, check your access logs for requests to it:

grep "suspicious-file.php" /var/log/apache2/access.log

look specifically for POST requests. web shells almost always get controlled via POST data, since that's how the attacker sends commands to the file. a long list of POSTs to a random-looking filename you've never heard of is confirmation, not coincidence.

step 5: clean it up properly

deleting the file is not the finish line, it's the halfway point. do this in order:

remove the file, obviously.
close the hole it came through, usually an outdated plugin, theme, or an upload form with no file-type restrictions.
rotate every credential on that server, database passwords, admin logins, api keys, ssh keys, all of it. assume anything on that box was visible to whoever got in.
check what else they touched, re-run the find and grep commands across the whole site, attackers often drop a second, quieter shell as a backup in case you find the first one.

the takeaway

web shells survive because people treat "the site looks fine" as proof nothing happened. it isn't. run these checks on a schedule, not just when something feels off, because by the time something feels off, the shell's already had its fun. save this post, send it to whoever actually manages your wordpress or php site, and make hunting for this stuff a five-minute monthly habit instead of a five-hour emergency.

watch the reel ↗
the weekly drop

one command a week that makes you harder to hack.

a single tool, explained in plain english, every week. straight to your inbox.

no spam. one email a week. unsubscribe anytime.