// Security · Web Shell Detection
Web Shell Detection in Logs
A web shell is a backdoor script (usually PHP) uploaded to your server through a file upload vulnerability, compromised FTP credentials, or a vulnerable plugin. Once active, it shows as GET/POST requests to a PHP file in an unexpected location — usually the uploads directory. Logs are your primary detection tool.
Web Shell Log Signatures
PHP in Uploads Directory (strongest indicator)
# PHP file served from uploads — almost never legitimate 185.220.101.45 - - [10/Apr/2025:02:14:00 +0000] "GET /wp-content/uploads/2025/03/image.php HTTP/1.1" 200 18420 185.220.101.45 - - [10/Apr/2025:02:14:01 +0000] "POST /wp-content/uploads/2025/03/image.php HTTP/1.1" 200 420 # Shell with cmd parameter (executing OS commands) 185.220.101.45 - - [10/Apr/2025:02:15:00 +0000] "GET /wp-content/uploads/2025/03/thumb.php?cmd=whoami HTTP/1.1" 200 8 185.220.101.45 - - [10/Apr/2025:02:15:30 +0000] "GET /wp-content/uploads/2025/03/thumb.php?cmd=cat+/etc/passwd HTTP/1.1" 200 1840
Known Shell File Names
# Classic named shells 91.108.4.12 - - [10/Apr/2025:03:00:00 +0000] "GET /c99.php HTTP/1.1" 200 45200 91.108.4.12 - - [10/Apr/2025:03:00:01 +0000] "GET /r57.php HTTP/1.1" 200 38100 91.108.4.12 - - [10/Apr/2025:03:00:02 +0000] "GET /b374k.php HTTP/1.1" 200 55000 # Random-looking names are also common — short, no relation to site content 91.108.4.12 - - [10/Apr/2025:03:01:00 +0000] "GET /wp-content/uploads/xbz.php HTTP/1.1" 200 22100
Shell Probe Before Execution (attacker confirming shell is alive)
# Attacker probing recently uploaded file — small response = echo output 185.220.101.45 - - [10/Apr/2025:02:13:55 +0000] "GET /wp-content/uploads/2025/03/image.php HTTP/1.1" 200 3 # 3-byte response is likely "ok\n" — a health check echo in the shell # Followed immediately by exploitation 185.220.101.45 - - [10/Apr/2025:02:13:56 +0000] "POST /wp-content/uploads/2025/03/image.php HTTP/1.1" 200 1840
Encoded Shell Commands
# base64-encoded command (evades simple string matching) 185.220.101.45 - - [10/Apr/2025:02:20:00 +0000] "GET /admin/tmp.php?x=Y2F0IC9ldGMvcGFzc3dk HTTP/1.1" 200 1840 # Decode: echo 'Y2F0IC9ldGMvcGFzc3dk' | base64 -d → cat /etc/passwd # Hex-encoded via PHP hex2bin or similar 185.220.101.45 - - [10/Apr/2025:02:20:30 +0000] "POST /include/config.php HTTP/1.1" 200 4200
Filesystem Checks (Beyond Logs)
bash
# Find PHP files in upload directories find /var/www/html/wp-content/uploads -name "*.php" -o -name "*.phtml" -o -name "*.php5" # PHP files modified or created in the last 7 days (anywhere in webroot) find /var/www/html -name "*.php" -newer /var/www/html/index.php -mtime -7 -ls # Search PHP files for shell indicators grep -rEl "(eval|base64_decode|str_rot13|gzinflate|gzuncompress)\s*\(" /var/www/html/ 2>/dev/null # Find files with shell_exec / system / passthru (execution functions) grep -rEl "shell_exec|passthru|proc_open|popen|system\s*\(" /var/www/html/ 2>/dev/null # Hidden files in web root (dot files shouldn't be there) find /var/www/html -name ".*" -not -name ".htaccess" -ls # Files owned by www-data that were recently modified (server wrote them = suspicious) find /var/www/html -user www-data -name "*.php" -mtime -14 -ls
Log-Based Detection Commands
bash
LOG=/var/log/nginx/access.log # PHP execution in upload/image/media directories grep -iE "/(uploads|files|media|images|cache|tmp)/.*\.php" $LOG # cmd= / exec= parameter to any PHP file grep -iE "\.php\?(cmd|exec|command|run|shell|code)=" $LOG # Known shell names grep -iE "/(c99|r57|b374k|wso|alfa|indoxploit|priv8|symlink|shell|backdoor|hack)\.php" $LOG # Large POST to unexpected PHP files (shell receiving data) awk '$6=="\"POST" && $7 ~ /\.php/ && $10+0 > 500' $LOG | grep -v "wp-cron\|wp-login\|xmlrpc\|wp-admin\|upload\|contact" # All IPs that accessed a PHP file in uploads grep -iE "/uploads/.*\.php" $LOG | awk '{print $1}' | sort -u
🚨 Confirmed Web Shell
If you find a 200 response to a PHP file in /uploads/ or any non-PHP directory: your server is actively compromised. Immediately: take the site offline, preserve logs, remove the shell file, audit the entire filesystem with the commands above, rotate all credentials, and check for cron jobs added by the attacker (crontab -l -u www-data).