This page looks best with JavaScript enabled

Preventing brute force attacks using PF

 ·  πŸŽƒ kr0m

Brute force attacks are very common on the Internet. They usually involve automatic scripts that attempt to log in to a specific service by trying the maximum number of logins per minute possible. These logins can cause degradation of the service or even a denial of service. In this article, we will see how to prevent this type of attack, either on a final server or by protecting an entire network behind PF, using overload tables.

First, we prepare the testing scenario. In my case, it is an Nginx with basic user/password authentication.

We install Nginx:

pkg install nginx

We generate the credentials file:

echo -n 'kr0m:' >> /usr/local/etc/nginx/.htpasswd
openssl passwd -apr1 >> /usr/local/etc/nginx/.htpasswd

We configure Nginx to request access credentials:

vi /usr/local/etc/nginx/nginx.conf

...
        location / {
            auth_basic "Login Required";
            auth_basic_user_file /usr/local/etc/nginx/.htpasswd;
            root   /usr/local/www/nginx;
            index  index.html index.htm;
        }

We enable and start the service:

sysrc nginx_enable=YES
service nginx restart

We access to check that everything works normally:
http://192.168.69.55


On the attacking host, we install Hydra , a well-known online cracker.

pkg install hydra

We launch the attack:

hydra -l kr0m -P wordlists/rockyou.txt 192.168.69.55 http-get

[STATUS] 8615.00 tries/min, 8615 tries in 00:01h, 14335784 to do in 27:45h, 16 active

On the server/router, we configure the overloaded table:

table <bruteforce> persist
block quick from <bruteforce>
pass quick proto tcp from any to any port http flags S/SA keep state (max-src-conn 15, max-src-conn-rate 5/3, overload <bruteforce> flush global)

The parameters of the overloaded table are:

  • max-src-conn is the number of simultaneous connections allowed from one host.
  • max-src-conn-rate is the rate of new connections allowed from any single host (15) per number of seconds (5).
  • overload means that any host which exceeds these limits gets its address added to the bruteforce table. The ruleset blocks all traffic from addresses in the bruteforce table.
  • Finally, flush global says that when a host reaches the limit, that all (global) of that host’s connections will be terminated (flush).

The complete script would look like this:

vi /etc/pf.conf

ext_if = "em0"
table <bruteforce> persist

set block-policy return
scrub in on $ext_if all fragment reassemble
set skip on lo

antispoof for $ext_if inet

block log all
block quick from <bruteforce>
pass quick proto tcp from any to any port http flags S/SA keep state (max-src-conn 15, max-src-conn-rate 5/3, overload <bruteforce> flush global)
pass out
pass in proto tcp to any port 22
pass in proto tcp to any port 80

Apply the rules:

pfctl -f /etc/pf.conf


We will see that Hydra starts giving connection errors:

[ERROR] Child with pid 55961 terminating, can not connect

If we check the content of the bruteforce table, we will see the attacker’s IP:

pfctl -t bruteforce -T show

   192.168.69.4

In most cases, we only need a temporary ban, so we can schedule a crontab entry like this to clean up the tables by removing entries that have not been referenced in the last X seconds.
Crontab:

crontab -e

00 11 * * * pfctl -t bruteforce -T expire 86400

One of the most common attacks is on SSH, with PF we could prevent such attacks in the same way we did for port 80:

pass quick proto tcp from any to any port ssh flags S/SA keep state (max-src-conn 15, max-src-conn-rate 5/3, overload <bruteforce> flush global)
If you liked the article, you can treat me to a RedBull here