Los ataques de fuerza bruta son muy comunes en Internet, suele tratarse de scripts automáticos que intentan realizar login en un servicio determinado intentando el máximo número de logins/minuto posibles, estos logins pueden llegar a provocar una degradación del servico o incluso una denegación de servicio. En este artÃculo veremos como prevenir este tipo de ataques ya sea en un servidor final o protegiendo una red entera detrás de PF, para ello utilizaremos las overload tables.
Primero preparamos el escenario de testing, en mi caso se trata de un Nginx con una autenticación usuario/password básica.
Instalamos Nginx:
Generamos el ficheros de credenciales:
openssl passwd -apr1 >> /usr/local/etc/nginx/.htpasswd
Configuramos Nginx para que pida credenciales de acceso:
...
location / {
auth_basic "Login Required";
auth_basic_user_file /usr/local/etc/nginx/.htpasswd;
root /usr/local/www/nginx;
index index.html index.htm;
}
Habilitamos y arrancamos el servicio:
service nginx restart
Accedemos para comprobar que todo funciona con normalidad:
http://192.168.69.55
En el host atacante instalamos
Hydra
, un conocido crackeador online.
Lanzamos el ataque:
[STATUS] 8615.00 tries/min, 8615 tries in 00:01h, 14335784 to do in 27:45h, 16 active
En el servidor/router configuramos la 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)
Los parámetros de la overloaded table son:
- 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).
El script completo quedarÃa del siguiente modo:
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
Aplicamos las reglas:
Veremos que Hydra empieza a dar errores de conexión:
[ERROR] Child with pid 55961 terminating, can not connect
Si consultamos el contenido de la tabla bruteforce veremos la ip del atacante:
192.168.69.4
En la mayorÃa de los casos solo necesitamos un baneo temporal, por lo tanto podemos crontabear un entrada como esta para hacer limpieza de las tablas eliminando las entradas que no han sido referenciadas en los últimos X segundos.
Crontab:
00 11 * * * pfctl -t bruteforce -T expire 86400
Uno de los ataques mas comunes es sobre SSH, con PF podrÃamos impedir dichos ataques del mismo modo que hemos hecho para el puerto 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)