DEV Community

Chace
Chace

Posted on

How I Caught 5 Attackers Hitting a Single Website in 4 Hours — And How to Automate It

How I Caught 5 Attackers Hitting a Single Website in 4 Hours — And How to Automate It

TL;DR: I analyzed 37 lines of Nginx access log and found 27 malicious requests from 5 different attackers — including a sqlmap SQL injection campaign, a Nikto directory scan, LFI attempts targeting /etc/shadow, and reflected XSS payloads. The entire analysis took less than 1 second using an automated tool. Your web server logs are a goldmine of threat intelligence. Here's how to mine them.


The Forgotten Security Tool in Your Server

Every website generates access logs. Most people look at them once to check "is the site working?" and then never again.

Those logs are a real-time record of every attack attempt against your server.

I wanted to prove how much signal is hidden in plain text — so I built a realistic attack scenario, generated 37 log entries, and ran them through an automated web log intrusion analyzer. The results were startling.

The Setup

I simulated a day of traffic on a small business website (example.com) — a mix of legitimate visitors and several types of real-world attackers. Here's what showed up in the access log:

08:12  192.168.1.100 — Normal visitor (homepage, CSS)
08:15  192.168.1.101 — SQL injection campaign (sqlmap)
09:01  10.0.0.50     — LFI + vulnerability scanning (Nikto)
10:30  172.16.0.200  — Cross-site scripting (XSS)
11:00  45.33.32.156  — Automated scanner (Nikto, 10 paths)
12:00  192.168.1.102 — Brute force login attempts
14:22  192.168.1.103 — Normal visitor (about, contact)
16:45  192.168.1.104 — Googlebot crawling
Enter fullscreen mode Exit fullscreen mode

37 log entries. 4 hours of attacks. 5 different attackers.

What the Analyzer Found

Result Summary

Metric Value
Total log entries 37
Suspicious requests 27 (73%)
Unique attacker IPs 5
SQL injection attempts 6
LFI (Local File Inclusion) 5
XSS (Cross-Site Scripting) 3
Scanner probes 10
Brute force attempts 4

73% of traffic was malicious. In a real production environment, the ratio would be lower — but the absolute number of attacks would be far higher. A medium-traffic site receives thousands of automated attack attempts daily.

Attacker #1: The SQL Injection Campaign

IP: 192.168.1.101
Tool: sqlmap/1.7.2
Duration: 13 seconds, 6 requests
Risk: CRITICAL

This attacker used sqlmap, the most popular open-source SQL injection tool, to systematically probe two endpoints:

GET /products?id=1 UNION SELECT username,password FROM users--
→ 400 (blocked)

GET /products?id=1' OR 1=1--
→ 200 ⚠️ SUCCESS

GET /products?id=1; DROP TABLE users--
→ 400 (blocked)

GET /search?q=1' UNION ALL SELECT null,table_name
  FROM information_schema.tables--
→ 400 (blocked)

GET /search?q=1' AND sleep(5)--
→ 200 ⚠️ SUCCESS (time-based blind SQLi)

GET /search?q=1' AND benchmark(10000000,SHA1('test'))--
→ 200 ⚠️ SUCCESS
Enter fullscreen mode Exit fullscreen mode

The scary part: 3 out of 6 injection attempts returned HTTP 200. This means the server accepted these payloads and returned a successful response — the data may or may not have been exfiltrated, but the injection point is confirmed vulnerable.

This is a textbook sqlmap workflow:

  1. Test basic tautology (OR 1=1) → confirms injection
  2. Try UNION-based extraction → attempt to dump data
  3. Try time-based blind (sleep(5)) → extract data bit by bit
  4. Try destructive (DROP TABLE) → maximum damage

If you see sqlmap in your logs, assume your database is already compromised until proven otherwise.

Attacker #2: The File Inclusion Hunter

IP: 10.0.0.50
Tool: Nikto/2.1.6 + manual LFI
Duration: 11 seconds, 5 requests
Risk: HIGH

This attacker combined Nikto vulnerability scanning with targeted Local File Inclusion (LFI) attacks:

GET /page?file=../../../../etc/passwd
→ 400 (blocked)

GET /page?file=../../../etc/shadow
→ 403 (blocked)

GET /download?path=php://filter/convert.base64-encode/resource=config.php
→ 400 (blocked)

GET /view?page=/proc/self/environ
→ 403 (blocked)

GET /static/%00.php
→ 400 (blocked)
Enter fullscreen mode Exit fullscreen mode

Five different LFI techniques in 11 seconds — this is a skilled attacker who knows what they're doing:

  • Classic directory traversal (../)
  • PHP stream wrapper (php://filter)
  • Process filesystem access (/proc/self)
  • Null byte injection (%00)

Good news: all attempts were blocked (400/403). Bad news: this attacker will move on to your competitor if they can't break in.

Attacker #3: The XSS Tester

IP: 172.16.0.200
Tool: Manual (Mozilla/5.0)
Duration: 7 seconds, 3 requests
Risk: MEDIUM

GET /comment?text=<script>alert('XSS')</script>
→ 200 ⚠️

GET /profile?name=<img src=x onerror=alert(document.cookie)>
→ 200 ⚠️

GET /redirect?url=javascript:alert(1)
→ 302
Enter fullscreen mode Exit fullscreen mode

Two out of three XSS payloads returned 200. The critical question: was the payload reflected in the HTML response unescaped? If yes, any user who clicks the attacker's crafted link will execute arbitrary JavaScript — cookie theft, session hijacking, credential phishing.

Attacker #4: The Scanner

IP: 45.33.32.156
Tool: Nikto/2.1.6
Duration: 10 seconds, 10 requests
Risk: LOW-MEDIUM

This is a pure reconnaissance scan — probing 10 common sensitive paths:

/admin          /phpmyadmin    /wp-admin
/wp-login.php  /.env          /backup.sql
/config.php.bak /debug        /server-status  /robots.txt
Enter fullscreen mode Exit fullscreen mode

9 out of 10 returned 404. The scanner found nothing — but it also revealed that robots.txt exists (200), which means the site has a robots file that might leak additional paths.

Attacker #5: The Automated Script

IP: 192.168.1.102
Tool: python-requests/2.31.0
Pattern: 4 failed logins → 1 success
Risk: MEDIUM

POST /api/login → 401 (fail)
POST /api/login → 401 (fail)
POST /api/login → 401 (fail)
POST /api/login → 401 (fail)
POST /api/login → 200 (SUCCESS)
Enter fullscreen mode Exit fullscreen mode

This looks like either a brute force attack or credential stuffing (using leaked passwords from other breaches). The fact that the 5th attempt succeeded is concerning — either they guessed the password, or they had it from a data breach.

There is no rate limiting on this login endpoint. An attacker could try thousands of passwords per minute.

The Defense Report Card

Defense Status Detail
LFI protection ✅ PASS All 5 LFI attempts blocked (400/403)
Path scan protection ✅ PASS All sensitive paths return 404
SQL injection protection ❌ FAIL 3/6 payloads returned 200
XSS protection ⚠️ NEEDS VERIFICATION 2/3 payloads returned 200
Rate limiting ❌ FAIL 4 failed logins + success in 7 seconds

Grade: D+ — Good at blocking file inclusion, weak at input validation and rate limiting.

How to Automate This Analysis

I used the analyzing-web-server-logs-for-intrusion skill — a Python agent that detects SQLi, LFI, XSS, scanner activity, and brute force patterns in Nginx/Apache combined log format.

# Single command, instant results
python3 agent.py --log-file access.log --output report.json
Enter fullscreen mode Exit fullscreen mode

Performance: < 1 second for 37 entries, ~30 seconds for 100K entries, ~3 minutes for 1M entries.

What it detects:

  • 10 SQL injection patterns (UNION, OR 1=1, SLEEP, BENCHMARK, information_schema, etc.)
  • 6 LFI patterns (directory traversal, /etc/passwd, PHP streams, null bytes, etc.)
  • 4 XSS patterns (script tags, event handlers, javascript: URI, dialog functions)
  • 9 scanner tools (Nikto, sqlmap, DirBuster, Gobuster, Nmap, etc.)
  • Brute force detection with configurable threshold

What You Should Do Today

Step 1: Check your own logs (5 minutes)

# Quick grep for the most common attack patterns
grep -i "union.*select\|or 1=1\|\.\.\/\|\/etc\/passwd\|<script" /var/log/nginx/access.log
Enter fullscreen mode Exit fullscreen mode

If this returns anything, you're being attacked right now.

Step 2: Set up automated daily analysis

# Add to crontab — analyzes yesterday's logs every morning at 8 AM
0 8 * * * python3 /path/to/agent.py \
  --log-file /var/log/nginx/access.log.`date -d yesterday +%Y%m%d` \
  --output /reports/security-$(date -d yesterday +%Y%m%d).json
Enter fullscreen mode Exit fullscreen mode

Step 3: Deploy a WAF

If your manual log analysis shows attacks (and it will), you need a Web Application Firewall. Options:

  • Cloudflare WAF — free tier blocks the most common attacks
  • ModSecurity — open-source, runs on your server
  • AWS WAF — if you're on AWS

Step 4: Add rate limiting

# Add to your Nginx config
limit_req_zone $binary_remote_addr zone=login:10m rate=3/m;

location /api/login {
    limit_req zone=login burst=5;
    proxy_pass http://backend;
}
Enter fullscreen mode Exit fullscreen mode

This would have blocked Attacker #5 after the first 3 attempts.

The Bigger Picture

This analysis covered 37 log entries from a simulated small business website. A real production server generates tens of thousands of log entries per day, and the attack volume scales accordingly.

According to various industry reports:

  • The average website receives ~3,500 attack attempts per day
  • 84% of web attacks are automated (bots, scanners, credential stuffing)
  • SQL injection and XSS remain in the OWASP Top 10 for over a decade

You don't need a SOC team to defend against the automated 84%. You need a log analyzer and a WAF. Both are available for free.

Conclusion

37 log entries revealed 5 attackers using 4 different attack methodologies in a 4-hour window. The analysis took less than 1 second. The tool costs $0.

Your access logs are sitting there right now, recording every attack against your server in real time. Stop ignoring them.

Run the grep command above. If it returns results (and it will), you now know two things:

  1. You're under attack
  2. You have a free, automated way to monitor it

The only question is: how long will you wait before doing something about it?


Tools used: Web Server Log Intrusion Analyzer (analyzing-web-server-logs-for-intrusion)
Data: Simulated Nginx combined log format, June 6 2026
Analysis time: < 1 second


Want me to analyze your access logs? Share a sanitized sample and I'll run the analysis.

Top comments (0)