Connexion
Abonnez-vous

L’adresse 0.0.0.0 au cœur d’une très vieille faille de sécurité dans les navigateurs

Supposition à tort

L’adresse 0.0.0.0 au cœur d’une très vieille faille de sécurité dans les navigateurs

La société de sécurité Oligo a publié hier un billet dans lequel elle explique avoir alerté les fournisseurs de navigateurs au sujet d’une faille critique. Elle réside dans la manière dont ils gèrent l’adresse 0.0.0.0, pouvant renvoyer des pirates vers des ressources locales et une exécution de code à distance.

Le 08 août à 17h20

0.0.0.0 Day : c’est le nom donné par la société israélienne Oligo à cette faille présente dans Chrome, Firefox et Safari. Elle n’a rien de nouveau pourtant, puisqu’elle remonte dans certains cas à 18 ans. Oligo précise toutefois qu’elle a été découverte « récemment ».

L’adresse IP 0.0.0.0 est particulière et n’a pas la même signification selon le contexte. Sur Wikipédia, on trouve les deux cas les plus courants. Dans le contexte d’un serveur par exemple, elle a valeur de « toutes les adresses IPv4 de la machine locale ». Dans le domaine du routage en revanche, elle signifie le plus souvent « route par défaut ». En IPv6, plutôt que d’écrire une longue chaine de zéros, on utilise la notation « :: ».

Quel lien avec les navigateurs ? « Ce problème découle de la mise en œuvre incohérente des mécanismes de sécurité dans les différents navigateurs, ainsi que d'un manque de normalisation dans l'industrie des navigateurs », résume Oligo.

Tous les navigateurs, sauf sur Windows

La vulnérabilité trouvée est décrite comme « fondamentale » et « logique ». Elle réside aussi bien dans Chromium que dans Firefox et Safari. macOS et Linux sont concernés, mais pas Windows. Microsoft a en effet décidé de bloquer l’adresse 0.0.0.0 il y a plusieurs années.

Le problème découvert par Oligo réside dans la manière dont les navigateurs traitent les requêtes vers la fameuse adresse IP. Elle peut être utilisée pour exploiter des services locaux. Un site web public (comme les domaines finissant en .com, .fr, etc.) sont « capables de communiquer avec des services fonctionnant sur le réseau local (localhost) et potentiellement d'exécuter un code arbitraire sur l'hôte du visiteur en utilisant l'adresse 0.0.0.0 au lieu de localhost/127.0.0.1 », explique Oligo.

En clair, toute application s'exécutant sur localhost et accessible via 0.0.0.0 est susceptible d'exécuter du code à distance. Les pirates peuvent alors former une requête malveillante et l’expédier vers l’adresse 0.0.0.0 de la victime, dans l’espoir d’accéder à des ressources locales. S’ils y parviennent, de nombreuses possibilités s’ouvrent à eux, avec un vaste choix de vecteurs pour d’autres attaques.

Un grand nombre de configurations vulnérables

En pratique, Oligo estime que la faille concerne surtout les particuliers et les entreprises hébergeant des serveurs web pour certains scénarios, dont les tests en développement. Mais même ainsi, les chercheurs pensent que le nombre de configurations vulnérables est très élevé.

En mars dernier, une cyberattaque avait par exemple détourné de la puissance de calcul à des fins de minage de cryptoactifs en détournant le logiciel Ray, rapportait Forbes. Ray est utilisé par de nombreuses grandes entreprises pour l’entrainement des modèles d’IA. Une configuration à base de localhost et une API non protégée rendaient l’attaque possible. Anyscale, qui supervise le développement de Ray, avait protesté. L’entreprise renvoyait vers son guide de configuration, qui déconseillait fortement d’exposer Ray à du trafic réseau non fiable.

« Lorsque les services utilisent localhost, ils supposent un environnement contraint. Cette hypothèse, qui peut (comme dans le cas de cette vulnérabilité) être erronée, donne lieu à des implémentations de serveurs non sécurisées », résume Avi Lumelsky, principal chercheur derrière l’étude d’Oligo.

Les entreprises travaillent à colmater la brèche

Apple a confirmé auprès de Forbes travailler sur la question. Lors d’une prochaine bêta de macOS Sequoia, le problème ne devrait plus exister. Safari 18 devrait complètement bloquer l’adresse 0.0.0.0 dans le nouveau macOS. Les nouvelles versions du navigateur étant répercutées sur le système précédent, Sonoma en bénéficiera également. La situation est plus floue pour les moutures plus anciennes.

Chez Google, la prochaine révision 128 de Chrome commencera à bloquer elle aussi l’adresse 0.0.0.0. Ce changement sera déployé progressivement au cours des prochaines versions, jusqu’à un blocage total pour Chrome 133.

Dans la fiche explicative de Google, on peut lire que cette mesure est adoptée avant que Private Network Access n’entre en jeu. PNA est une spécification (toujours en brouillon) pour un mécanisme visant à limiter « la capacité des sites Web à envoyer des requêtes aux serveurs situés sur des réseaux privés ». PNA étend également le protocole CORS (Cross-Origin Resource Sharing). Avec PNA, les sites web doivent donc demander explicitement l’autorisation aux serveurs situés sur des réseaux privés pour leur envoyer des requêtes. Or, la faille découverte par Oligo permet de contourner entièrement PNA.

Chez Mozilla, c’est un peu plus compliqué. Firefox va adopter Private Network Access, mais ne compte pas bloquer immédiatement l’adresse 0.0.0.0. Le navigateur n’ayant jamais restreint l’accès au réseau privé, il n’y a pas de faille à proprement parler. Après l’avertissement d’Oligo, Mozilla a quand même proposé un changement de la spécification Fetch pour introduire le blocage 0.0.0.0. « Imposer des restrictions plus strictes comporte un risque important d'introduire des problèmes de compatibilité », a cependant déclaré Mozilla à Forbes.

Oligo présentera ses découvertes plus en détail le 10 août, lors de la DEF CON qui se tient à Las Vegas.

Commentaires (28)

Vous devez être abonné pour pouvoir commenter.

Abonnez-vous
votre avatar
Certains étant très prompt à dézinguer les mauvais choix de Windows lorsqu'il s'agit de sécurité, j'espère qu'ils seront également prompt à dézinguer le mauvais choix de Linux (et de macOS) quant à la gestion des adresses IP :troll:
votre avatar
:bouletdujour:

C'est comme 1.1.1.1 utilisé en interne dans les livebox.:fr:
votre avatar
Ce n'est pas un "mauvais choix" mais une spécification de BSD qui a été reprise dans Linux. En IPv4 comme en IPv6.

Comme Microsoft ne suit pas les standards, pour une fois ca tombe du bon coté de la tartine pour Windows. Mais je n'appellerai pas un "bon choix" le fait de ne pas suivre les standards.
votre avatar
je trollais hein ;) (cf. le smiley).

Par contre, je ne vois pas pourquoi tu dis que Windows ne suit pas les standards. Pour le coup, et à ma connaissance, l'usage d'adresse 0.0.0.0 ne fait pas partie du standard (je parle bien de l'adresse, pas des blocs 0.0.0.0/8)

edit]
la [RFC 5735 section 3
précise l'usage possible de 0.0.0.0. L'IP 0.0.0.0 devrait (MAY) être utilisée qu'en tant qu'adresse source, pas en tant qu'adresse cible. Donc toute communication à destination de 0.0.0.0 devrait, d'après la compréhension que j'ai de la norme, être rejeté.

J'ai bien employé devrait pour refléter le MAY de la norme. Autrement dit, ce n'est pas une obligation, mais une recommandation forte. Allez à l'encontre n'est pas formellement interdit, mais ne va pas dans le sens de l'esprit de la norme.

Donc pour le coup, c'est même Windows qui respecte mieux la norme sur ce coup là !

[edit 2]
Pour être le plus précis possible, je suis remonté jusqu'à la RFC 1700, où le texte est beaucoup plus clair à mes yeux, et n'utilise pas MAY :
This host on this network. Can only be used as a source address (see note later)
votre avatar
Oui j'avais compris pour le troll :)

Standard était peut-être un peu fort. Cette "interprétation" de 0=localhost était dans l'implémentation de BSD qui a été reprise par les OS qui ont ré-implémentés les "BSD socket".

L'implémentation a toujours été différente coté Windows (winsock) car ils sont repartis de la spec pour leur stack réseau. Meme si on trouve du code BSD dans windows, c'est davantage pour les outils que pour la stack.

Avis perso:

Je ne pense pas que BSD ait volontairement voulu donner la sémantique INADDR_LOOPBACK (127.0.0.1) à INADDR_ANY (0.0.0.0) dans le cas d'un connect(). Ca ressemble plutôt à l'interprétation du développeur C quand il a été confronté à la valeur 0 (zéro). Comme 0 (zéro) et "0.0.0.0" ont la même représentation (0x00000000), ca sent le raccourcis logique 0 = "0.0.0.0" = pas de routage => on reste sur l'hôte local.

Avec cette faille, j'espère qu'on aura l'explication d'un vieux de la vieille sur le pourquoi. J'adore ces anecdotes sur l'archéologie des logiciels. Ex: le blog de Raymond Chen.
votre avatar
Ok, je comprends mieux. Merci pour les précisions ;) Nul non respect de standard ici donc, car il n'y en a pas vraiment sur ce point précis.
Avec cette faille, j'espère qu'on aura l'explication d'un vieux de la vieille sur le pourquoi. J'adore ces anecdotes sur l'archéologie des logiciels. Ex: le blog de Raymond Chen.
C'est toujours intéressant effectivement, et souvent riche en informations !
votre avatar
Merci pour le blog que je ne connaissais pas mais qui est hyper technique. On dirait le blog du créateur des ordinateurs xD
votre avatar
votre avatar
... et en plus tu es cité dans l'article ! La gloire est là ^^
votre avatar
J'ai longtemps (l'auteur a laissé tomber depuis quelques années en raison de gros pb de santé) utilisé le fichier hosts proposé ci-dessous comme filtre simple et efficace de pubeux, sur Linux comme Windows, bien qu'il ait été fait pour ce dernier:
https://winhelp2002.mvps.org/hosts.htm

Et je me souvenais qu'a l'époque win8, il avait changé la redirection de 127.0.0.1 vers 0.0.0.0 pour une raison dont je ne me rappelais plus mais qui est encore notée:
"The HOSTS file now contains a change in the prefix in the HOSTS entries to "0.0.0.0" instead of the usual "127.0.0.1".
This was done to resolve a slowdown issue that occurs with the change Microsoft made in the "TCP loopback interface" in Win8.1"


Peut-être qu'en réalité, c’était juste devenu plus rapide car MS s'était mis à carrément poubelliser toute trame ayant cette IP source/destination.

Probable que Microsoft ait été assez longtemps dans la même situation. De toutes manières, niveau réseau, ils ont dès le début été à la bourre (il a fallu attendre win3.11 pour avoir une pile réseau quand les unices étaient construits autour depuis les origines à la fin des années 60) et Linux n'a pas arrangé les choses: Là c'est très simple, un OS boite blanche c'est l'outil idéal pour implémenter les évolutions/nouveautés par la recherche universitaire, entre autres. Windows étant au contraire une boite noire, le choix général dans le domaine c'est surtout celui de suivre! Ce n'est pas pour rien si toute l'infra réseaux/télécoms a fait le choix de passer à Linux dans la première moitié de la décennie 2000: Les RTOS qui s'imposaient jusque là posaient le même type de problème et quand le réseau est votre cœur de métier, on va là ou l'innovation se trouve.
votre avatar
Je ne vois pas le rapport entre l'écoute sur 0.0.0.0 (qui semble être sous-entendue quand on parle du système d'exploitation), et les requêtes sur une autre réseau opéré par des agents qui exécutent du code tiers (ici les navigateurs).

Je sais que l'on adore taper sur ceux qui tiennent la dragée haute des bonnes pratiques quand ils se gaussent (à raison) du cauchemar en face, parce qu'on adore tous être moralisateur, mais encore faut-il être de bonne foi pour être crédible et audible, à la fois immédiatement… et à plus long terme !
votre avatar
J'ai du mal à voir la différence, dans ce cas, entre 0.0.0.0 (accessible en local et distant) et 127.0.0.1 (accessible uniquement en local). Une requête forgée vers 127.0.0.1 retournerait strictement la même chose que vers 0.0.0.0, soit "quelque chose" qui tournerait en localhost.

Dans tous les cas ça semble être un problème uniquement lié à des machines où des services spécifiques tournent (qui a un serveur http qui écoute sur son laptop ?) et donc non sur des machines d'usagers lambda. (un peu) ouf.
votre avatar
Le souci, si j'ai bien compris, est que comme 0.0.0.0 a plusieurs usages en fonction du contexte (écoute sur toutes les interfaces / routage vers toutes les adresses), il n'est pas sécurisé correctement par mécanismes de sécurité (pare-feux et autres).
Donc oui, ça ne touche que les machines qui ont des services réseau qui tournent localement, mais ça touche... toutes les machines qui ont des services réseau qui tournent localement. J'imagine qu'on peut avoir un proof of concept basé sur un client SMB écrit en Javascript et exécuté dans le navigateur qui passerait outre les mécanismes de sécurité placés sur 127.0.0.1 en utilisant 0.0.0.0 et qui redirigerait le contenu local vers un serveur distant.
votre avatar
Cela ne touche pas tous les services réseau qui tournent en local mais ceux qui ne spécifient pas explicitement une ou des adresses d'écoute. Si tu écoutes 127.0.0.1, je pense que tu ne sera pas touché.

Utiliser 0.0.0.0 est courant en IPv4 car pas mal de services tournent sur des vm ou conteneurs avec une adresse locale et un NAT44

En IPv6, on peut utiliser des adresses de service qui sont passées en argument au conteneurs et permettre au service de n'écouter que sur l'adresse dédiée. Si un accès de test est désiré, il est possible d'utiliser une adresse ULA en plus.
votre avatar
Hmmm.... Je pense que si. Une connexion "0.0.0.0" est remplacée par une connexion à INADDR_LOOPBACK (127.0.0.1) par l'OS.

if (!fl4->daddr) fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);

net/ipv4/route.c
votre avatar
Je dirais que le problème se situe à la ligne d'avant:
if (!fl4->daddr) {
fl4->daddr = fl4->saddr;
if (!fl4->daddr)
fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
dev_out = net->loopback_dev;
(pénible le markdown pipé...)

C'est donc dès la ligne « fl4->daddr = fl4->saddr » qu'une requête provenant de 127.0.0.1 et destinée à 0.0.0.0 devient destinée à 127.0.0.1

Et cela interdit donc de bloquer ces requêtes via le pare-feu. :fumer:
votre avatar
La spec de BSD c'est:

1. si pas d'adresse de destination, alors destination = source.
2. si pas d'adresse de destination ni d'adresse source, alors destination = source = localhost.

C'est ce que fait le code, même si ce n'est pas très lisible :)
votre avatar
C'est bien ce que j'avais compris mais c'est bien la première condition qui pose problème dans le cas présent.

En cas d'arrivée d'un paquet IPv4 d'un navigateur, l'adresse source sera 127.0.0.1 et c'est la ligne que j'ai donné qui cause le remplacement de 0.0.0.0 par 127.0.0.1

Je suis du même avis que tous ceux qui pensent que cela devrait provoquer le rejet du paquet.
votre avatar
il n'est pas sécurisé correctement par mécanismes de sécurité (pare-feux et autres).
Au contraire ! 0.0.0.0 signifie "accessible depuis l'extérieur de la machine" donc il faut justement qu'un pare-feu soit présent, contrairement à binder sur 127.0.0.1 qui ne sera accessible qu'en local (et donc présumé sans risques).

Autre point d'ailleurs, les navigateurs bloquent les ports connus standard :
https://searchfox.org/mozilla-central/source/netwerk/base/nsIOService.cpp#152

Donc justement on se limite quand même sacrément au niveau des services qui pourraient être accessibles en 0.0.0.0:. (Bon ton exemple de SMB typiquement n'est pas dans la liste des ports bloqués… donc OK, mais pour moi la faille de sécurité est aussi présente avec 127.0.0.1)
votre avatar
Au contraire ! 0.0.0.0 signifie "accessible depuis l'extérieur de la machine"
Pour être précis, dans le contexte de la configuration d'un service qui écoute, mettre 0.0.0.0 indique qu'on se fiche de l'adresse de destination pour accepter les communications. On acceptera à la fois les communications internes et externes, dès lors que la communication atteint la machine.

Si tu saisis l'adresse loopback (typiquement 127.0.0.1) tu n'accepteras que les communications en provenance de localhost (interne = la machine).

Si tu saisi l'adresse sur le réseau local (par ex. 192.168.2.38) tu accepteras les communications provenant de l'extérieur (= extérieur à la machine, donc en provenance du réseau = externe) dès lors que l'adresse cible est 192.168.2.28. Si tu es sur ta machine et que tu essaies en loopback (via 127.0.0.1), la communication ne sera normalement pas acceptée, mais elle le sera si tu utilises l'adresse 192.168.2.28.

Si ta machine est accessible via plusieurs réseaux, si tu mets un 0.0.0.0, alors elle acceptera les communications, quel que soit le réseau. Si tu mets une adresse 192.168.2.38 comme adresse d'écoute, mais que ta machine dispose aussi de l'IP 10.0.43.23 sur un autre réseau, alors utiliser cette 2e IP (10.0.43.23) pour accéder au service ne marchera pas .

En fonction de la position du pare-feu dans le réseau, cela peut avoir une très grande importance !

Les subtilités du réseau...
votre avatar
Oui, et donc, ça n'impacte pas le cas où les requêtes viennent d'un navigateur tournant sur la machine en local (un process bindé sur 0.0.0.0 ou 127.0.0.1 sera accessible).
votre avatar
exécuter un code arbitraire sur l'hôte du visiteur en utilisant l'adresse 0.0.0.0 au lieu de localhost/127.0.0.1
espèce d'imposteur !!!!!!
 
votre avatar
jaloux ^^
votre avatar
Je viens de tester un fetch('//0.0.0.0:8000') dans ma console JS de mon Firefox : bloqué par uBlock Origin.

Filtre qui vient à la fois de EasyPrivacy et de « uBlock filters - Quick fixes »

Donc, je pense que uBlock Origin suffit. Mais bon, hein, je dis ça, je dis rien.
votre avatar
Le fait que ton navigateur n'attaque pas 0.0.0.0 est une bonne atténuation du risque. Mais le risque reste présent, le service répond toujours en 0.0.0.0, et d'autres navigateurs peuvent continuer à y accéder.

Sur ton poste de travail, il y a probablement des navigateurs "cachés" comme par exemple celui qui gère les connexions WiFi (pour proposer une mire de login), ou un afficheur html dans le client mail. Et ces "navigateurs" n'ont probablement pas uBlock.
votre avatar
ou toute application de type Electron (Teams, Discord, Notion, Slack, VS Code, Obsidian, Twitch, ...)
votre avatar
Ouais,
dans mes références, 0.0.0.0 était une adresse non définie en adresse source et invalide en destination, je me demande qui a eu cette idée bizarre de la traiter comme localhost ou loopback, ça n'aurait pas dû arriver.
Ce n'est pas parce que netstat affiche une écoute sur 0.0.0.0 pour dire non définie que cette destination est valide, tout comme un routeur doit bloquer l'adresse avec host à 0 d'un réseau qui lui est raccordé, même si elle est présente dans sa table de routage.
votre avatar
Le traitement du ticket côté Firefox est juste incroyable : la preuve de l'accès à une ressource qui n'a rien a faire dans le chemin requête réponse d'un site ne suffisait pas.
Il fallait qualifier le bogue.
Puis il fallait démontrer une réelle exploitation.

Ouverture, fermeture, tergiversations… 20 ans.
Et plus le temps passait, plus la probabilité d'un traitement simple & rapide s'éloignait, par le simple fait du temps passé (qui va être entendu en questionnant 10 ans de tergiversation sans se retrouver être attaqué personnellement ?).

Messieurs dans le domaine de la sécurité, je vous propose ceci :
* Perçons ensemble l’abcès de votre ego
* Arrêtons d'emmerder les remonteurs de problèmes, et partons du principe qu'ils puissent avoir raison
* Revenons à des questions simples : si un accès n'est pas absolument légitime/nécessaire, alors partons du principe que l'isolation est bonne, sans avoir à savoir exactement pourquoi. En cas de bris fonctionnel, le débat pourra être ré-ouvert sur la base, toujours, de la légitimité et des bonnes pratiques.

L’adresse 0.0.0.0 au cœur d’une très vieille faille de sécurité dans les navigateurs

  • Tous les navigateurs, sauf sur Windows

  • Un grand nombre de configurations vulnérables

  • Les entreprises travaillent à colmater la brèche

Fermer