Community discussions

MikroTik App
 
TheirFruits
just joined
Topic Author
Posts: 1
Joined: Fri Mar 21, 2025 3:50 pm
Location: Ohio, United States

Logging and Blocking IPs Based on Failed Authentication Attempts

Fri Mar 21, 2025 6:14 pm

Motivation

I thought I would share this simple method of monitoring a number of conditions, that could reasonably be considered nefarious activity of a bad actor, trying to gain access to a resource in your network, such as an HTTP(S) server. Trying to find a reputable list of IPs associated with particular countries can be a great challenge, and even then, maybe you don't want to consider a whole country bad, but maybe you want to rather watch for certain conditions that you decide to be undesirable, and dynamically block those connections for a limited time, or even permanently. I am using this method with time limits, since I do not want to overburden my router with excessive address list entries, and especially since most of these types of attacks are distributed. It can be a bit like plugging leaks in a pond dam one by one, where it seems like the battle will never end, rather than taking a step back and addressing the problem in a more reasonable way.

Concept

Monitor connections in the pre-routing chain for conditions consistent with failed authentication attempts ranging from a single failure up to what could be considered brute-force, record the source IP of the connection to a dynamic address list with some time limit, and position a firewall rule to block the traffic sourcing from the IP in question. While the IP is present in the address list, determined by the set time limit, connection attempts sourcing from it will be dropped. After the time limit expires, the IP will be automatically removed from the address list, and the connection will again be allowed. If an attempt is made from that IP again and one of the failed authentication conditions is observed, the IP will again be dynamically added to the address list and connection attempts from that IP will endure the configured time limit wherein they will be dropped. Rinse and repeat.

Example Topology

Image

We have two bad actors who have discovered our HTTPS server answering requests on TCP port 443 at public address 1.1.3.2, which is assigned to the WAN interface of our router (ether1). Our DST-NAT rule is what enables requests destined to TCP port 443 at 1.1.3.2 to be forwarded on to our internal server 192.168.1.2:
/ip firewall nat
add chain=dstnat dst-address=<your-public-ip> protocol=tcp dst-port=443 action=dst-nat to-addresses=192.168.1.2 to-ports=443 in-interface=ether1
The bad actors at 1.1.1.2 and 1.1.2.2 have made connections through our router, to our internal server, by way of our configured DST-NAT rule, and have observed our web application that requires some authentication to be able to use it. They attempt authentication based on guesses, which are incorrect, authentication fails and the web server resets the TCP connection, resulting in a TCP RST packet being sent. Observing these in prerouting, we'll log them and add the source IPs to an address list named FailedTCP443AuthIPs (adjust to your liking) with a time limit of 7 days:
/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 tcp-flags=rst in-interface=ether1 action=add-src-to-address-list address-list=FailedTCP443AuthIPs address-list-timeout=7d comment="Log TCP RST on Port 443"
Additionally, we will watch for excessive connection attempts with multiple SYN packets from a single source IP, which could potentially indicate a brute-force attack, and log these to a separate address list called "SYNbursts" (adjust name to your liking) with a time limit of 1 minute, since this is behavior we expect to see over a short term in bursts. If we see our predicted behavior within that 1 minute span, we will add the source IP of the connection to our FailedTCP443AuthIPs address list:
/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 tcp-flags=syn in-interface=ether1 action=add-src-to-address-list address-list=SYNbursts address-list-timeout=1m comment="Track SYNs on TCP/443"
/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 src-address-list=SYNbursts limit=10,32 in-interface=ether1 action=add-src-to-address-list address-list=FailedTCP443AuthIPs address-list-timeout=7d comment="Log excessive SYNs"
First rule: Adds IPs sending SYN to SYNbursts list and resets every minute, dropping the source IP from the SYNbursts address list if the behavior does not continue.

Second rule: If an IP exceeds 10 connections (limit=10,32), it’s added to the FailedTCP443AuthIPs address list. Adjust the connection count based on your server’s normal traffic (for example, you may opt to go higher if it is a busy server).

Check the address list to see what IPs are getting flagged and added to our FailedTCP443AuthIPs address list:
/ip firewall address-list print where list=FailedTCP443AuthIPs
You will see the IPs, timestamps and timeouts. We will implement the following rule in prerouting to block traffic destined to TCP port 443, sourcing from IPs indexed in our FailedTCP443AuthIPs list:
/ip firewall raw
add chain=prerouting src-address-list=FailedTCP443AuthIPs protocol=tcp dst-port=443 in-interface=ether1 action=drop comment="Drop failed auth attemps on TCP/443"
You may rather consider that, if someone from a remote IP is trying to gain access to your application maliciously, that is better to just block ALL traffic from them, regardless of protocol and port:
/ip firewall raw
add chain=prerouting src-address-list=FailedTCP443AuthIPs in-interface=ether1 action=drop comment="Drop failed auth attemps on TCP/443"
We have set the time limit on the address list to 7 days, perhaps so if they repent of their malicious behavior during or after that period by going through the proper channels and requesting access to our application, they are given grace and again allowed to access it.

If you want to see what connections are triggering these rules, enable logging:
/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 tcp-flags=rst in-interface=ether1 action=log log-prefix="TCP-RST-443" comment="Debug TCP RST"
Why This Approach?

- Raw Table: Using raw rather than filter skips connection tracking for RST/SYN rules, saving on CPU utilization.

- Address Lists: Efficient for tracking IPs without overburdening the firewall with per-IP rules.

- Timeouts: Prevent the list from growing indefinitely. I consider 7 days reasonable, but adjust based on your own traffic volume and use-case.

Limitations

- No True Authentication Visibility: RouterOS can’t see HTTPS authentication failures, as they are encrypted. This method identifies TCP-level signs of trouble; RSTs, floods—not application layer failures like bad passwords. If your server logs authentication failures (e.g., in IIS, Apache, NGINX, etc), you’d need a script pulling those logs and feeding IPs to RouterOS via API.

- False Positives: RSTs might come from legitimate clients with network hiccups. Tune connection limits and timeouts to reduce false positives.

- Performance: On a busy WAN, hundreds or thousands of entries in the FailedTCP443AuthIPs address list could slow things, depending on the specifications of your hardware. Monitor CPU utilization (/system resource monitor) and prune as you see fit.

Full Configuration in Summary
/ip firewall nat
add chain=dstnat dst-address=<your-public-ip> protocol=tcp dst-port=443 action=dst-nat to-addresses=192.168.1.2 to-ports=443 in-interface=ether1

/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 tcp-flags=rst in-interface=ether1 action=add-src-to-address-list address-list=FailedTCP443AuthIPs address-list-timeout=7d comment="Log TCP RST on Port 443"

/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 tcp-flags=syn in-interface=ether1 action=add-src-to-address-list address-list=SYNbursts address-list-timeout=1m comment="Track SYNs on TCP/443"

/ip firewall raw
add chain=prerouting protocol=tcp dst-port=443 src-address-list=SYNbursts limit=10,32 in-interface=ether1 action=add-src-to-address-list address-list=FailedTCP443AuthIPs address-list-timeout=7d comment="Log excessive SYNs"

/ip firewall raw
add chain=prerouting src-address-list=FailedTCP443AuthIPs protocol=tcp dst-port=443 in-interface=ether1 action=drop comment="Drop failed auth attemps on TCP/443"
Test and Tune Your Setup

- Test by simulating failed authentications or RSTs from a remote IP.

- Check "/ip firewall address-list print" for IPs.

- Adjust connection limit or timeouts based on legitimate traffic patterns—too tight, and you’ll punish the good guys; too loose, and attackers sneak through.
You do not have the required permissions to view the files attached to this post.