📑 Daftar Isi
- Introduction
- Symptoms — What Was Happening?
- Root Cause — What Went Wrong?
- 1. Distributed Automated Attack
- 2. Multi-Vector Attack
- 3. Server Started Overloading (503 Errors)
- 4. Fake User Agents & Referrers
- How to Read Apache Logs — Step by Step
- Step-by-Step Solution — Securing a cPanel + CloudLinux Server
- Step 1: Identify & Block Brute Force IPs
- Step 2: Rate Limiting in Apache
- Step 3: Configure CloudLinux Limits
- Step 4: Install & Configure ModSecurity Rules
- Step 5: Configure CloudLinux PHP Selector
- Step 6: Monitor & Verify
- Pro Tips & Warnings
- FAQ
- Q: Why did the status codes change from 200 to 500 to 503?
- Q: How do you distinguish bot attacks from real human traffic?
- Q: Are CSF IP blocks permanent?
- Q: Can CloudLinux protect against this type of attack?
- Conclusion
Introduction
One afternoon around 4 PM, I was hanging out in the NOC room having some coffee when the Telegram monitoring went off — but this wasn’t a normal error notification. It was more like an alarm: “Server load spiking drastically, response time up 300%”. I immediately opened a terminal and ran tail -f on one of our clients’ access logs.
What I saw gave me chills. Not because the errors were severe — but because the pattern was too clean. Hundreds of POST requests came from 9 different IPs within seconds, hitting different endpoints: /wp-login.php, /api/comments, /api/subscribe, /api/news. User agents were all over the place — Chrome, Firefox, Safari, even mobile browsers. Referrers from Google, Bing, Yahoo.
But it was precisely this cleanliness that was suspicious. A real human wouldn’t be sending requests to 4 different endpoints from different IPs this fast. This wasn’t a human — it was a bot designed to attack your server from multiple angles at once.
Symptoms — What Was Happening?
The Apache access log showed suspicious activity from 9 different IPs:
10.0.0.1 - - [20/Jul/2026:16:43:55 +0700] "POST /api/comments HTTP/1.1" 200 0 "https://www.bing.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.1 - - [20/Jul/2026:16:43:55 +0700] "POST /api/subscribe HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.3 - - [20/Jul/2026:16:43:56 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36"
10.0.0.4 - - [20/Jul/2026:16:43:56 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36 Edg/10.0.0.2"
10.0.0.5 - - [20/Jul/2026:16:43:56 +0700] "POST /api/comments HTTP/1.1" 500 384 "https://www.yahoo.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.5 - - [20/Jul/2026:16:43:56 +0700] "POST /api/news HTTP/1.1" 200 0 "https://www.yahoo.com/" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
10.0.0.4 - - [20/Jul/2026:16:43:57 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "-" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.5 - - [20/Jul/2026:16:43:57 +0700] "POST /api/comments HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36"
10.0.0.4 - - [20/Jul/2026:16:43:57 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.6 - - [20/Jul/2026:16:43:57 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
10.0.0.1 - - [20/Jul/2026:16:43:58 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.7 Safari/537.36"
10.0.0.3 - - [20/Jul/2026:16:43:58 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.bing.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.8 - - [20/Jul/2026:16:43:58 +0700] "POST /api/news HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15"
10.0.0.4 - - [20/Jul/2026:16:43:58 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.3 - - [20/Jul/2026:16:43:58 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
10.0.0.8 - - [20/Jul/2026:16:43:58 +0700] "POST /api/comments HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.1 - - [20/Jul/2026:16:43:59 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.yahoo.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.7 Safari/537.36"
10.0.0.5 - - [20/Jul/2026:16:43:59 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.5 - - [20/Jul/2026:16:43:59 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.bing.com/" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.4 - - [20/Jul/2026:16:43:59 +0700] "POST /api/comments HTTP/1.1" 500 384 "https://www.yahoo.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.7 Safari/537.36"
10.0.0.9 - - [20/Jul/2026:16:43:59 +0700] "POST /api/news HTTP/1.1" 500 384 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.8 - - [20/Jul/2026:16:43:59 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.yahoo.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.9 - - [20/Jul/2026:16:43:59 +0700] "POST /api/comments HTTP/1.1" 500 384 "https://www.yahoo.com/" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.1 - - [20/Jul/2026:16:43:59 +0700] "POST /api/comments HTTP/1.1" 500 384 "https://www.google.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.4 - - [20/Jul/2026:16:43:59 +0700] "POST /api/news HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.4 - - [20/Jul/2026:16:44:03 +0700] "POST /api/news HTTP/1.1" 503 807 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.4 - - [20/Jul/2026:16:44:11 +0700] "POST /api/comments HTTP/1.1" 503 807 "https://www.yahoo.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.5 - - [20/Jul/2026:16:44:13 +0700] "POST /api/news HTTP/1.1" 503 807 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36"
10.0.0.5 - - [20/Jul/2026:16:44:14 +0700] "POST /api/comments HTTP/1.1" 503 807 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.4 - - [20/Jul/2026:16:44:06 +0700] "POST /api/comments HTTP/1.1" 503 807 "https://www.google.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.7 Safari/537.36"
10.0.0.4 - - [20/Jul/2026:16:44:09 +0700] "POST /api/comments HTTP/1.1" 503 807 "-" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.4 - - [20/Jul/2026:16:44:07 +0700] "POST /api/subscribe HTTP/1.1" 503 807 "https://www.yahoo.com/" "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36"
10.0.0.5 - - [20/Jul/2026:16:44:11 +0700] "POST /api/subscribe HTTP/1.1" 503 807 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
10.0.0.6 - - [20/Jul/2026:16:44:01 +0700] "POST /api/news HTTP/1.1" 500 384 "https://www.bing.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.2 Safari/537.36 Edg/10.0.0.2"
10.0.0.5 - - [20/Jul/2026:16:44:09 +0700] "POST /api/comments HTTP/1.1" 503 807 "https://www.bing.com/" "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36"
10.0.0.4 - - [20/Jul/2026:16:44:14 +0700] "POST /api/comments HTTP/1.1" 503 807 "https://www.bing.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.0.0.7 Safari/537.36"
The symptoms:
- 9 different IPs attacking simultaneously (16:43:55 — 16:44:14, just 19 seconds)
- 4 different endpoints targeted:
/wp-login.php,/api/comments,/api/subscribe,/api/news - Status codes evolved: from
200(success) →500(internal error) →503(server overload) as the attack progressed - Diverse user agents: Chrome, Firefox, Safari, Mobile — showing bots simulating various browsers
- Fake referrers: Google, Bing, Yahoo — used to cover the attack trail
Root Cause — What Went Wrong?
1. Distributed Automated Attack
This attack used 9 different IPs simultaneously. This wasn’t ordinary brute force from a single IP — it was a distributed attack designed to:
- Avoid per-IP rate limiting (because each IP only sends a few requests)
- Overload the server from multiple sides at once
- Make detection harder (each IP looks “normal” individually)
2. Multi-Vector Attack
This attack didn’t target just one endpoint. There were 4 different targets:
/wp-login.php— WordPress login brute force/api/comments— trying to inject spam comments or find API vulnerabilities/api/subscribe— trying to exploit email subscription (could be used for email bombing)/api/news— trying to exploit the news API (could be used for injection or data theft)
This is called a multi-vector attack — an assault targeting several weak points simultaneously to maximize impact.
3. Server Started Overloading (503 Errors)
Notice the evolution of status codes in the log:
- 16:43:55 — 16:43:59: All requests return
200(success). Server still holding up - 16:43:59 — 16:44:01:
500errors (Internal Server Error) start appearing. Server struggling - 16:44:03 — 16:44:14: Mostly
503(Service Unavailable). Server overloaded
The 503 error means the server can no longer serve requests — Apache or PHP-FPM has hit its maximum process/connection limit. This is a sign that the attack successfully overwhelmed the server.
4. Fake User Agents & Referrers
The bots used diverse user agents and referrers to mimic real human traffic. But there are patterns we can detect:
- User agents too “clean” — no cookies, sessions, or extra headers that real browsers typically include
- Inconsistent referrers — the same IP switches from Google to Bing to Yahoo within seconds
- Timing too uniform — requests arrive at very consistent intervals (1-2 seconds), unlike the random patterns of real humans
How to Read Apache Logs — Step by Step
Apache Log Format
The standard Apache Combined Log Format is:
%h - - %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"
| Field | Example | Meaning |
%h |
10.0.0.1 |
Source IP address (client) |
- |
- |
Remote log name (usually empty) |
- |
- |
Remote user (empty for non-authenticated) |
%t |
[20/Jul/2026:16:43:55 +0700] |
Access time (CLF format) |
%r |
"POST /api/comments HTTP/1.1" |
Request line: Method + Path + Protocol |
%>s |
200 |
HTTP status code |
%b |
0 |
Response size in bytes |
%{Referer}i |
"https://www.google.com/" |
Source page (referrer) |
%{User-Agent}i |
"Mozilla/5.0 ..." |
Browser/client user agent |
Reading a Specific Request
Let’s break down one log line in detail:
10.0.0.3 - - [20/Jul/2026:16:43:56 +0700] "POST /wp-login.php HTTP/1.1" 200 0 "https://www.google.com/" "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36"
| Part | Value | Meaning |
| Source IP | 10.0.0.3 |
IP making the request |
| Timestamp | [20/Jul/2026:16:43:56 +0700] |
July 20, 2026, 4:43:56 PM, GMT+7 timezone |
| Method | POST |
HTTP method — sending data to the server |
| Path | /wp-login.php |
WordPress login endpoint |
| Protocol | HTTP/1.1 |
HTTP version used |
| Status | 200 |
Successful response (login form shown or attempt recorded) |
| Size | 0 |
Response body 0 bytes (redirect or empty) |
| Referrer | https://www.google.com/ |
From Google — this is fake, used to cover tracks |
| User Agent | Chrome/120... Mobile Safari/537.36 |
Android browser — also fake |
Counting Attacks from Logs
To see how bad the attack is, run the following commands:
# Count requests per IP
awk '{print $1}' /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
sort | uniq -c | sort -rn | head -n 10
# Output:
# 15423 10.0.0.1
# 12847 10.0.0.2
# 9834 10.0.0.3
# Count requests per endpoint
awk '{print $7}' /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
sort | uniq -c | sort -rn | head -n 10
# Output:
# 12432 /wp-login.php
# 8721 /api/comments
# 6543 /api/subscribe
# 5432 /api/news
# Count status code distribution
awk '{print $9}' /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
sort | uniq -c | sort -rn
# Output:
# 34521 200
# 8721 500
# 6543 503
Step-by-Step Solution — Securing a cPanel + CloudLinux Server
Modifying Apache config, firewall, or CloudLinux settings can cut off website access on the server. Before proceeding:
- Back up existing config —
cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak - Make sure you have console/SSH access — if the config is wrong, websites go down and you need direct access
- Test config before restarting — always run
apachectl configtest - Don’t permanently block internal IPs — IPs can change
Step 1: Identify & Block Brute Force IPs
First, identify the attacking IPs and block them via firewall:
# Count IPs with the most requests
awk '{print $1}' /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
sort | uniq -c | sort -rn | head -n 20 > /tmp/attacker-ips.txt
cat /tmp/attacker-ips.txt
# Block IPs with CSF (cPanel Firewall)
csf -d 10.0.0.1 "Brute force attack - multi-vector"
csf -d 10.0.0.2 "Brute force attack - multi-vector"
csf -d 10.0.0.3 "Brute force attack - multi-vector"
csf -d 10.0.0.4 "Brute force attack - multi-vector"
csf -d 10.0.0.5 "Brute force attack - multi-vector"
csf -d 10.0.0.6 "Brute force attack - multi-vector"
csf -d 10.0.0.8 "Brute force attack - multi-vector"
csf -d 10.0.0.9 "Brute force attack - multi-vector"
# Restart CSF
csf -r
Step 2: Rate Limiting in Apache
Add rate limiting directly in the Apache config. For cPanel, edit /etc/httpd/conf.d/rate-limit.conf:
# Rate limiting per IP
<IfModule mod_ratelimit.c>
<Location "/wp-login.php">
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 5
</Location>
<Location "/api/">
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 10
</Location>
</IfModule>
Or use ModSecurity (more effective for cPanel):
# Add to /etc/httpd/conf.d/mod_security.conf
SecRule REQUEST_URI "@beginsWith /wp-login.php"
"id:1001,phase:1,deny,status:429,
setenv:wp-login-rate-limit,
msg:'WP Login Rate Limit'"
Step 3: Configure CloudLinux Limits
In CloudLinux, make sure LVE limits aren’t too high to prevent one account from overloading the server:
# Check LVE limits for all users
lveinfo --period=1M
# Set limits for the affected user
lvectl set-user client-a --maxmem=512M --maxcpu=50 --maxio=50000
# Check current usage
lveinfo --period=1h --sort=memusage | head -20
Make sure MySQL/MariaDB isn’t running out of connections:
# Check active connections
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
# Check max connections
mysql -e "SHOW VARIABLES LIKE 'max_connections';"
# If too high, reduce in /etc/my.cnf
# max_connections = 100
# wait_timeout = 60
# interactive_timeout = 60
Step 4: Install & Configure ModSecurity Rules
ModSecurity is a Web Application Firewall (WAF) that can detect and block attacks at the HTTP level:
# Check if ModSecurity is installed
apachectl -M | grep security
# If not, install via EasyApache (cPanel)
# WHM → EasyApache → Apache → Include → mod_security
# Enable OWASP ModSecurity Core Rule Set
# WHM → ModSecurity → Configure → Enable OWASP CRS
OWASP CRS rules will automatically detect:
- Brute force on login pages
- SQL injection via API
- Cross-site scripting (XSS)
- Path traversal attempts
Step 5: Configure CloudLinux PHP Selector
Make sure PHP execution limits aren’t too high:
# Check PHP limits for user
cat /home/client-a/public_html/.user.ini 2>/dev/null
# Set recommended limits in /opt/cpanel/ea-php*/root/etc/php.ini
max_execution_time = 30
max_input_time = 60
memory_limit = 256M
post_max_size = 8M
upload_max_filesize = 5M
Step 6: Monitor & Verify
After all configurations are applied, monitor the logs in real time:
# Monitor ongoing attacks
tail -f /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
grep -E '429|503|rate.limit'
# Check blocked IPs
csf -g 10.0.0.1
# Check requests per minute (should be decreasing)
watch -n 5 'tail -1000 /usr/local/apache/logs/domlogs/client-a.com-ssl_log |
awk "{print $4}" | cut -d: -f1-3 | uniq -c | tail -5'
Pro Tips & Warnings
- Use CSF (ConfigServer Security & Firewall) — CSF is easier to use in cPanel than raw iptables. Install via WHM → Plugin
- Enable ModSecurity — a WAF can detect attacks that don’t show up in regular logs (SQL injection, XSS, etc.)
- Use CloudLinux CageFS — CageFS isolates each user so an attack from one account can’t affect others
- Monitor LVE statistics — CloudLinux LVE shows resource usage per user. If a user is consuming excessive resources, it could be a sign of a compromised account
- Use Imunify360 — a paid solution but very effective at protecting servers from brute force, malware, and other attacks
- Back up config before editing — always backup
/etc/httpd/conf/httpd.confand other configs
FAQ
Q: Why did the status codes change from 200 to 500 to 503?
The status code evolution shows the server overloading: 200 = server still handling requests, 500 = PHP/MySQL starting to struggle (internal errors), 503 = Apache hit its maximum process limit and is rejecting new requests. If you see lots of 503, immediately block attacker IPs because the server can no longer handle the load.
Q: How do you distinguish bot attacks from real human traffic?
Look at the patterns: (1) Bots use diverse but inconsistent user agents, (2) Referrers switch too quickly, (3) Request timing is too uniform (1-2 second intervals), (4) Requests hit many endpoints simultaneously, (5) No cookies or sessions are cached. Real humans are usually consistent in their user agent and referrer.
Q: Are CSF IP blocks permanent?
No. CSF auto-unblocks after the timeout (default 3600 seconds = 1 hour). You can check blocked IPs with csf -g [IP] and unblock manually with csf -dr [IP]. For permanent blocks, use csf -d [IP] "reason" — the IP stays blocked even after server restart.
Q: Can CloudLinux protect against this type of attack?
CloudLinux helps with LVE (Lightweight Virtual Environment) which limits resources per user. But CloudLinux doesn’t directly block attacks — it ensures one user can’t consume all server resources. To actually block attacks, you still need a firewall (CSF), WAF (ModSecurity), and rate limiting.
Conclusion
Apache logs are your first source of information when a server feels slow or errors appear. By understanding the log format — from source IP and timestamp to request method, status code, and user agent — you can spot attack patterns early and take preventive action before the server goes down completely.
From the logs I analyzed, this attack used a multi-vector approach: targeting 4 different endpoints from 9 IPs simultaneously. The bots tried to evade detection with diverse user agents and referrers. But the uniform timing pattern and status code evolution from 200 → 500 → 503 told us this was a coordinated attack that successfully overwhelmed the server.
The biggest lesson: don’t just look at a single log line. Look at the pattern. One POST request to /wp-login.php might look normal. But 9 IPs attacking 4 endpoints in 19 seconds with evolving status codes — that’s a pattern that demands immediate action.
Author: NOC Engineer — written based on experience handling multi-vector attacks on cPanel + CloudLinux production servers.