← News
/PLAYBOOK · 2026-07-26

Nginx Log Attack Tracing: Finding Intrusion Traces in access.log

Reconstruct an attack chain from Nginx access.log. Covers an enhanced log format, detection commands for SQL injection, path traversal, and brute force, plus a one-shot tracing script.

Scope

For security ops engineers, incident responders, and DevOps teams. Covers tracing attacks in Nginx logs to find intrusion evidence. When a server looks compromised or a site behaves abnormally, Nginx access.log is the first source to analyze. This article gives a full method from log collection to attack reconstruction, plus runnable commands.

Prerequisites

How it works

Nginx access.log records metadata for every HTTP request: source IP, request time, method, URL path, HTTP status, User-Agent, Referer, and more. Attack tracing correlates these fields to reconstruct the attacker's kill chain: recon → scan → exploit → privilege escalation → lateral movement. Common cases include WebShell access, scanner probes, brute-force attempts, SQL injection payloads, and file-inclusion attempts.

Procedure

Step 1: Configure an enhanced log format

The default combined format is missing key fields. Enable a custom format in /etc/nginx/nginx.conf:

http {
    # Enhanced log format — request body size, upstream response time, TLS version
    log_format attack_trace '$remote_addr - $remote_user [$time_local] '
                            '"$request" $status $body_bytes_sent '
                            '"$http_referer" "$http_user_agent" '
                            '$request_time $upstream_response_time '
                            '$ssl_protocol $ssl_cipher';

    access_log /var/log/nginx/access.log attack_trace;
}

Reload Nginx: nginx -t && systemctl reload nginx

Step 2: Attack-signature command cheat sheet

Copy these commands and run them on the server:

1. Find the most common attacking IPs:

# Top 20 IPs by request volume
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# IPs with the most 404s (scanner signature)
awk '$9 == 404 {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

2. Detect malicious scanning:

# Likely SQL injection requests
grep -iE "(union.*select|select.*from|or+1=1|--|%27)" /var/log/nginx/access.log | head -50

# Path traversal attempts
grep -iE "(\.\./|\.\.\|/etc/passwd|/proc/self)" /var/log/nginx/access.log | head -50

# WebShell access attempts
grep -iE "(cmd|exec|shell|eval|passthru|system)\.(php|asp|aspx|jsp)" /var/log/nginx/access.log | head -50

3. Analyze HTTP status code anomalies:

# Status code distribution
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# IPs with the most 403s (WAF blocks)
awk '$9 == 403 {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

4. Detect brute force:

# Frequent hits on the login endpoint (wp-login.php)
grep "wp-login" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

# IPs with the most POST requests (form submissions)
awk '$6 == "\"POST"' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

5. Analyze User-Agent anomalies:

# User-Agent distribution
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -30

# Known malicious tool signatures
grep -iE "(sqlmap|nikto|nmap|masscan|acunetix|nessus|openvas|python-requests|curl|wget)" \
  /var/log/nginx/access.log | awk '{print $1}' | sort -u

Step 3: Reconstruct the attack timeline

Use time as the axis:

# Attack frequency by hour
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-2 | sort | uniq -c | sort -rn

# Full request sequence for a specific IP (attack timeline)
grep "203.0.113.42" /var/log/nginx/access.log | awk '{print $4, $6, $7, $9}' | head -100

Step 4: Automated tracing script

#!/bin/bash
# /usr/local/bin/attack_trace.sh — one-shot attack tracing report
LOG="/var/log/nginx/access.log"
REPORT="/tmp/attack_report_$(date +%Y%m%d).txt"

echo "=== Attack tracing report $(date) ===" > $REPORT
echo "" >> $REPORT

echo "--- Anomalous IP Top 10 (by 404) ---" >> $REPORT
awk '$9 == 404 {print $1}' $LOG | sort | uniq -c | sort -rn | head -10 >> $REPORT

echo "" >> $REPORT
echo "--- Suspected SQL injection requests ---" >> $REPORT
grep -ciE "(union.*select|or+1=1|%27)" $LOG >> $REPORT
echo " SQL injection signature requests logged" >> $REPORT

echo "" >> $REPORT
echo "--- Scanner User-Agents ---" >> $REPORT
grep -ciE "(sqlmap|nikto|acunetix|nessus)" $LOG >> $REPORT
echo " scanner requests" >> $REPORT

echo "" >> $REPORT
echo "--- Brute-force attempt stats ---" >> $REPORT
grep -c "wp-login" $LOG >> $REPORT
echo " wp-login.php hits" >> $REPORT

echo "Report written to: $REPORT"

Add execute permission and a cron job:

chmod +x /usr/local/bin/attack_trace.sh
# Generate a report at 02:00 daily
echo "0 2 * * * root /usr/local/bin/attack_trace.sh" >> /etc/crontab

Verify the config

# 1. Confirm the Nginx log format is in effect
tail -1 /var/log/nginx/access.log | awk '{print NF}'
# Output should have 9+ fields (including ssl_protocol and other extras)

# 2. Run the one-shot tracing report
bash /usr/local/bin/attack_trace.sh
cat /tmp/attack_report_$(date +%Y%m%d).txt

# 3. Simulate an attack signature and verify detection
curl -v "http://yourdomain.com/user?id=1%27%20OR%201=1"
# Run the report again and confirm the SQL injection count increased

FAQ

Q1: The log file is huge (GB-scale). grep is too slow. What then?

Three options: (1) use ngxtop for real-time analysis; (2) deploy GoAccess for fast binary-level parsing: goaccess /var/log/nginx/access.log -o report.html; (3) ship logs to ELK or Loki for full-text indexing. For incident response only, slice the last 100k lines with tail -n 100000 first.

Q2: The attacker used a proxy/CDN. access.log only shows CDN node IPs. What then?

Enable the realip module to get the real client IP: (1) compile Nginx with --with-http_realip_module; (2) configure set_real_ip_from CDN_CIDR; real_ip_header X-Forwarded-For;; (3) if the CDN does not pass X-Forwarded-For, ask the CDN to enable XFF passthrough or read the origin IP from CDN logs.

Summary

Nginx log attack tracing is basic incident-response work. An enhanced log format, a standard command library, and automated reports cut hours of investigation to minutes. Key points: a log format that meets security needs; a standard analysis flow (anomalous IPs → anomalous status codes → anomalous request patterns → timeline reconstruction); regular tracing reports. Put these commands and scripts in the ops incident-response SOP so they become routine security checks.