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
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:
Code: Select all
/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
Code: Select all
/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"
Code: Select all
/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"
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:
Code: Select all
/ip firewall address-list print where list=FailedTCP443AuthIPs
Code: Select all
/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"
Code: Select all
/ip firewall raw
add chain=prerouting src-address-list=FailedTCP443AuthIPs in-interface=ether1 action=drop comment="Drop failed auth attemps on TCP/443"
If you want to see what connections are triggering these rules, enable logging:
Code: Select all
/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"
- 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
Code: Select all
/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 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.