24 julio 2008

DNS, pasaté al TCP

Mucho se ha hablado ya del famoso bug que afecta al DNS y del que recientemente se han conocido los detalles "mas íntimos" sobre la forma y manera de sacarle partido (con su correspondiente exploit).

De una forma muy resumida y digerible el asunto estriba en dos características del protocolo DNS tal y como está desplegado actualmente :


·La comunicación se realiza con un protocolo NO orientado a conexión (UDP) y por tanto susceptible de ser "spoofeado"
· Las transacciones (peticiones-respuestas) están marcadas con un ID que, si bien se han hecho esfuerzos por dotarlo de aleatoriedad, como se ha podido comprobar, no ha sido suficiente.

El protocolo DNS, tal y como está definido en la RFC 883 debería de ser capaz de atender querys tanto en el puerto 53-UDP como en el 53-TCP. Erróneamente mucha gente asocia únicamente la comunicación del protocolo DNS en formato TCP a las transferencias de zonas entre DNSs primarios <-> secundarios y cuando una petición excede los 512 bits. Incluso no es descabellado encontrar documentos de hardening en el que se propone como medida de seguridad bloquear el acceso al puerto TCP del DNS.

Lo cierto es que un servidor DNS debería de prestar servicio por el puerto 53-TCP de forma "normal" el problema está en que consuetudinariamente la gente ha usado siempre 53-UDP alegando motivos de eficiencia, motivos que, en origen, cuando se diseñó el protocolo DNS tenían mucho peso, el problema es que esos conceptos forman parte de la época del Gopher y la www por texto, donde unos pocos bits eran un lujo. En los tiempos actuales en los que cualquiera puede incluso emplear su ADSL para colgar enormes vídeos en formato flash de varios megas, no tiene demasiado sentido seguir con esas premisas.

A nivel seguridad, ¿que supondría pasar el protocolo DNS a TCP? En pocas palabras: adiós al spoofing de conexiones (parte básica en todos los ataques al protocolo DNS), cuando hablamos de conexiones TCP estamos hablando de un protocolo orientado a conexión, donde interviene en cada conexión lo que se conoce como "TCP Sequence Number" que es un numero aleatorio por cada conexión. Hace años (principio de los 90) el protocolo TCP adoleció de fallos en este sistema que permitía predecir dichos números volviéndolo vulnerable a ataques de tipo IP-Spoof. Actualmente y tras muchos esfuerzos, unánimemente se considera un mecanismo robusto y fiable ya que prácticamente todos los sistemas operativos cuentan con mecanismos muy probados para obtener la suficiente entropia.
Podemos usar Hping para comprobar la aleatoriedad del ISN sobre cualquier host de la siguiente forma:
hping -S -p 80 www.security-projects.com -Q
HPING www.security-projects.com (eth0 208.88.52.63): S set, 40 headers + 0 data
bytes
1144894739 +1144894739
1147953489 +3058750
1136625600 +4283639406
1137798400 +1172800
1150024660 +12226260
1147708505 +4292651140
1138715293 +4285974083

Como se puede observar, la forma en la que se altera el ISN no tiene ningún patrón predecible.
Con el cambio de UDP a TCP, un potencial atacante tendría que deducir el ISN de TCP y el DNS-query-ID para falsear una respuesta, algo prácticamente imposible.

A nivel rendimiento, ¿que supondría pasar el protocolo DNS a TCP? En este punto toca disfrazarse del Sr Solbes y sacar la calculadora para manejar correctamente los datos, Wireshark en mano, una consulta DNS por el protocolo UDP, de www.google.com en un Windows XP sp2 sale en:

4 Paquetes / 461 Bytes

Misma query usando TCP:

22 Paquetes / 1557 Bytes

Evidentemente, bajo UDP, el consumo de ancho de banda es infinitamente menor, y visto porcentualmente, puede que el dato sea demoledor, pero si nos fijamos en las cifras y sobre todo en el orden de magnitud que nos estamos moviendo (Bytes) ¿realmente supone tanta diferencia?
He buscado algún tipo de métrica online con datos fiables a-la-mrtg para tratar de hacerme una idea de lo que puede suponer multiplicar por dos el trafico DNS. Y si, estudios del estilo "El p2p ocupa el 80% del tráfico" hay cientos, pero con datos para ver, pocos. Finalmente he encontrado un proyecto de la organización CAIDA (si, un nombre poco apropiado para los hispanohablantes) que se basa en obtener métricas de "puntos neutros" al estilo de nuestro Espanix.

Ojeando dichos datos me llama la atención que el DNS no está entre los protocolos con mas consumo de ancho de banda, de hecho, ni sale en la lista ordenada por consumo de bytes hay que ir a las listas de flujos de datos (normal, el DNS se supone que ha de generar múltiples hits) para encontrar los datos de consumo que, según esas estadísticas, suponen un 0,18 %

Con esos datos en la mano (que no tienen porque ser ni parecidos a los de, por ejemplo, un ISP como telefónica) queda bastante claro que el cambio TCP por UDP no tiene que resultar especialmente traumatico.

¿Soluciones? A dia de hoy no resulta obvio ni trivial alterar los parámetros del sistema operativo para forzar que las consultas DNS se hagan mediante TCP, en Linux-Unix, el 'resolver' (la base donde se sustenta el mecanismo para resolver direcciones), está preparado para hacer consultas vía TCP empleando la opción RES_USEVC, pero sorprendentemente, esta opción no se puede configurar desde el fichero /etc/resolv.conf (otras muchas, si). Resultaría trivial hacer unas pequeñas modificaciones para soportar esta funcionalidad. En el caso de sistemas Windows no costaría mucho adaptar el sistema y dejar al usuario la opción de añadir una clave en el registro para activar-desactivar esa opción.

A nivel servidores, (Bind, DJB y cía) como ya hemos visto, nativamente soportan querys vía 53-tcp, no costaría demasiado adaptarlos para que empleen un mecanismo al estilo "primero intento TCP, si falla, lo envío por UDP", ajustando muy muy bien los 'timeouts' para identificar con suficiente celeridad que servidor DNS esta dispuesto a resolver por TCP y cuales no.

Queda un ultimo punto: el desempeño en enlaces con poco ancho de banda (PPP, GSM, y similares) obviamente esta claro que ese tipo de conexiones iban a sufrir bastante por la falta de rapidez en realizar las transacciones DNS, por eso, la solución necesariamente tendría que ser como he comentado antes, dejar al usuario los mecanismos para decidir si necesita UDP o TCP.

¿Que se puede hacer ahora? Con todo lo expuesto anteriormente, si se puede hacer algo, al menos, para securizar nuestro entorno (Red local, nuestro PC). Después de investigar bastante el tema, buscar y probar varias implementaciones de DNS Cache e incluso plantearme hacer mi propio DNS-proxy, di con un software que hace justo lo que yo tenia en la cabeza: Admite querys en formato UDP (necesario para la comunicacion PC<->DNS) y re-envía la petición al DNS principal en formato TCP, su nombre: Pdnsd (Para linux).

La configuración que se puede hacer con este programa corresponde a este esquema:


Como se puede ver, la comunicación desde nuestro PC / un equipo de nuestra red, hacia el cache DNS va en formato UDP "atacable" pero la comunicación hacia el servidor DNS principal, en internet, va en formato TCP con lo que restringimos el riesgo de ataque a nuestra propia red, cosa bastante menor ya que si alguien pretende atacarnos desde nuestra intranet o nuestro PC, tendríamos bastantes mas problemas de los que preocuparnos.

Un ejemplo de configuración para Pdnsd de cara a usarlo en local (para tu propio PC, no como DNS cache para toda tu intranet) sería ésta

En este punto solo nos hace falta localizar un servidor DNS recursivo que acepte querys por el puerto TCP, como ya hemos dicho anteriormente, muchos ISPs cierran ese puerto o impiden que se acepten querys por el 53-TCP. Para comprobar si un servidor DNS acepta peticiones al 53-tcp podemos usar la herramienta dig con los parametros +vc

dig +vc www.google.com @dns.ya.com

; <<>> DiG 9.2.3 <<>> +vc www.google.com @dns.ya.com
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38295 ;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 7, ADDITIONAL: 7 ;; QUESTION SECTION: ;www.google.com. IN A ;; ANSWER SECTION: www.google.com. 577445 IN CNAME www.l.google.com. www.l.google.com. 245 IN A 66.102.9.99 www.l.google.com. 245 IN A 66.102.9.104 www.l.google.com. 245 IN A 66.102.9.147

Como se puede ver, el DNS de ya.com acepta y resuelve bien por el puerto 53-TCP

2 comments :

Anónimo dijo...

Muy buena entrada

Anónimo dijo...

Lo acabo de probar...

muy bueno!