Table of Contents
- What is a Brute-Force Attack?
- The Impact of Brute-Force on Your Business
- Existing Solutions & Their Limitations:
- Enter Malcure’s Intrusion Prevention ModSecurity Plugin
- Key Features of Malcure’s Intrusion Prevention ModSecurity Plugin
- How Malcure’s Intrusion Prevention ModSecurity Plugin Works
- Plugin Requirements
- Downloading Malcure Intrusion Prevention Plugin for ModSecurity
- Testing the Plugin
- Monitoring Real-Time Activity
- Conclusion
What is a Brute-Force Attack?
A brute-force attack is a trial-and-error method used by attackers to gain unauthorized access to accounts, systems, or encrypted data, in this case your website. The attacker systematically attempts all possible combinations of URLs or passwords until the correct one is found to get into the website or attempt other malicious activity like uploading malware etc. This method relies on automated tools and patience, exploiting website vulnerabilities in the absence of proper security measures.
Brute-force attacks target login pages, forms, etc. exploiting predictable URLs or input fields to access restricted areas. For example, an attacker targets a website’s login page, using automated scripts to try numerous password combinations for a specific username. If successful, they gain unauthorized access to the user’s account, potentially accessing sensitive information or performing malicious actions like uploading malware, spyware, etc.
Here’s how the URLs look when an attacker tries brute-force site-scanners.
The Impact of Brute-Force on Your Business
These brute-force requests happen at hundreds to thousands of attempts per second. This means increased server load, slower response times or even denial-of-service if your server or website crashes due to CPU usage or the expanding log files filling the storage. Your server is essentially overwhelmed with the load thrown at it and succumbs resulting in bad user-experience as well as SEO-penalties.
When successful, the website is compromised; essentially a lot of spam could be posted, emailed, the website hacked or brought down. This implies unauthorised access, data-breaches, website-downtime, impact on sales, brand reputation and even legal compliance issues.
If left unaddresses, these costs and impacts will scale over time.
Existing Solutions & Their Limitations:
- Fail2Ban: Fail2Ban reacts to entries in log files. Configuration is complex and there’s a delay between the malicious activity and the banning action. Continuous log parsing can consume significant system resources, affecting server performance.
- ModSecurity DDoS Plugin: The plugin essentially works as a rate-limiter, tracking the number of requests from an IP address over a specified time and blocking the same. It blocks or throttles IPs that exceed predefined request rates and can deny requests, challenge the client, or log the activity for further analysis. However it is still easy to get by provided the request-rate is low or requesting IPs distributed. Also it doesn’t really care if the requests are genuine or not and the thresholds are blindly applied to all requests including legitimate requests.
- ModSecurity Bad-Bot Plugin: The ModSecurity Bad-Bot Plugin aims to identify and block malicious bots by matching request attributes against known bad-bot signatures. The signatures can easily be spoofed and most automated-attacks mimic real-users and real-browsers thereby rendering this mechanism redundant or ineffective.
Other Challenges & Shortcomings
- Lack of Proactive Error-Based Detection: Existing tools do not monitor specific error responses (e.g., multiple 403 or 404 errors) for specific ports especially for webapps and websites that signal malicious probing or brute-force attempts.
- Inadequate Handling of Internal Traffic: Internal services or scheduled tasks may be blocked if not explicitly exempted. This requires careful configuration to exempt trusted IPs without creating security loopholes.
- Scalability and Performance Issues: Monitoring logs and enforcing rules can consume significant resources, affecting performance and does not scale effectively in environments with high request volumes or distributed architectures.
Enter Malcure’s Intrusion Prevention ModSecurity Plugin
Given the above, the idea behind the plugin is to proactively block IPs that attempt suspicious activity on your website or webserver.
Brute-force attempts result in failed login attempts from a single IP like a 403-forbidden error or unusual traffic patterns resulting in 404-not-found error.
Since brute-force essentially results in “client error responses” in the 400-499 range, the plugin works by detecting 403 and 404 errors. 403 is the HTTP status code that translates to “Forbidden” while 404 translates to “Not Found”. With these status codes, it’s easy to track if an IP is making excessive requests resulting in too many forbidden errors and not-found errors in a specific period of time. A real user would not go on excessively making forbidden or not-found errors in a short period of time.
This means:
- There are extremely high chances that the traffic is not-human and the IP is malicious.
- Proactively block the IP to reduce server-load.
- Proactively block the IP to eliminate successful brute-force intrusion.
- Ensuring scalability of the solution with zero-expenses.
Key Features of Malcure’s Intrusion Prevention ModSecurity Plugin
- Error Monitoring and Threshold-Based Blocking: Tracks error responses (e.g., 403, 404) to identify malicious activity.
- Automatic IP Blocking: Blocks IPs that exceed the defined error threshold.
- Customizable Settings: Allows configuration of error limits, expiry periods, and whitelisting.
- Differentiation Between Internal and External IPs: Prevents false positives by excluding trusted networks.
- Integration with ModSecurity: Seamless addition to existing ModSecurity setups.
How Malcure’s Intrusion Prevention ModSecurity Plugin Works
Monitoring Error Responses
The core of the plugin’s functionality lies in its ability to monitor HTTP response codes that are indicative of malicious activities, specifically: 403 Forbidden and 404 Not Found.
Detecting Malicious Patterns
— Error Tracking: The plugin tracks the number of times an IP address triggers 403 or 404 errors within a defined time frame.
— Behavior Analysis: Frequent 403 and 404 errors from the same IP can indicate malicious scanning, probing for vulnerabilities, or attempting unauthorized access.
— Configurable Error Thresholds and Tracking Period: To tailor the plugin’s sensitivity to your specific environment, you can configure:
- Error Limit (
tx.error_limit
): The maximum number of allowed errors from an IP before it is considered malicious. The default is 5 errors which works fine in a real-world scenario. Keeping it lower like 2 will increase false positives because most browsers trigger a 404 requesting the defacto facicon.ico. - Error Tracking Period (
tx.error_counter_expire_period
): The time frame (in seconds) during which errors are counted. The default is 30 seconds and is perfect since the block remains in place as long as the IP continues to cause 404s and 403s. The block only expires once the IP behaves itself AND the block has expired. So even after blocking, the block would not expire as long as the IP continues to make rogue requests.
Automatic IP Blocking Mechanism
Once the error threshold is exceeded, the plugin takes immediate action to block the offending IP.
Block Flag Activation
The plugin sets a block flag for the IP address that has exceeded the error limit.
Denying Requests
Subsequent requests from the blocked IP are denied, preventing further interaction with the server.
Logging
All blocking actions are logged for auditing and monitoring purposes.
Handling Trusted IPs and Internal Traffic
To prevent unintended blocking of legitimate internal services and trusted users, the plugin exempts Private IPs from being blocked. This is required since WordPress makes several internal requests with WP-Cron, REST-API etc. Additionally modules like PageSpeed Module also access the website internally and may cause 404s which need to be exempted.
- Automatic Exclusion: The plugin exempts private/internal IP addresses (e.g.,
127.0.0.1
,10.x.x.x
,192.168.x.x
,172.16.*
to172.31.*
) from the intrusion prevention logic. - Avoiding False Positives: This ensures that internal processes, such as cron jobs or administrative access, are not disrupted.
Plugin Requirements
- libModSecurity must support persistent storage of variables across transactions to accurately track errors and blocking states per IP. (./configure must include “–with-lmdb” flag).
- ENABLE_DEFAULT_COLLECTIONS must be set to 1. See
coreruleset/crs-setup.conf.example
Rule900130
. - The plugin intentionally doesn’t rely on the default Anomaly Scoring Mode and ignores the SecDefaultAction to forcibly blocks malicious IPs.
- The plugin uses TIME_EPOCH to expire the counters forcibly since ModSecurity expirevar doesn’t seem to work reliably.
Downloading Malcure Intrusion Prevention Plugin for ModSecurity
The plugin is available at GitHub with a detailed readme including installation and testing steps.
Additionally this feature is built into Malcure Secure Hosting so if you are already on Malcure’s hosting, you need to do nothing.
Testing the Plugin
Testing the plugin is easy. After installing the plugin and restarting the webserver, visit any 404 page on the website. After 5 consecutive 404 errors within 30 seconds it will block the IP. If you wait it out for over 30 seconds, the unblocking is done automatically. If you continue to visit the 404 page, you remain blocked.
You can also use the following curl command for over 5 times within 30 seconds to test the plugin:
curl -I https://your-website.com/some-random-url-that-throws-404-or-403
The block is logged in the webserver’s error.log. Also you can set ModSecurity SecDebugLogLevel
to 9
to see detailed debug logs in ModSecurity’s debug-log.
Monitoring Real-Time Activity
To monitor the plugin in action, use the following command to see what’s being analysed and tracked:
tail -f /path/to/error.log | grep -a "malcure_intrusion_prevention"
Here’s what the log would look like. You’ll need to scroll to the extreme right to see the type of URLs being accessed by the malicious IP and how they are blocked.
nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/wp-admin/radio.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /wp-admin/radio.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/wp-admin/radio.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/wp-content/plugins/index.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /wp-content/plugins/index.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/wp-content/plugins/index.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/install.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/install.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/install.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/cloud.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/cloud.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/cloud.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/upfile.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/upfile.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/upfile.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/wp-blog.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/wp-blog.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/wp-blog.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/temp.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/temp.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/temp.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/wp-signup.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/wp-signup.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/wp-signup.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/moon.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/moon.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/moon.php", host: "hostname.com" nginx/error.log:nn:yyyy/mm/dd hh:mm:ss [error] nnnn#nnnn: *nnnnnn [client ip.add.re.ss] ModSecurity: Access denied with code 403 (phase 3). Matched "Operator `Ge' with parameter `1' against variable `IP:ip.add.re.ss_8f70bcb6fa12d6f9618bfc12da1177fff7a7bc57::::block_ip' (Value: `1' ) [file "/etc/nginx/.../plugins/malcure-intrusion-prevention-before.conf"] [line "ll"] [id "ID"] [rev ""] [msg "malcure_intrusion_prevention: nnnnnnn Blocking IP ip.add.re.ss after nnnn errors. ip.ec_expiry=nnnnnnnnnn, TIME_EPOCH=nnnnnnnnnn"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "host_name"] [uri "/cgi-bin/admin.php"] [unique_id "some_unique_id"] [ref ""] while reading response header from upstream, client: ip.add.re.ss, server: server.com, request: "GET /cgi-bin/admin.php HTTP/1.1", upstream: "http://ip.add.re.ss:port/cgi-bin/admin.php", host: "hostname.com"
Conclusion
To conclude, here are the highlights:
Proactive, reliable protection from brute-force attacks is a challenge. While existing solutions try to mitigate attacks from bad-bots and DDoS attacks, a better approach is to proactively monitor the IP addresses and flag the ones that indicate robotic, non-human, random activity targeting error patterns indicative of brute-force attacks.
Malcure’s Intrusion Prevention Plugin for Modsecurity provides
- Proactive defense mechanism with immediate action: Blocks malicious IPs before they can exploit vulnerabilities or compromise your system.
- Reduced server-load: By filtering out malicious requests, your server can operate more efficiently, dedicating resources to legitimate users.
- Enhanced Performance: Improves page load times and overall user experience by preventing server overload caused by brute-force attempts.
- ModSecurity Compatibility: Works effortlessly with your existing ModSecurity setup without the need for additional tools like Fail2Ban.
- Easy Installation: Simple to implement with minimal configuration, allowing you to bolster your security quickly.
- Adjustable Settings: Tailor error thresholds and tracking periods to fit your website’s specific traffic patterns and security needs.
- Automatic Blocking and Unblocking: Manages IP blocking dynamically, reducing the need for manual intervention.
- Persistent Protection: Continues to safeguard your website even as attack patterns change.
- Zero Dependencies: Operates independently within ModSecurity, reducing complexity and maintenance efforts.
- Consistent Performance: Designed to handle high volumes of traffic without compromising security or speed.
- Focused on Actual Threats: Unlike generic solutions, it specifically targets the error patterns indicative of brute-force attacks.
- Reduces False Positives: Intelligent monitoring ensures that legitimate users aren’t mistakenly blocked.