Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

miércoles, 8 de mayo de 2013

Proteger Asterisk de atacantes

Asterisk es una herramienta fantástica de software libre usada para la comunicación voz ip que funciona perfectamente en Linux. Evidentemente no todo es gratis, si queremos hacer llamadas al exterior, se necesita contratar un proveedor SIP cuyo precio es bastante asequible pero que no deja de ser un coste. Aún así, yo la considero una excelente herramienta tanto cómo aprendizaje tanto cómo herramienta profesional (centralita de llamadas hecha por uno mismo). Hace poco monté una pequeña centralita muy simple, contratando un proveedor SIP gratuito que tenía la limitación de realizar o recibir llamadas de miembros de dicho proveedor. No es algo practico en la vida real, pero sí útil. 

La centralita voz ip es muy útil, pero si no tenemos cuidado puede salirnos caro. Un recurso indispensable es la configuración de varios filtros para que nadie que nosotros no queramos pueda entrar por el router. Pero nunca está de más tener una protección extra en el servidor linux donde está instalado Asterisk. Hace poco estaba mirando los logs y grande fue mi sopresa al ver más de mil intentos de registro en mi centralita con diferentes nombres y contraseñas. Por suerte mi contraseña es sólida y no ha podido hacer nada (aunque si hubiese entrado no habría podido hacer gran cosa), pero nunca es agradable ver cómo te saturan de ataques o ver que tu servidor no es tan seguro. En mi caso solo he tenido que filtrar todo aquello que entrase por el puerto 5060 menos mi proveedor SIP, pero imaginemos que queremos algo abierto en un caso real. No es aconsejable impedir todos los accesos por el puerto(imaginemos que tenemos varios proveedores o que tenemos una centralita con constantes cambios), pero tampoco hay que dejarlo abierto para todos ya que pueden pasar cosas cómo esta. Por ello vi la necesidad de bloquear solo las ip que me intentasen invadir.


Hay varias herramientas por ahí, pero ninguna se adaptaba a mis necesidades o era defectuosa y por ello, he creado un script para sea ejecutado automáticamente (gracias a la herramienta crontab) cada cierto tiempo, en mi caso particular cada 30 minutos, y me proteja de aquello que me acosa constantemente.

En mi caso he llamado al script asterisk_filter.sh

  1. #!/bin/bash
  2. ##############################################Filtrador de Asterisk################################
  3. #Variables necesarias
  4. tabla[1]=0
  5. i=1
  6. count[1]=0
  7. aux=1
  8. rev=0
  9. marca=0
  10. #Registramos en el fichero /tmp/fichero.txt las ultimas las lineas que incluyen: NOTICE y failed for. Solo guardamos la ip y el puerto.
  11. #Esta puesto para que lea las ultimas 500 lineas
  12. tail -n 500 /var/log/asterisk/messages |grep 'failed for' |grep 'NOTICE' |cut -d "'" -f4 > /tmp/fichero.txt
  13. #Lectura del fichero
  14. while read linea;
  15. do
  16. #Inicializamos la variable auxiliar
  17.  aux=1
  18.  while [ ${aux} -le ${i} ];
  19.  do
  20.   if [ ${tabla[$aux]} !${linea} ];
  21.   then
  22. #Con esto evaluamos si lo que no coincide con el contenido ya existe en nuestra tabla
  23.    while [ ${rev} -le ${i} ];
  24.    do
  25.     rev=$((${rev} + 1))
  26.     if [ "${tabla[$rev]}" == "${linea}" ]#Si coincide hacemos una marca que dice que existe
  27.     then
  28.      marca=1
  29.     fi
  30.    done
  31.    if [ ${marca} -eq 0 ]#Si la marca dice que no existe, sumamos una entrada a la tabla
  32.    then
  33.     i=$((${i}+1))
  34.                          tabla[${i}]=${linea}
  35.    fi
  36.    else
  37.    count[${aux}]=$((${count[aux]} + 1)) #Si la cadena existe en la tabla, la sumamos al contador
  38.   fi
  39. #Reinicializamos las variables de revision
  40.   marca=0
  41.   rev=0
  42. #Sumamos uno al auxiliar
  43.   aux=$((${aux} + 1))
  44.  done #Fin de bucle de comparaciones de cadenas
  45. done < /tmp/fichero.txt #Fin de lectura de fichero
  46. aux=1 #Aprovechamos la variable auxiliar para la evaluacion final
  47. limite=180 #Limite de intentos
  48. while [ ${aux} -le $i ]#Mientras que aux sea
  49. do
  50.  marca=0 #Siempre que iniciamos el bucle la marca es 0
  51.  aux=$((${aux}+1))
  52. #Si el numero de intentos de entrada desde una ip concreta es mayor que 180, entonces la bloqueamos
  53.  if [ ${count[${aux}]} -gt ${limite} ];
  54.  then
  55. #Miramos si esta regla ya existe en nuestro iptables por para evitar duplicidades
  56. #Esto se hace para evitar que nuestro equipo se llene de reglas iguales
  57. #ya que se puede leer algo del log que ya ha sido tratado antes pero que sigue en dicho
  58. if [ -f /etc/init.d/iptables.sh ]#si existe iptables...
  59. then
  60.  echo "nada" >/dev/null
  61. else
  62.  touch /etc/init.d/iptables.sh
  63.  echo "### BEGIN INIT INFO" > /etc/init.d/iptables.sh
  64.  echo "# Provides:          iptables.sh" >> /etc/init.d/iptables.sh
  65.  echo "# Required-Start:    " >> /etc/init.d/iptables.sh
  66.  echo "# Required-Stop:     " >> /etc/init.d/iptables.sh
  67.  echo "# Should-Start:      " >> /etc/init.d/iptables.sh
  68.  echo "# Should-Stop:       " >> /etc/init.d/iptables.sh
  69.  echo "# Default-Start:     2 3 4 5" >> /etc/init.d/iptables.sh
  70.  echo "# Default-Stop:      0 1 6" >> /etc/init.d/iptables.sh
  71.  echo "# Short-Description: iptables.sh" >> /etc/init.d/iptables.sh
  72.  echo "# Description:       iptables script" >> /etc/init.d/iptables.sh
  73.  echo "### END INIT INFO" >> /etc/init.d/iptables.sh
  74.  chmod 755 /etc/init.d/iptables.sh
  75.  $(insserv iptables.sh)
  76. fi
  77.   while read line;
  78.   do
  79. ##Aqui dividimos la ip del atacante y el puerto por el que intenta acceder
  80.    ip=${tabla[${aux}]} |cut -d ":" -f1
  81.    port=${tabla[${aux}]} |cut -d ":" -f2
  82. #Esto es para que funcioe en algunas versiones antiguas que no incluyen el puerto en el log
  83.    if [ ${#ip} == 0 ];
  84.    then
  85.     ip=${tabla[${aux}]}
  86.    fi
  87.    if [ ${#port} == 0 ]
  88.    then
  89.     port=5060 #Aqui ponemos el standard sip porque suele ser el mas atacado
  90.    fi
  91. #Fin de proteccion
  92. #Comprobamos si existe la regla
  93.    if [ "${line}" == "iptables -A INPUT -s ${ip} -p tcp --dport ${port} -j DROP" ];
  94.    then
  95.     marca=1 #si existe, lo marcamos para no crear duplicidades
  96.    fi
  97.   done < /etc/init.d/iptables.sh
  98. #Si no hay marca, es decir si no existe, agregamos una regla
  99.   if [ ${marca} == 0 ];
  100.   then
  101. #Bloqueamo los protocolos, tcp y udp y agregamos las reglas a nuestro script de inicio
  102.    $(iptables -A INPUT -s ${ip} -p tcp --dport ${port} -j DROP)
  103.    $(iptables -A INPUT -s ${ip} -p udp --dport ${port} -j DROP)
  104.    echo "iptables -A INPUT -s ${ip} -p tcp --dport ${port} -j DROP" >> /etc/init.d/iptables.sh
  105.    echo "iptables -A INPUT -s ${ip} -p udp --dport ${port} -j DROP" >> /etc/init.d/iptables.sh
  106.   fi
  107.  fi
  108. done
  109. rm /tmp/fichero.txt

Esto es el funcionamiento básico del programa. Obviamente puede ser mejorado. Hay multitud de opciones pero para ello he puesto también el código, para que luego cada uno lo vaya mejorando a su gusto. Si tenéis alguna propuesta/mejora comentarla por favor.

Por cierto luego en el crontab pondríamos algo cómo esto:

*/30 * * * * root cd "ruta script" && ./asterisk_filter.sh &> /dev/null

Un saludo.

No hay comentarios :

Publicar un comentario