Collect and Analyze Web Server Logs for Web App Compromise
CollectionP290 min
IR AnalystSwitch roles in the top navigation to see different perspectives.
Collect IIS, Apache, and Nginx access/error logs along with WAF logs to identify web shells, suspicious uploads, SQL injection, and other web application attack patterns.
Actions
- 1.Collect web server access logs: Apache/Nginx (`/var/log/apache2/access.log`, `/var/log/nginx/access.log`), IIS (`C:\inetpub\logs\LogFiles\`). Include rotated/archived logs covering the investigation timeframe.
- 2.Collect web server error logs for stack traces and application errors that may indicate exploitation attempts.
- 3.Collect WAF logs if available (ModSecurity, AWS WAF, Azure WAF, Cloudflare). These contain blocked and flagged requests that may show earlier attack attempts.
- 4.Search for web shell indicators: `grep -rn "eval\|base64_decode\|system\|exec\|passthru\|shell_exec" /var/www/ --include="*.php"` or for IIS: search for `<%.*eval\|Execute\|CreateObject.*%>` in aspx/asp files.
- 5.Parse access logs for attack patterns: unusual POST requests to upload endpoints, requests to newly created files, requests with encoded payloads in parameters, and requests from known malicious IPs.
Queries
index=web sourcetype=access_combined OR sourcetype=iis | where status >= 400 | stats count by uri_path, status, clientip | where count > 50 | sort -count // Find frequently targeted URIs
index=web sourcetype=access_combined | where method="POST" | where uri_path=".php" OR uri_path=".aspx" OR uri_path=".jsp" | where NOT uri_path IN ("/login.php", "/api/*") | stats count values(clientip) by uri_path | where count < 10 // Find suspicious POST to uncommon filesW3CIISLog | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where scStatus >= 200 and scStatus < 300 | where csUriStem endswith ".aspx" or csUriStem endswith ".asp" or csUriStem endswith ".ashx" | where csUriStem !in~ (KNOWN_GOOD_PAGES) | summarize RequestCount=count(), DistinctIPs=dcount(cIP) by csUriStem | where DistinctIPs == 1 // Find pages accessed by single IP (potential web shell)
Notes
- Web shells are often placed in directories that are writable by the web server process. Focus on upload directories, temp directories, and any directory with write permissions.
- Check for encoded or obfuscated web shells that may evade simple string searches. Use tools like PHP-malware-finder or YARA rules for detection.