errorlogs.net /Web Attacks Overview
attack patterns access.log
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 / UAAttack TypeSeverityWhat It Means
UNION SELECT, OR 1=1, --+, %27, information_schemaSQL InjectionCriticalAutomated or manual SQLi probe. 200 response = possible data leak.
<script>, onerror=, javascript:, alert(, %3CscriptXSSCriticalCross-site scripting payload injection attempt.
../../../, %2e%2e%2f, ..%5c, %252e%252ePath TraversalCriticalAttempting to read files outside web root (e.g. /etc/passwd).
/etc/passwd, /etc/shadow, /proc/self, wp-config.php, .env, .git/configSensitive File AccessCriticalDirect attempt to read credentials, config files, or source code.
cmd=, exec(, shell_exec, passthru, system(, eval(base64RCE / Web ShellCriticalRemote code execution — either probing for shells or using one.
/xmlrpc.php POST repeated, /wp-login.php POST floodWordPress Brute ForceHighCredential stuffing or password guessing against WordPress.
nikto, sqlmap, nessus, masscan, zgrab, nuclei, dirbuster, gobusterScannerHighKnown vulnerability scanner user agents.
GET /wp-content/uploads/*.php, *.php in non-PHP directoriesWeb Shell ExecutionCriticalPHP file in uploads directory = almost certainly a web shell.
High rate from single IP (100+ req/min), same URI, 400/403 floodsDDoS / FloodHighApplication-layer DoS or credential brute force.
HEAD / HTTP/1.0 with no User-AgentBot/ScannerMediumMinimal probes checking if server is alive. Common pre-attack recon.
/phpmyadmin, /pma, /myadmin, /mysql, /db/Admin Panel ProbeMediumScanning for exposed database admin interfaces.
/.well-known/acme-challenge (unexpected), /.git, /.svn, /.htaccessConfig/Source LeakMediumTrying 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.

StatusAttack ContextAction
200Probe succeeded — server returned content. SQLi 200 = data potentially exfiltrated. Shell request 200 = shell is live.Investigate immediately. Treat as confirmed compromise.
302Redirect after exploit attempt. Redirected to login after WP credential success.Check destination URL. Successful auth redirects are suspicious if from unexpected IP.
400Malformed probe — scanner sending garbage to fingerprint WAF/server behavior.Low urgency alone, but spike = automated scanning underway.
401/403Access denied — attack blocked. Flood of these = brute force in progress.Rate limit or block the source IP. Add fail2ban rule.
404Probing for files that don't exist. Hundreds of 404s = directory enumeration.Review URIs for known exploit paths. Block IP if scanning pattern clear.
500Server 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| $LOG

# Requests that got a 200 AND look suspicious (the dangerous ones)
awk '$9=="200"' $LOG | grep -iE "union|select|passwd|\.env|wp-config|cmd=|shell"

# Known scanner user agents
grep -iE "sqlmap|nikto|nessus|masscan|zgrab|nuclei|dirbuster|gobuster|acunetix|burpsuite|wfuzz|hydra" $LOG

# Path traversal attempts
grep -E "(\.\./|%2e%2e%2f|%252e%252e|\.\.\\\\)" $LOG

# PHP files in upload directories (web shell execution)
grep -iE "/uploads/.*\.php|/files/.*\.php|/tmp/.*\.php" $LOG

# High-volume IPs (potential DDoS — top 20 by request count)
awk '{print $1}' $LOG | sort | uniq -c | sort -rn | head -20

# Requests per minute from one IP (replace IP)
grep "185.220.101.45" $LOG | awk '{print $4}' | cut -d: -f1-3 | sort | uniq -c
⚠ Key Principle
A 404 response to a suspicious URL means the attack failed — the file wasn't there. A 200 response to the same URL means something was returned. Always filter for $9 == "200" alongside attack signatures to prioritise what to investigate first.
Immediate Response Actions
bash
# Block an attacker IP immediately (pick one)
ufw deny from 185.220.101.45           # Ubuntu/Debian
iptables -I INPUT -s 185.220.101.45 -j DROP   # any Linux
csf -d 185.220.101.45                   # ConfigServer Firewall (cPanel)

# Block entire /24 subnet (common for Tor exit / VPN ranges)
ufw deny from 185.220.101.0/24

# Find all IPs that got a 200 on suspicious URIs today
grep "$(date +%d/%b/%Y)" $LOG | awk '$9=="200"' | grep -iE "union|shell|passwd|cmd=" | awk '{print $1}' | sort -u

# Check if any PHP shells are currently accessible
find /var/www -name "*.php" -newer /var/www/html/index.php -ls 2>/dev/null
find /var/www/html/wp-content/uploads -name "*.php" 2>/dev/null