Asterisk: baneando IPs “peligrosas” de por paises

Hoy he encontrado una página muy interesante donde se reportan bloques de IP que pueden ser utilizados para realizar ataques. A la hora de securizar nuestro Asterisk, tener estos bloques de IPs denegados, nos ayudará mucho a mitigar malas experiencias, como por ejemplo, fraudes en llamadas.

Mi consejo es siempre banear todas las IPs excepto aquellas que queramos utilizar, conociendo a nuestros clientes, sin embargo, en algunos casos esto no puede ser, y hay que tener nuestro Asterisk abierto a todo el mundo.

¿A todo el mundo? Bueno, a casi todo el mundo. En este post explicaré como poner en funcionamiento un script que he encontrado junto a fail2ban (herramienta que no queremos que se deshabilite).

Este script que he encontrado en http://www.lowendguide.com/ se nutre de la base de datos de http://www.ipdeny.com, donde se pueden encontrar “algunas” (muchas) IPs que no son deseadas ni deseables, y desde las cuales se realizan mucho ataques. Estas están almacenadas por países.

Script:

Este script lo que hace es simplemente conectarse a la página, bajarse un listado de IPs de los países que queramos, y proceder a añadirlas en el IPTables de nuestra máquina. Sí, efectivamente, deberemos tener instalado IPTables en nuestro servidor para poder utilizar dicho script.

Una vez creado este script, el cual tenéis pegado en el siguiente apartado, lo que haremos es crear un fichero, con permisos de ejecución en nuestra máquina e insertar el siguiente código en bash:

#!/bin/bash
### Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code ###
ISO="af cn"
 
### Set PATH ###
IPT=/sbin/iptables
WGET=/usr/bin/wget
EGREP=/bin/egrep
 
### No editing below ###
SPAMLIST="countrydrop"
ZONEROOT="/root/iptables"
DLROOT="http://www.ipdeny.com/ipblocks/data/countries"
 
cleanOldRules(){
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
$IPT -P INPUT ACCEPT
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD ACCEPT
}
 
# create a dir
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT
 
# clean old rules
cleanOldRules
 
# create a new iptables list
$IPT -N $SPAMLIST
 
for c in $ISO
do
 # local zone file
 tDB=$ZONEROOT/$c.zone
 
 # get fresh zone file
 $WGET -O $tDB $DLROOT/$c.zone
 
 # country specific log message
 SPAMDROPMSG="$c Country Drop"
 
 # get 
 BADIPS=$(egrep -v "^#|^$" $tDB)
 for ipblock in $BADIPS
 do
 $IPT -A $SPAMLIST -s $ipblock -j LOG --log-prefix "$SPAMDROPMSG"
 $IPT -A $SPAMLIST -s $ipblock -j DROP
 done
done
 
# Drop everything 
$IPT -I INPUT -j $SPAMLIST
$IPT -I OUTPUT -j $SPAMLIST
$IPT -I FORWARD -j $SPAMLIST
 
# call your other iptable script
# /path/to/other/iptables.sh
 
exit 0

Si os fijáis bien, en la segunda línea del script se puede indicar entre las comillas los países que queremos que se baneen.:

### Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code ###
ISO="af cn"

Si queremos banear las no deseadas de España, pondremos: “es” entre las comillas.

Una vez realizado esto, ejecutamos el script y a esperar. ¡Ojo! Este script siempre borra todo lo que tengáis en el IPTables, dado que ejecuta una función definida dentro del mismo llamada “cleanOldRules” la cual hace un flush de todas las reglas existentes.

Una vez realizado esto, y para mantener nuestro Fail2Ban trabajando como es de recibo, lo que os aconsejo es que procedáis a realizar un:

/etc/init.d/iptables reload

Con esto volveremos a cargar las chains de reglas del IPtables.

Depués de utilizar este script, y hacer un Word count de IPtables, pues me han aparecido un todal de 57692 reglas que banean (casi nada, y eso que comenté la parte de LOG…)

root@VOIP:/etc/asterisk# iptables -nL | wc -l
57692
root@VOIP:/etc/asterisk#

Mi consejo es que para ver que hace iptables de ahora en adelante, utilicéis un head (y a poder ser que os creéis un alias en la consola http://www.thegeekstuff.com/2010/04/unix-bash-alias-examples/). Las reglas se añaden en una cadena llamada “countrydrop”:

root@VOIP:/etc/asterisk# iptables -nL | head -n 20

Chain INPUT (policy ACCEPT)
target prot opt source destination
fail2ban-ASTERISK-UDP all -- 0.0.0.0/0 0.0.0.0/0
fail2ban-ASTERISK-TCP all -- 0.0.0.0/0 0.0.0.0/0
fail2ban-ssh tcp -- 0.0.0.0/0 0.0.0.0/0
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT)
target prot opt source destination
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain countrydrop (3 references)
target prot opt source destination
DROP all -- 27.116.56.0/22 0.0.0.0/0
DROP all -- 43.231.131.0/24 0.0.0.0/0
DROP all -- 43.249.40.0/22 0.0.0.0/0

Luego para no tener que repetir el proceso cada vez que se reinicie la máquina, haré un:

root@VOIP:/etc/asterisk# /etc/init.d/iptables-persistent save

¡Espero que este post sea de utilidad!

 

Referencias:

http://www.lowendguide.com/3/networking/block-an-entire-country-with-iptables-2/

http://www.ipdeny.com/ipblocks/data/countries

http://jonathanmanning.com/2012/01/17/how-to-iptables-firewall-configuration-for-sipvoip-on-centos-rackspace-cloud/

Trunks con TLS en Asterisk

Hoy vamos a levantar un troncal a través de TLS entre dos servidores Asterisk. Avanzo que no soy experto en PKI ni seguridad, pero voy a intentar explicarlo lo mejor posible. Añado: si alguien tiene alguna sugerencia, por favor, serán muy bien recibidas.

Fase 1: Crear claves y certificados

Primero vamos a crear una clave privada para nuestro servidor Asterisk. Esta clave que ahora generaremos y anidaremos en una carpeta de configuración dentro de /etc/asterisk/. Es un fichero que no debe de ser público, sólo este servidor debe de tener esta clave.

Es importante guardar esta clave y hacer una copia de seguridad en algún elemento externo, por si existiese alguna contingencia en el servidor.

root@rasptoni001:/etc# mkdir /etc/asterisk/keys

root@rasptoni001:/etc# cd /etc/asterisk/keys

root@rasptoni001:/etc/asterisk/keys# openssl genrsa -out serverKeyRasp.pem 1024
Generating RSA private key, 1024 bit long modulus
..........++++++
...++++++
e is 65537 (0x10001)
root@rasptoni001:/etc/asterisk/keys#

Seguidamente, creamos un certificado utilizando esta clave privada. De esta forma, verificaremos que este certificado ha sido creado por/para este servidor, y no por nadie más.

root@rasptoni001:/etc/asterisk/keys# openssl req -new -key serverKeyRasp.pem -out requestRasp.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Barcelona
Locality Name (eg, city) []:Barcelona
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ToniRTPrasp Ltd
Organizational Unit Name (eg, section) []:ToniTest
Common Name (e.g. server FQDN or YOUR name) []:netvoip.no-ip.org
Email Address []:tibanezlujan@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
root@rasptoni001:/etc/asterisk/keys#

Signamos nuestro certificado siguiendo el estandard x509. Este certificado va a caducar en un total de 3650 días (10 años). Creo que para entonces ya mi Rasp habrá muerto! =)

root@rasptoni001:/etc/asterisk/keys# openssl x509 -req -days 3650 -in requestRasp.pem -signkey serverKeyRasp.pem -out certificateRasp.pem
Signature ok
subject=/C=ES/ST=Barcelona/L=Barcelona/O=ToniRTPrasp Ltd/OU=ToniTest/CN=netvoip.no-ip.org/emailAddress=tibanezlujan@gmail.com
Getting Private key
root@rasptoni001:/etc/asterisk/keys#

¿Qué ficheros entonces quedan? Los siguientes:

serverKeyRasp.pem >> Clave privada

requestRasp.pem      >> Clave pública

certificateRasp.pem >> Certificado

El certificado no lo utilizaremos, pero como no molesta, lo dejaremos en esta carpeta. Seguidamente procederemos a crear un documento que tendrá el certificado y la clave privada, uno detrás de otro:

root@rasptoni001:/etc/asterisk/keys#cp certificateRasp.pem asterisk.netvoip.no-ip.org.pem
root@rasptoni001:/etc/asterisk/keys#cat serverKeyRasp.pem >> asterisk.netvoip.no-ip.org.pem

Resumiendo: ¿Qué hemos hecho? Hemos generado una clave privada para el servidor, luego una pública y a través de la combinación de ambas con x509 creamos el certificado para nuestro Asterisk.

Para que Asterisk funcione correctamente, y no tenga que buscar diferentes ficheros, hacemos un append de la clave privada y el certificado. Nuestros clientes no deberán de bajarse ningún archivo, ya que esto funcionará como “si fuese una página web con https”.

Fase 2: Modificar Asterisk y crear Trunks

Ahora vamos a por sip.conf, a añadir soporte para TLS e indicarle a Asterisk donde puede encontrar los archivos que hemos creado:

tlsenable=yes
tlsbindaddr=0.0.0.0:30065
tlscertfile=/etc/asterisk/keys/asterisk.netvoip.no-ip.org.pem
tlsdontverifyserver=no
tlscipher=DES-CBC3-SHA
tlsclientmethod=tlsv1

Cuidado, es importante destacar que no quiero que mi Asterisk escuche en el puerto 5060. Prefiero que lo haga en otro (en este caso 30065). Comentaros que el puerto TCP para este puerto, no deberá de estar filtrado.

Ahora creo en el servidor un peer para que funcione bajo transport tls (en archivo sip.conf también):

[trunktestingtls]
host=dynamic
type=friend
transport=tls
secret=password
disallow=alaw
allow=alaw
allow=ulaw
nat=yes
dtmfmode=rfc2833
context=dummy
canreinvite=no
qualify=yes

Una vez realizado esto, hago un reload del Asterisk y a funcionar.

Fase 3: Configurando el otro servidor Asterisk (máquina cliente)

Dentro del archivo de sip.conf del otro Asterisk (maquinacliente), simplemente añadimos las siguientes líneas:

[general]

...

tlsenable=yes

...

register => tls://trunktestingtls:password@netvoip.no-ip.org:30065

Por otro lado, creamos el troncal para poder emitir llamadas. Recordad que los Registros sólo sirven para que el Asterisk que actúa como TLS server (en este caso mi Rasp) sepa donde enviar las llamadas.

[trunktestingtls]
type=peer
transport=tls
host=netvoip.no-ip.org
port=30065
secret=password
disallow=all
allow=ulaw
allow=alaw
canreinvite=no
insecure=invite,port
nat=yes
context=from-outside

Hacemos un reload, y miramos que registre nuestro troncal:

maquinacliente*CLI> sip show registry
Host dnsmgr Username Refresh State Reg.Time 
netvoip.no-ip.org:30065 N trunktestingtls 3585 Registered Wed, 26 Nov 2014 16:25:02
1 SIP registrations.
maquinacliente*CLI>

¡Lo tenemos listo! Podemos hacer una prueba, para que cuando se marque con un prefijo 999 vaya por este troncal en TLS:

exten => _999.,1,NoOp(*TESTING TLS CALL*)
same => n,Dial(SIP/${EXTEN:3}@trunktestingtls,30)
same => n,Hangup()

Fase 4: Debug de llamadas

Para debug de llamadas, tendremos que tener en nuestro ngrep el intercambio de claves. Sin esto, no se puede descifrar el tráfico SIP con un analizador de paquetes.

En siguiente post explicaremos como abrir con ngrep y Wireshark estas capturas.

¡¡¡ Espero que os haya sido de ayuda el post!!!

Fuentes: 

http://www.voip-info.org/wiki/view/SIP+TLS (Imprescindible).

https://wiki.asterisk.org/wiki/display/AST/Secure+Calling+Tutorial

Instalando SIPCheck 2 en un honeypot

Mi profesor de dCAP (Elio Rojano) junto a otros desarrolladores, han creado SIPCheck. Este es un proyecto que me ha parecido interesante, a la hora de verificar seguridad en nuestras máquinas y conocer el estado del arte a nivel de ataques a través de un mapa muy bonico:

http://sipcheck.sinologic.net/candidates/stats

En el siguiente enlace se explica mejor cómo Elio y su equipo (refiriendome así a ellos dado que el único que he tenido el placer con quien copartir tiempo es este) han desarrollado el proyecto, y sus principales objetivos:

https://www.sinologic.net/blog/2014-06/sipcheck2-vigila-tu-asterisk-en-busca-de-atacantes.html

Por este motivo, en la RASP de casa me he instalado un pequeño Asterisk con SIP2Check. El proceso de instalación es muy muy sencillo, y lo podéis encontrar aquí:

https://github.com/sinologicnet/sipcheck

Por si os da pereza bajarlo, lo dejo aquí mismo, son tres comandos:

root@rasptoni001:/usr/src# git clone https://github.com/sinologicnet/sipcheck
root@rasptoni001:/usr/src#cd sipcheck
root@rasptoni001:/usr/src#python setup.py install

En mi caso he tenido que instalar una dependencia:

root@rasptoni001:/usr/src/sipcheck# apt-get install python-setuptools

Una vez instalado, nos registramos a través de http://sipcheck.sinologic.net/getKey y nos hacemos con una key para poder compartir IPs y tener así más reputación sobre nuestros reportes.

Dentro de esta carpeta encontraremos el etc/sipcheck.conf donde podremos configurar nuestro script.

[general]
messagefile=/var/log/asterisk/messages ; Archivo de message de Asterisk
loglevel=debug    ; Nivel de informacion en el log
useiptables=True  ; Dropear todas las ips que se detecten ataques
minticks=2        ; Intentos para que se considere un ataque
logfile=/tmp/sipcheck.log ; Archivo de log

[shared]
enable=True     ; Queremos reportar ataques a Sinologic
key=494949      ; Clave de usuario

[database]
file=/tmp/sipcheck.db ; Lugar donde almacenar la base de datos local

[ignore] ; Lista de direcciones IP y redes a ignorar
own=178.60.201.227/32,127.0.0.1/32,192.168.0.0/16,10.0.0.0/12,80.26.250.100/24,178.60.201.227/24

[gui]
enable=True
port=8081
user=admin
pass=sipcheck

Ojo! Cosas que he cambiado: la key por la cual se me generó en el paso anterior (getKey) y que Sinologic me dio, así como la lista de own (IPs en las que confio). Esto último tenía algunas que eran desconocidas para mi (las he dejado en este documento). Me las he cargado y he puesto mi rango de IPs.

Finalmente, he arrancado el servicio desde la consola, desde la misma carpeta:

./bin/sipcheck -c ./etc/sipcheck.conf

Recuerda que el “.” delante del comando indica que estamos trabajando en esta carpeta. Por otro lado, he creado un pequeño script que se ejecuta cada 5 minutos mirando que este servicio esté corriendo:

#!/bin/bash
service="sipcheck"
if (( $(ps -ef | grep -v grep | grep $service | wc -l) > 0 ))
then
    echo "$service is running!!!"
else
    /usr/src/sipcheck/bin/$service -c /usr/src/sipcheck/etc/sipcheck.conf
fi

Es necesario tener en cuenta que el nombre del script que hemos creado no puede contener el string “sipcheck”, dado que si fuese así, entonces, al hacer un “ps -ef” aparecería como que hay “algo” ejecutándose con este nombre y no se reactivaría el servicio (yo le he llamado sipAttacks.sh)

¡Lo metemos en crontab y adelante!

#
# m h dom mon dow command
* * * * * /usr/src/scripts/sipAttacks.sh