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. 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. 2.Collect web server error logs for stack traces and application errors that may indicate exploitation attempts.
  3. 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. 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. 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 files
W3CIISLog | 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.