// Security · Web Attacks
Identifying Web Attacks in Logs
Your web server access log is the primary forensic record of every attack against your site. This page covers how to recognise attack patterns, scanner activity, and automated exploitation attempts directly from Apache or Nginx access logs — no special tools required.
Anatomy of an Attack Request
Most web attacks are visible in the URI ($7 in awk) and the response status. A normal request looks clean; an attack request contains encoded characters, known exploit strings, or references to sensitive files.
185.220.101.45 - -
[10/Apr/2025:03:14:59 +0000]
"GET
/wp-admin/admin-ajax.php?action=query&sql=1+UNION+SELECT+1,user(),3--
HTTP/1.1"
200
512 "-"
"sqlmap/1.7.8"
⚠ Automated tool UA (sqlmap)
⚠ UNION SELECT in URI = SQLi probe
⚠ 200 response = server returned data
Attack Pattern Recognition Table
| Pattern in URI / UA | Attack Type | Severity | What It Means |
|---|---|---|---|
| UNION SELECT, OR 1=1, --+, %27, information_schema | SQL Injection | Critical | Automated or manual SQLi probe. 200 response = possible data leak. |
| <script>, onerror=, javascript:, alert(, %3Cscript | XSS | Critical | Cross-site scripting payload injection attempt. |
| ../../../, %2e%2e%2f, ..%5c, %252e%252e | Path Traversal | Critical | Attempting to read files outside web root (e.g. /etc/passwd). |
| /etc/passwd, /etc/shadow, /proc/self, wp-config.php, .env, .git/config | Sensitive File Access | Critical | Direct attempt to read credentials, config files, or source code. |
| cmd=, exec(, shell_exec, passthru, system(, eval(base64 | RCE / Web Shell | Critical | Remote code execution — either probing for shells or using one. |
| /xmlrpc.php POST repeated, /wp-login.php POST flood | WordPress Brute Force | High | Credential stuffing or password guessing against WordPress. |
| nikto, sqlmap, nessus, masscan, zgrab, nuclei, dirbuster, gobuster | Scanner | High | Known vulnerability scanner user agents. |
| GET /wp-content/uploads/*.php, *.php in non-PHP directories | Web Shell Execution | Critical | PHP file in uploads directory = almost certainly a web shell. |
| High rate from single IP (100+ req/min), same URI, 400/403 floods | DDoS / Flood | High | Application-layer DoS or credential brute force. |
| HEAD / HTTP/1.0 with no User-Agent | Bot/Scanner | Medium | Minimal probes checking if server is alive. Common pre-attack recon. |
| /phpmyadmin, /pma, /myadmin, /mysql, /db/ | Admin Panel Probe | Medium | Scanning for exposed database admin interfaces. |
| /.well-known/acme-challenge (unexpected), /.git, /.svn, /.htaccess | Config/Source Leak | Medium | Trying to access version control or server config files. |
Response Status as Attack Signal
The HTTP status code returned tells you whether an attack found anything. A 200 on a suspicious request is far more dangerous than a 404.
| Status | Attack Context | Action |
|---|---|---|
| 200 | Probe succeeded — server returned content. SQLi 200 = data potentially exfiltrated. Shell request 200 = shell is live. | Investigate immediately. Treat as confirmed compromise. |
| 302 | Redirect after exploit attempt. Redirected to login after WP credential success. | Check destination URL. Successful auth redirects are suspicious if from unexpected IP. |
| 400 | Malformed probe — scanner sending garbage to fingerprint WAF/server behavior. | Low urgency alone, but spike = automated scanning underway. |
| 401/403 | Access denied — attack blocked. Flood of these = brute force in progress. | Rate limit or block the source IP. Add fail2ban rule. |
| 404 | Probing for files that don't exist. Hundreds of 404s = directory enumeration. | Review URIs for known exploit paths. Block IP if scanning pattern clear. |
| 500 | Server error triggered by request. SQLi that breaks a query may cause 500. Buffer overflow attempts. | Check error log for stack traces. May indicate partial exploitation. |
Attack Detection grep Cheatsheet
bash
LOG=/var/log/nginx/access.log # Any of the top attack signatures in one pass grep -iE "union.{0,20}select|or\s+1=1|