Header Ads

Filtrado por Geolocalización II

Si queremos bloquear una dirección ip o un rango en nuestro firewall, con crear una regla iptables podría ser suficiente:
iptables -I INPUT -s 1.2.3.4 -j DROP
iptables -I INPUT -s 1.2.0.0/16 -j DROP
Pero qué sucedería si queremos neutralizar un país entero con varios cientos de miles (y a veces hasta millones) de ips. Hacerlo con estas reglas de iptables no es algo muy recomendable, ya que pueden saturar el firewall.
En este punto muchos optarán por hacerlo a la inversa, o sea dejar pasar las ips que nos interesan y denegar el resto, sin embargo en redes flexibles (abiertas o semi-abiertas) sería un trabajo de tiempo completo para el operador IT, ya que tendría que validar cada ip que solicite un usuario de su red local, convirtiéndose en una auténtica locura, no viable para estos escenarios.
Pero esto no significa que nos quedemos de brazos cruzados. Hay ips relacionadas con spam, o de países de "dudosa reputación", que podemos bloquear, sin que esto implique una carga excesiva tanto a nuestro firewall como a nuestro trabajo.
sslcop
En el post Filtrado por Geolocalización expusimos varias herramientas que hacen esto posible; entre ellas el módulo Xtables-addons de Netfilter Iptables (vea el tutorial), SSL Cop de Securybydefault (para certificados CAs), GeoLocalización por Apache, entre otras, pero algunas han quedado obsoletas, como es el caso de Xtables, que funcionó bien en kernel 2.x, pero presenta problemas de compatibilidad con los nuevos kernels 3.x, y hay que compilar el kernel para instalarla, lo cual no siempre es conveniente, y SSL Cop no ha recibido actualizaciones en más de 2 años.
Existen otros proyectos con el mismo propósito, como ipfilterX, IPlist, I-blocklist, countryipblocksip2location, entre otros, en su mayoría relacionados con Netfilter, al igual que nuestro candidato de hoy, ipset, el cual utiliza reglas tipo ipdeny <country>, para el bloqueo de ips, que es tan bueno, que usted olvidará cualquier otro método de bloqueos de ips, por su velocidad y flexibilidad (Vea el benchmarks AQUI).
Antes de comenzar
Las reglas que explicaremos a continuación están basadas en Debian/Ubuntu, IPv4 y formato CIDR. Se recomienda utilizar kernel 3.1x, iptables v1.4.x o superior y ipset v6.20x. También se sugiere realizar la instalación directamente de los repositorios:
sudo apt-get install ipset
Muy Importante
Los programas y reglas que se describen en este post consumen gran cantidad de recursos de su sistema. Su uso excesivo puede llevar a su servidor al colapso. Úselos con moderación.
Ipset + ipdeny
Las reglas ipset son sencillas. Basta con echarle una mirada al tutorial y tendremos todas las opciones, entonces solo nos resta poner algunos ejemplos para automatizarlo.
Asumiendo que tenemos un script de iptables (que es lo más aconsejable) con nuestras reglas personales, entonces vamos a agregar ipset.
Primero crearemos un script que descargará la base de datos de ips geolocalizadas por países, para que la labor de bloqueo se haga directamente en nuestro terminal y/o servidor y no tener que descargar cada bloque de manera independiente, según el país que queramos restringir.
Abrimos el editor de texto y pegamos el siguiente código
#!/bin/bash
### BEGIN INIT INFO
# Provides:          geozones
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO
if [ ! -d /etc/zones ]; then mkdir -p /etc/zones; fi
wget -c --retry-connrefused -t 0 http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz && tar -C /etc/zones -xvzf all-zones.tar.gz && rm -R all-zones.tar.gz
Y lo guardamos con un nombre, en este caso elegimos geozone.sh en la carpeta /etc/init.d/. Le damos permisos de ejecución.
sudo chmod +x /etc/init.d/geozones.sh
Y lo programamos en el cron para que actualice periódicamente. Por ejemplo semanalmente.
sudo crontab -e
@weekly /etc/init.d/geozones.sh >/dev/null 2>&1
Este script crea una carpeta en /etc llamada zones (si ya existe no la crea) y descarga y descomprime la base de datos ipdeny a /etc/zones (puede ser cualquier otra carpeta).
El paso siguiente es abrir nuestro script de iptables, y antes de cualquier regla propia, agregamos el bloqueo por geolocalización. En el siguiente ejemplo, vamos bloquear a china y rusia. Si quiere saber exactamente cuál es la nomenclatura usada para cada país (para poder agregar los países a su regla de iptables), puede consultarla AQUI.
#!/bin/bash
# BLACKZONE (seleccione el pais o la ip/rango a bloquear)
# http://www.ipdeny.com/ipblocks/
ipset=/sbin/ipset
iptables=/sbin/iptables
$ipset -F
$ipset -N -! blackzone hash:net maxelem 1000000
for ip in $(cat /etc/zones/{cn,ru}.zone /etc/acl/blackips); do
$ipset -A blackzone $ip
done
$iptables -A FORWARD -p tcp -m set --match-set blackzone src -j DROP
En el ejemplo anterior utilizamos dos variables. iptables (representando a /sbin/iptables) y ipset (representando a /sbin/ipset) con el propósito de no escribir esta información y en su reemplazo poner $iptables y $ipset.
Luego hacemos un flush de las reglas almacenadas en ipset (ipset -F) y creamos nuestra lista negra para ipset, la cual llamamos blackzone (puede ser cualquier nombre). Le agregamos el parámetro -! que significa -exist, que me permite ignorar el error que se genera cuando se corre más de una vez el script y se vuelven a agregar los mismos bloques CIDR del país a bloquear.
También utilizamos hash:net que por lo general se utiliza para almacenar múltiples bloques de ips diferentes (lo contrario a hash:ip que sirve para host o ips individuales. También existen otros como hash:mac, etc). Por defecto tiene 65.536 elementos, sin embargo se recomienda elevar este valor con el parámetro maxelem. En este caso lo hemos subido a 1000000 (ya que son muchos bloques)
Luego hacemos un cat a los archivos que contienen las ips de los países a bloquear, en este caso cn.zone y ru.zone y los agregamos a la regla de ipset que creamos (blackzone). Finalmente iptables bloquea a blackzone utilizando la regla -m set --match-set blackzone src. Esta "engancha" el conjunto IP con el interruptor -m y se establece la asociación con blackzone y aplica a la ip destino src y cerramos con DROP.
Nota: Tenga en cuenta la cabecera de los script (/bin/bash vs /bin/sh). El comando cat no es capaz de leer los corchetes con cabecera /bin/sh ({cn,ru}.zone) por tanto para evitar este y otros errores de compatibilidad se recomienda /bin/bash. Para mayor información consulte el portal askubuntu.
Finalmente verificamos que la regla funcione.
sudo iptables -L
Y si queremos agregar algunos rangos de ips adicionales a nuestra lista negra de ipset blackzone, podemos hacerlo directamente por terminal. Ejemplo:
sudo ipset add blackzone 1.1.1.1/32
sudo ipset add blackzone 1.1.2.0/24
Y verificamos que se hayan agregado con el comando:
sudo ipset list
Y debería salir algo similar a lo siguiente:
Y para vaciar las ips
sudo ipset flush
Ipset + listas negras personalizadas
Podemos crear nuestras propias listas negras de ips, rangos de ips, CIDR, bien sea a partir de las existentes o desde 0. Como habíamos mencionado, en internet existen muchas de estas listas, tales como la ya mencionada ipdeny, y también countryipblocksip2location, etc. También puede incluir las utilizadas por los nodos proxys (Tor, ultrasurf, etc). Incluso en el post Firewall IV publicamos algunas de estas superlistas.
Y creamos una acl que contenga estas ips, y la ponemos en algún lugar de nuestro servidor y/o terminal y modificamos la regla de iptables descrita para que la lea.
En el siguiente ejemplo creamos la acl blackips que contiene las ips a denegar y la guardamos en algún lugar (ejemplo: /home/usuario/blackips) y la creamos también en ipset con el nombre de blackips y luego la denegamos. En este caso reemplazamos hash:net por hash:ip, que es el que se utiliza para bloquear IPs independientes.
#!/bin/bash
iptables=/sbin/iptables
ipset=/sbin/ipset
$ipset -F
$ipset -N -! blackips hash:ip maxelem 1000000
for ip in $(cat /home/usuario/blackips); do $ipset -A blackips $ip; done
$iptables -A INPUT -p tcp -m set --match-set blackips src -j DROP
hash:mac
Para poder bloquear direcciones macs con ipset, debe verificar la versión. Los repositorios de Ubuntu 14.04 traen la v6.20.1 y hash:mac solo está disponible a partir de la v6.22. Por tanto debe actualizarla, ya sea en el sitio oficial de descarga (tar -jxvf ipset-6.26.tar.bz2) o por git en el siguiente orden:
git clone git://git.netfilter.org/iptables.git
cd iptables
sudo git pull
git clone git://git.netfilter.org/libmnl.git
cd libmnl
sudo git pull
git clone git://git.netfilter.org/ipset.git
cd ipset
sudo git pull
Sin embargo es probable que le salga el mensaje "Already up-to-date". En ese caso, verifique con ipset version y si no sale el mensaje ipset v6.26, protocol version: 6, pruebe compilando (Lea el archivo README dentro de la carpeta ipset -./autogen.sh, ./configure, make, make modules, make install, make modules_install, make tests, make clean, make modules_clean-) y si tampoco funciona esto se debe a que "the ipset source supports kernels released by kernel.org. It may or may not work on distribution-specific kernel sources". Entonces no queda otro remedio que bloquear macs con una regla de iptables:
for mac in `cat /home/usuario/blackmacs`; do
 $iptables -A INPUT -m mac --mac-source $mac -j DROP
done
Donde /home/usuario/blackmacs es la ruta hacia la acl blackmacs (que puede ponerle cualquier nombre y en cualquier ruta) que contiene las direcciones macs negras.
Puede ser más específico con la regla, por ejemplo, agregando el protocolo y puerto (Ej: -p tcp --destination-port 22) o la interfaz de red (ej: -o eth1, -i eth0, etc)
Ipset + iptables (Protección externa)
También puede hacer bloqueos personalizados con iptables + ipset. Por ejemplo, supongamos que quiere monitorear algunos puertos sensibles en la entrada de su servidor (específicamente la eth que recibe el internet desde el exterior) o el acceso a algunas carpetas y archivos, con el objeto de que si alguien de afuera de su red local intenta acceder a su servidor, este lo bloquee automáticamente. Para esto podemos utilizar una regla iptables. En el siguiente ejemplo asumimos que eth0 es la que recibe internet desde el exterior y vamos a bloquear cualquier intento de acceso a los puertos 80,8080,21,22,3000,10000,5900,139,443,445,3306,20005 y de paso a las zonas esenciales del servidor como /etc/passwd, /etc/shadow y /etc/group
# Proteccion del servidor
iptables=/sbin/iptables
internet=eth0
$iptables -A INPUT -p tcp -i $internet -m multiport --dports 80,8080,21,22,3000,10000,5900,139,443,445,3306,20005 -j NFLOG --nflog-prefix 'Illegal: server access ports'
$iptables -A INPUT -p tcp -i $internet -m multiport --dports 80,8080,21,22,3000,10000,5900,139,443,445,3306,20005 -j DROP
$iptables -A INPUT -m string --string "/etc/passwd" --algo kmp  -j NFLOG --nflog-prefix 'Illegal: passwd access'
$iptables -A INPUT -m string --string "/etc/passwd" --algo kmp -j DROP
$iptables -A INPUT -m string --string "/etc/shadow" --algo kmp  -j NFLOG --nflog-prefix 'Illegal: shadow access'
$iptables -A INPUT -m string --string "/etc/shadow" --algo kmp -j DROP
$iptables -A INPUT -m string --string "/etc/group" --algo kmp  -j NFLOG --nflog-prefix 'Illegal: group access'
$iptables -A INPUT -m string --string "/etc/group" --algo kmp -j DROP
Como podemos ver, no solo hemos bloqueado estos accesos sino que los registros son manejados por NFLOG, por tanto irán a parar al log ubicado en /var/log/ulog/syslogemu.log. Un intento de acceso podría quedar reflejado de la siguiente manera:
Oct 28 14:07:38 adminred Illegal: server access ports IN=eth0 OUT= MAC=00:99:88:77:66:55:AA:BB:CC:DD:EE:FF:08:00 SRC=86.108.3.167 DST=190.99.99.99 LEN=40 TOS=00 PREC=0x00 TTL=63 ID=43260 PROTO=TCP SPT=50208 DPT=443 SEQ=1 ACK=0 WINDOW=0 RST URGP=0 MARK=0
Nomenclatura del log:
Oct 28 14:07:38 (fecha y hora del registro del log) 
adminred (nombre del servidor) 
Illegal: server access ports (mensaje de registro que proporciona la regla iptables) 
IN=eth0 (interface de red conectada directamente al modem o proveedor de internet) 
MAC=00:99:88:77:66:55 (dirección mac de la DST, o sea interface eth0 IP 190.99.99.99) 
AA:BB:CC:DD:EE:FF (dirección mac del modem o proveedor de internet) 
08:00 (significa que es TCP) 
SRC=86.108.3.167 (IP de origen - de donde intentan acceder ilegalmente a nuestro servidor)
DST=190.99.99.99 (ip destino IN=eth0) 
SPT=50208 (puerto de origen) 
DPT=443 (puerto de destino)
Nota: las peticiones ff:ff:ff:ff:ff:ff son de broadcast
En este caso específico sabemos que la ip 86.108.3.167 (esta ip es real y fue utilizada en un ataque contra un servidor en latinoamérica) es el origen del ataque, por tanto simplemente la bloqueamos con el siguiente script bash:
#!/bin/bash
cat /var/log/ulog/syslogemu.log | grep -Eo 'SRC=[0-9.]+' | sed 's:SRC=::' >> /home/usuario/blackips
sort -o /home/usuario/blackips -u /home/usuario/blackips -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n /home/usuario/blackips
cat /dev/null > /var/log/ulog/syslogemu.log
O puede utilizar sed en reemplazo de grep
cat /var/log/ulog/syslogemu.log | sed 's/.*SRC=\([0-9.]\+\).*/\1/' infile | sort -u > /home/usuario/blackips
Este script lee el log, extrae las ips de origen (SRC) y la envía a la ACL de ipset explicada anteriormente (/home/usuario/blackips pero puede ser cualquier ruta) y finalmente limpia el log.
Podemos automatizar esta labor, guardando el script en init.d, le damos permisos chmod +x y lo programamos en el cron para que lea regularmente el log y bloquee estas ips.
Otros comandos de ipset
# Listar ipset
sudo ipset list
# Eliminar nuestra regla de ipset (blackzone)
sudo ipset destroy blackzone
# Eliminar todas
sudo ipset destroy
# Antes de eliminar hay que borrar las reglas de iptables que las estáun usando
iptables -F
iptables -X
Ipset + iblocklist y otras listas negras de ips
Otro método de bloqueo con ipset es el descrito por el portal xmodulo.com, el cual utiliza otra base de datos llamada iblocklist. También puede consultar el post Protegiendo nuestro servidor (algo mas que iptables), donde encontrará muchos enlaces a listas de ips de países.
Errores frecuentes
ipset v6.20.1: Syntax error: cannot resolve 'xxx.com' to an IPv4 address: Name or service not known
Syntax error: cannot parse xxx.com: resolving to IPv4 address failed
Si se utilizan en lugar de direcciones IP o números de servicio, nombres de host o nombres de servicios con guión en el nombre, el nombre de host o nombre de servicio deben ir entre corchetes. Ejemplo: ipset add foo [test-hostname],[ftp-data]
ipset v6.20.1: Syntax error: Second element is missing from 1.160.0.0/12
Este error es frecuente en compilaciones y se refiere al rango CIDR no válido, versiones incompatibles y otras situaciones. Puede consultar el siguiente enlace
Aclaratoria
Es necesario esclarecer que con ipset o cualquier otro método, no se garantiza el bloqueo completo a un país, y tampoco lo consideramos prudente, ya que las ips cambian de mano constantemente y puede que una ip sea hoy de China y mañana de Francia. Es por eso que recomendamos la lectura de los logs y bloquear con ipset solamente aquellas ips que nos afecten directamente (y no necesariamente un país entero). Esto agilizaría mucho nuestro firewall.
NtopNG
Para acompañar a ipset, que mejor que un aplicativo web de geolocalización. En el post Network Monitor, vimos algunas herramientas que monitorean nuestra red local, y entre ellas NtopNG, que incluye esta posibilidad. Lo instalamos...
sudo add-apt-repository ppa:cavedon/ntop --yes
sudo apt-get update && sudo apt-get -y --force-yes -f install libpcap-dev libglib2.0-dev libgeoip-dev redis-server libxml2-dev libnl1 && sudo apt-get -y --force-yes -f install ntopng ntopng-data
sudo service redis-server restart && sudo service ntopng restart
Y creamos un script, al cual llamaremos updategeoip.sh para descargar y mantener las bases de datos geoip de Ntopng actualizadas.
#!/bin/bash
### BEGIN INIT INFO
# Provides:          Geoip update
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# # Functions
# ==========================================================================

#uso() {
echo -n "`basename $0`, v"
echo -n $version | awk '{printf $3}'
echo ". By Luis Palacios"
echo "Actualizado por Maravento.com"
echo "Uso: updategeoip.sh [-h]"
echo " -h help"
echo " "
echo " "
exit -1 # Salimos
}

# Analisis de las opciones
while getopts "h" Option
do
case $Option in

# EOM, no comments
h ) uso;;

# Resto de argumentos, error.
* ) uso;;

esac
done
# ================================================================
#
echo
#
cd /usr/share/ntopng/httpdocs/geoip
wget -nc http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip -f GeoLiteCity.dat.gz
#
cd /usr/share/ntopng/httpdocs/geoip
wget -nc http://geolite.maxmind.com/download/geoip/database/GeoLiteCityv6-beta/GeoLiteCityv6.dat.gz
gunzip -f GeoLiteCityv6.dat.gz
#
cd /usr/share/ntopng/httpdocs/geoip
wget -nc http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
gunzip -f GeoIPASNum.dat.gz
#
cd /usr/share/ntopng/httpdocs/geoip
wget -nc http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNumv6.dat.gz
gunzip -f GeoIPASNumv6.dat.gz
Finalmente accedemos a http://localhost:3000 con el usuario admin y contraseña admin (la podemos cambiar en las preferencias)...
Y vamos a la geolocalización y ahí podemos detectar los países que tienen tráfico con nuestra red local y eventualmente bloquearlos con iptables.
Imagen cortesía de Blog.elhacker.net
Con la tecnología de Blogger.