SIPCheck: Vigila quien intenta registrarse en tu Asterisk
Hace unas semanas creamos una pagina web desde la que podíamos comprobar si nuestro Asterisk era vulnerable a INVITES externos sin autenticación. Por la cantidad de emails que recibí tanto de usuarios de España como los de otros países, ví que una gran cantidad de usuarios admitían paquetes INVITES sin autenticación.
Por lo general, esto no es en absoluto erróneo, entra dentro de la filosofía de la VoIP que podamos admitir llamadas anónimas desde otros sistemas para poder ponerlas en contacto con usuarios que tengamos registrados en nuestro Asterisk, pero conociendo la cantidad de usuarios que permiten esto (apenas un 5%), el resto se podría considerar que utilizan un interfaz web como FreePBX que configura por defecto el famoso parámetro ‘allowguest=yes’ en lugar de rechazarlo.
Asterisk 1.4 y 1.6 también configuran por defecto este parámetro, pero por supuesto es responsabilidad de cada uno conocer el significado de estos parámetros y actuar en consecuencia.
Durante una charla/debate/brainstorming que tuvimos en el último curso de Asterisk Advanced en Bilbao, aparecieron algunas ideas bastante interesantes y que nos gustaría compartir desde aquí:
- Utilizar la aplicación ‘Authenticate’ con un código PIN conocidos por todos los usuarios y que se ejecute antes de hacer una llamada internacional:
Por ejemplo, algo como esto:
exten => _00X.,1,NoOp(Calling International number: ${EXTEN})
exten => _00X.,n,Authenticate(0173)
exten => _00X.,n,Dial(SIP/${EXTEN}@InterProvider)
Esto ya haría que el usuario llamante que envía dicha llamada, necesite conocer nuestro código de autentificación (0173) para poder realizar dicha llamada. Este código deberán conocerlo todos los usuarios y, aunque retrase un poco el establecimiento de la llamada por tener que marcar 4 números más, seguro que el hecho ampliar dicha seguridad es algo que merece la pena hacer.
- Evitar el acceso externo del 5060 mediante el propio firewall de Linux:
Este, sin duda es el que menos me gusta, ya que es muy interesante poder recibir llamadas a nuestros usuarios sin necesidad de tener que llamarles vía red telefónica.
Es decir, si yo desde mi softphone llamo a: SIP:jackoman@asterisk.jackoman.com suene correctamente la extensión de mi amigo sin tener que llamarlo al móvil o a su número fijo.
No obstante, si cierro el puerto 5060/UDP vía firewall, jamás podría hacerlo algo que rompería con toda la filosofía de lo que es la VoIP y una de sus principales ventajas. 🙁
- Una configuración adecuada del dialplan:
Generalmente este es el principal error, las llamadas entrantes sin autentificar en el SIP.conf son dirigidas al contexto ‘default’ del extensions.conf.
Si el extensions.conf NO lo hemos configurado como nos han enseñado, podríamos llegar a tener algo como esto:
[default]
exten=>s,1,NoOp(Llamadas desde el exterior)
exten=>s,n,Dial(SIP/100,20)
exten=>s,n,VoiceMail(100,u)include=>salientes ;; <<<< MUY MAL! Añadimos el contexto ‘salientes’ dentro del ‘default’
…[salientes]
exten=>_1XX,1,Dial(SIP/${EXTEN})
exten=>_9X.,1,Dial(DAHDI/g1/${EXTEN})
exten=>_00X.,1,Dial(SIP/${EXTEN}) ;; <<<<< Esto es lo que hará que puedan hacer llamadas desde fuera.
De esta manera, nuestro sistema estará completamente configurado para que cualquier persona pueda llamar a costa nuestra a donde quiera. 🙁
Ante esto, un consejo… NUNCA utilizar ‘includes’ si no sabemos exactamente qué estamos haciendo.
Existen muchas otras soluciones para hacer que nuestra seguridad se refuerce un poco, aunque existe un problema mayor:
Los usuarios maliciosos incluso se autentifican y registran en nuestro sistema para hacerse pasar por una extensión con permisos y poder hacer llamadas como un usuarios normal y corriente.
Ante esto ¿qué podemos hacer?. Pues está claro que lo primero es mejorar la seguridad básica:
- La típica extensión 100 con contraseña 100, es tan vulnerable como no poner ninguna contraseña, por lo que debemos cambiarla a algo más robusto: algo como eLnsAaLiyÑ100. (la ñ y la ç son letras muy útiles para las claves)
- Cuando estos usuarios intentan registrarse desde nuestras propias cuentas, utilizan un sistema de ‘fuerza bruta‘ para buscar las contraseñas, así que de poco nos servirá algo como esto: Usuario 100, contraseña 100100, ya que tan solo van a necesitar un par de horas de intentos para conseguir registrarse y empezar a hacer llamadas.
- Evitar a toda costa eso que hacen los interfaces de configurar todas las extensiones como nat=yes, este parámetro sólo debe estar para aquellas extensiones que realmente se encuentren detrás de NAT que realmente son las más vulnerables.
No obstante, durante el curso de Asterisk Advanced aparecieron varias ideas más entre las que había una que no me disgustó:
- Comprobar en el log del Asterisk los intentos fallidos de autenticación y en el caso de varios intentos, añadir de forma automática en el IPTables la dirección IP de nuestro ‘supuesto’ atacante.
Lo de ‘de forma automática‘ es imprescindible, ya que los ataques suelen producirse cuando nuestro sistema es más vulnerable: los fines de semana, de forma que no les prestemos atención a los logs hasta que el administrador de sistemas vuelva el lunes, de esta forma los atacantes tienen varios días para su ataque por fuerza bruta.Así que, analizando el log y documentándonos un poco vimos que Asterisk loguea los intentos fallidos de registro SIP como mensajes de tipo NOTICE (algo que viene por defecto en el logger.conf y que nos permite monitorizar quien se ha intentado registrar casi siempre).
A la vista de esta última idea, desarrollamos un script que, añadido al crontab, analizaba el archivo ‘messages’ del Asterisk en busca de intentos fallidos y cuando este número superase una cantidad considerable, el script añadiría dicha IP en el IPtables para que el sistema le prohibiese acceder al puerto 5060/UDP.
El script lo podéis encontrar aquí y para activarlo, tan sólo tenéis que copiarlo al directorio /usr/local/bin y llamarlo cada cierto tiempo en el crontab editando el archivo /etc/crontab y añadiendo una línea como esta:
00 * * * * root /usr/local/bin/sipcheck.pl messages
De esta forma, evitaremos que un atacante pueda conocer la contraseña de nuestras extensiones que están detrás de nat y pueda hacer llamadas internacionales a través nuestra.
Por defecto, el número de intentos fallidos antes de ser añadido automáticamente al IPTables es de 200, suficientes para detectar un ataque por fuerza bruta sin que añada extensiones que han fallado por escribir mal la contraseña. Este número se puede cambiar dentro del código.
Las direcciones IP atacantes se añaden al firewall ya existente, permitiendo «limpiar» estas direcciones con el parámetro ‘clear‘ sin que afecte al resto de la configuración del IPTables.
Por supuesto, se le pueden hacer muchas mejoras, pero de momento, esta primera versión servirá para aquellos que quieran asegurar su sistema un poco más.
Si te gusta el script y lo quieres mejorar, acuérdate de enviarme los cambios para que pueda servir a otras personas (para eso es GPL).
El script lo podeis descargar de aquí: sipcheck
Únicamente nos falta agradecer a los asistentes al curso de Asterisk Advanced Bilbao 2010 por ese BrainStorming antes de quedar para cenar que fomentó hacer el script que ha conseguido que en algunos sistemas conocidos donde instalé este script para pruebas, ya haya capturado varias direcciones IP. ;D