Brute-force login attacks on web admin panels happen constantly in the wild. What if you could catch them in real time — watching the exact moment someone hammers your login page? That's exactly what I set up here.
In this walkthrough, I'll show you how to deploy a password-protected Apache web server on Ubuntu, simulate failed login attempts from a Kali Linux machine, and write custom Snort3 rules that fire alerts the moment those attempts hit your network. You'll see both the fast log and full log format outputs — side by side.
This is a hands-on, practical setup. Every command here was actually run and verified.
Problem Statement
Default web servers expose their admin pages with zero intrusion visibility. An attacker can keep hammering /admin with wrong credentials for hours, and without a detection layer, you'd never know. The goal here is to:
- Set up a realistic web server with a password-protected
/adminendpoint - Simulate unauthorized access from a separate attacker machine
- Write Snort3 detection rules that catch those attempts in real time
Lab Environment
| Machine | OS | Role |
|---|---|---|
| Ubuntu (Server) | Ubuntu 24.x | Web server + Snort3 IDS |
| Kali Linux (Attacker) | Kali 2025/2026 | Attack simulation |
| Network | Host-only / NAT | VirtualBox |
Step 1 — Install and Verify Apache2
On the Ubuntu machine, start by installing the Apache web server and the utilities package needed for password protection:
sudo apt update
sudo apt install apache2 -y
sudo apt install apache2-utils -y
Verify Apache is running:
sudo systemctl status apache2
You should see Active: active (running) in the output.
Step 2 — Create the Admin Web Page
Apache serves files from /var/www/html/. Create a new directory for the admin area and set up a basic HTML page:
sudo mkdir /var/www/html/admin
sudo nano /var/www/html/admin/index.html
Paste this minimal HTML:
<!DOCTYPE html>
<html>
<body>
Welcome to Admin Page
</body>
</html>
Save and exit. Then remove the default Apache index page to keep things clean:
sudo rm /var/www/html/index.html
Step 3 — Password-Protect the Admin Directory
Create an admin user with a password. The -c flag creates a new password file:
sudo htpasswd -c /etc/apache2/.htpasswd adminuser
You'll be prompted to enter and confirm a password (e.g., 1234). Then set the correct permissions on the admin folder:
sudo chmod -R 755 /var/www/html/admin
Step 4 — Configure Apache to Protect the Admin Route
Edit the default Apache virtual host config:
sudo nano /etc/apache2/sites-available/000-default.conf
Add the following block inside the <VirtualHost *:80> section:
<Directory "/var/www/html/admin">
AuthType Basic
AuthName "Restricted Admin Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
Enable the headers module and restart Apache:
sudo a2enmod headers
sudo systemctl restart apache2
sudo systemctl status apache2
Step 5 — Confirm the Admin Page is Live
Check Ubuntu's IP address:
ip a
Note the IP (e.g., 192.168.1.104). Then from the Kali machine, open a browser and navigate to:
http://<UBUNTU_IP>/admin
You should see a browser login prompt asking for username and password.
Step 6 — Write the Custom Snort3 Detection Rule
Back on Ubuntu, open the local Snort rules file:
sudo nano /usr/local/etc/rules/local-rules/local.rules
Add this rule to detect HTTP traffic to port 80 that contains an Authorization header — which is what HTTP Basic Auth sends on every login attempt:
alert tcp any any -> any 80 (
msg:"Unauthorized Access to admin page";
content:"Authorization";
sid:1000011;
rev:2;
)
What this rule does:
-
alert tcp any any -> any 80— watches all TCP traffic heading to port 80 -
content:"Authorization"— matches the HTTP header browsers send during Basic Auth login attempts -
msg— the label you'll see in the alert log -
sid— unique Snort rule ID
Step 7 — Validate the Snort3 Configuration
Before running Snort live, always test the config:
snort -c /usr/local/etc/snort/snort.lua -T
Look for this at the end of the output:
Snort successfully validated the configuration (with 0 warnings).
Step 8 — Start Snort3 in Alert Fast Mode
Run Snort on the active network interface (check yours with ip a — commonly enp0s3):
sudo snort -A alert_fast -i enp0s3 -c /usr/local/etc/snort/snort.lua
Leave this running in one terminal window.
Step 9 — Simulate the Attack (More Than 3 Failed Logins)
On the Kali machine, open the browser and go to http://<UBUNTU_IP>/admin. Click Sign in with wrong credentials at least 4–5 times (all attempts should fail).
Step 10 — Generate Alerts in Full Log Format
Stop the previous Snort instance (Ctrl+C) and restart with the full log format:
sudo snort -A full -i enp0s3 -c /usr/local/etc/snort/snort.lua
Repeat the failed login attempts from Kali. The full format gives you detailed packet-level information including TCP flags, sequence numbers, TTL, and more — useful for deeper analysis.
How to Verify Everything is Working
-
Apache is up:
sudo systemctl status apache2showsactive (running) -
Admin page is protected: Visiting
http://<UBUNTU_IP>/adminshows a login popup -
Snort is detecting: After login attempts, alerts appear in the terminal with the message
"Unauthorized Access to admin page" -
Snort config is valid:
snort -c /usr/local/etc/snort/snort.lua -Treturns 0 warnings -
Full log works: Switching to
-A fullshows packet-level detail per alert
What I Learned
Working through this setup gave me a much clearer picture of how network-level detection actually works in practice. A few things stood out:
HTTP Basic Auth is surprisingly transparent to Snort. Every login attempt sends an Authorization header in cleartext (over HTTP), which makes it trivially detectable with a content-match rule. This reinforces why HTTPS is non-negotiable for anything sensitive.
Snort rules are very literal. The rule fires on every connection that contains the Authorization header — not just failed ones. To detect only failures, you'd need to correlate the server's 401 response, which requires stateful detection or threshold rules. This is a good next step to explore.
Fast vs. Full log formats serve different purposes. The fast format is great for real-time monitoring — clean, one-line-per-alert. The full format is better for post-incident forensics where you need packet details.
Configuration validation saves time. Running snort -T before going live catches rule syntax errors before they silently fail in production.
Common Mistakes
| Mistake | What Happens | Fix |
|---|---|---|
Not running sudo a2enmod headers
|
Apache fails to restart after config edit | Run sudo a2enmod headers then restart |
Wrong network interface in -i flag |
Snort captures nothing | Use ip a to confirm interface name (e.g., enp0s3) |
| Rule content keyword mismatch | No alerts fire | Check the exact string sent in HTTP headers using Wireshark |
Using sid that already exists |
Snort config validation fails | Use a unique SID (10000000+ range is safe for custom rules) |
| Forgetting to clear browser cache | Old auth cookies auto-login without triggering alerts | Clear cache or use incognito/private mode |
Not testing with snort -T first |
Errors only appear after launching live capture | Always validate config before live run |
Conclusion
This setup takes under 30 minutes and gives you a fully functional intrusion detection demo for web admin brute-force attempts. The combination of Apache's Basic Auth, a targeted Snort3 content rule, and live packet capture on the interface creates a pipeline you can actually watch in action.
From here, there's a lot to build on — threshold rules to alert only after N attempts, suppression rules to reduce noise, or integrating with a SIEM to store and query alerts. But this foundation shows exactly how the detection layer works at the network level.
If you set this up or tweak the rules, let me know how it went in the comments.


















