<?xml version="1.0" encoding="utf-8"?>
<entry title="Le cours « Hacking IPv6 »">
<date>2013-06-20</date>
<content>
<p>Cette semaine, j'ai eu le plaisir de suivre le cours
« <foreign><link url="http://www.hackingipv6networks.com/">Hacking
IPv6</link></foreign> » de Fernando Gont lors de <link
url="http://www.hackinparis.com/trainings">Hack in Paris</link> à
<wikipedia name="Disneyland Paris">Disneyland</wikipedia>. C'est l'occasion de partager
quelques-unes de mes notes de cours. (Les supports de cours ne sont
pas encore publiquement disponibles.)</p>
<p>Gont est l'auteur de <link url="/search?pattern=gont">plusieurs excellents RFC sur la
sécurité</link>. La tonalité générale de son cours était plutôt
méfiante vis-à-vis d'<wikipedia>IPv6</wikipedia>, il s'est notamment attaqué à des mythes
comme celui selon lequel IPv6 serait plus sûr car
<wikipedia name="Internet Protocol Security">IPsec</wikipedia> y est obligatoire (cela n'a jamais été
vrai en pratique et cela n'est même plus le cas en théorie
depuis le <rfc num="6434" local="true"/>). Il a également noté la
faiblesse en ressources humaines (peu de compétences disponibles) mais
il a oublié de dire que c'était pareil chez les attaquants. Faites
l'expérience (comme moi), mettez un <wikipedia name="Honeypot">pot de miel</wikipedia>
accessible uniquement en IPv6 et vous verrez que personne ne l'attaque
(alors que les mouches affluent immédiatement sur tout pot de miel
IPv4). Dans le monde réel (pas dans les conférences de hackers), les attaques via IPv6 sont en quantité
négligeable et, à mon avis, ne représentent pas une raison sérieuse de
retarder la migration. Gont a un point de vue différent, comme quoi il
faudrait avoir un bon niveau de sécurité avant de migrer. Il note que
les <wikipedia xml:lang="en" name="How-to">HOWTO</wikipedia> « comment migrer vers IPv6 en cinq
minutes » sont dangereux car ils laissent le réseau migré vulnérable. Selon moi,
avec un tel argument, on n'aurait jamais déployé
<wikipedia>IPv4</wikipedia>...</p>
<p>Mais Gont note aussi que, non seulement la migration est
inévitable, mais qu'elle a déjà commencé. Ainsi, beaucoup de
<wikipedia name="Système d'exploitation">systèmes d'exploitation</wikipedia> ayant IPv6 activé par
défaut, bien des réseaux ont déjà IPv6 sans le savoir et, grâce à
<wikipedia name="Teredo (protocole)">Teredo</wikipedia>, ont même parfois une connectivité
externe (« <foreign>There are no IPv4-only networks</foreign> »). Donc, qu'on veuille migrer ou pas, il faut se préoccuper de
la sécurité sur IPv6.</p>
<p>L'essentiel de la partie pratique du cours se faisait avec deux
boîtes à outils :
<enum>
<item>La plus ancienne, <link
url="http://www.thc.org/thc-ipv6/">THC-IPv6</link>, qui ne marche que
sur <wikipedia>Linux</wikipedia> et que sur
<wikipedia>Ethernet</wikipedia> et dont Gont trouve la documentation
plutôt limitée,</item>
<item>Celle du formateur, <link
url="http://www.si6networks.com/tools/ipv6toolkit/">SI6
toolkit</link>, distribuée sous <wikipedia name="Licence publique générale GNU">GPL</wikipedia>.</item>
</enum>
Les exemples ci-dessous utilisent en général les outils d'une de ces
deux boîtes.</p>
<p>Le cours suit classiquement le <wikipedia name="Modèle OSI">modèle en
couches</wikipedia>. On part de la <wikipedia>couche 2</wikipedia>. Normalement, dans Ethernet, le type de protocole
utilisé figure dans l'en-tête Ethernet mais, en théorie, on pourrait
imaginer un attaquant mettant des paquets IPv6 avec un en-tête
Ethernet indiquant ces paquets comme étant IPv4, pour essayer de
passer outre un filtrage dans les
<wikipedia name="Commutateur réseau">commutateurs</wikipedia>. En pratique, cette attaque ne
marche pas, tous les systèmes testés vérifient que les deux types
correspondent. Premier hack raté.</p>
<p>Ensuite, la <wikipedia>couche 3</wikipedia>, le gros morceau du
cours. Chaque champ de l'en-tête IPv6 est examiné. Par exemple, le peu
connu <foreign>Flow label</foreign> avait été conçu pour ne pas avoir
à suivre la chaîne des en-têtes (opération <link local="analyse-pcap-ipv6">très
complexe</link>) pour découvrir les paquets du même flot. En pratique,
peu de systèmes s'en servent (il est souvent à zéro et, dans ce cas,
<wikipedia>tcpdump</wikipedia> ne l'affiche pas) mais il peut être utilisé par
l'attaquant, par exemple pour découvrir le rythme de création de
nouvelles connexions par une machine. L'outil flow6 dans la boîte SI6
permet de connaître la politique utilisée (ici, contre un système <wikipedia>Linux</wikipedia>) :
<code>
# flow6 -i eth1 -v --flow-label-policy -d 2001:db8:8ad9:84b1:ba27:ebff:feba:9094                                                                    
...
Identifying the 'Flow ID' generation policy of the target node....
Flow Label policy: Global (predictable) constant labels, set to 00000
</code>
On voit que ce système met toujours le <foreign>flow label</foreign> à
zéro. Contre un système <wikipedia>FreeBSD</wikipedia> :
<code>
# flow6 -i eth0 -v --flow-label-policy -d 2001:1900:2254:206a::50:0
...
Identifying the 'Flow ID' generation policy of the target node....
Flow Label policy: Global (predictable) labels with increments of 2202551761 (sdev: 0.500000)
</code>
Cette fois, le <foreign>flow label</foreign> est mis et est
prévisible, donnant accès à des informations utiles. Avec tcpdump, on
voit ce champ, s'il n'est pas nul (il vaut ici 0xaa187) :
<code>
12:28:58.432511 IP6 (flowlabel 0xaa187, hlim 57, next-header TCP (6) payload length: 40) 
     2001:41d0:1:ea44::1. 42700 > 2001:4b98:dc0:41:216:3eff:fece:1902.80: 
     Flags [S], cksum 0x9850 (correct), seq 1485994586, win 65535,
      options [mss 1440,nop,wscale 3,sackOK,TS val 181079131 ecr 0], length 0
</code>
Cet outil, sur certains réseaux (peut-être ceux ayant plus d'un routeur), dit parfois <foreign>Couldn't find
local router</foreign> mais cette bogue n'est pas encore résolue.</p>
<p>Autre chose amusante dans IPv6 : au lieu d'avoir un en-tête de
taille variable, comme IPv4 (avec un champ qui indique la taille de
l'en-tête, qui change selon les options IP incluses), IPv6 a un
en-tête de taille fixe, puis zéro, un ou davantage d'en-têtes
d'extension. Par exemple, si le paquet est
<wikipedia xml:lang="en" name="IP fragmentation">fragmenté</wikipedia>, un en-tête d'extension
<foreign>Fragment header</foreign> va être mis. L'un des problèmes que
posent ces en-têtes d'extension est que les paquets qui les portent
sont souvent jetés sans cérémonie par des routeurs ou des
<wikipedia name="Pare-feu (informatique)">pare-feux</wikipedia> violents. Si ce n'est pas le
cas, comme leur présence décale tous les champs suivants (comme
l'en-tête <wikipedia name="Transmission Control Protocol">TCP</wikipedia>, avec ses numéros de
<wikipedia name="Port (logiciel)">port</wikipedia>), ils peuvent être utilisés pour échapper
à des <wikipedia name="Système de détection d'intrusion">IDS</wikipedia> naïfs, qui attendent ces numéros de
port à un décalage fixe. (Par exemple, si on utilise le
<link url="http://www.netfilter.org/documentation/HOWTO/netfilter-extensions-HOWTO-3.html#ss3.21">module u32</link> de
<wikipedia>Netfilter</wikipedia>.)</p>
<p>Une attaque en IPv4 commence souvent par un balayage
(<foreign>scan</foreign>) du réseau visé pour trouver des machines
intéressantes. En IPv4, il y a au maximum 2^32 adresses et balayer
tout le réseau est très court (on peut même balayer tout
l'Internet IPv4 relativement facilement). Les outils de hack
habituels savent faire cela sans mal (par exemple
<wikipedia>nmap</wikipedia> qui peut prendre comme cible une adresse
mais aussi un préfixe entier). En IPv6, 2^128 adresses est un nombre
énorme qui défie l'imagination. Est-ce que cela rend le balayage
impossible ? Non, comme l'a montré <link
url="http://www.maths.tcd.ie/~dwmalone/p/addr-pam08.pdf">un article
fameux de David Malone</link> et les <rfc num="5157"
local="true"/> et <rfc num="7707" local="true"/>. Malone a vu que les adresses IPv6 ne sont pas
réparties au hasard dans l'espace de 128 bits. Pour reprendre son
vocabulaire, certaines adresses sont <foreign>low-byte</foreign>
(<computer>2001:db8:67a::1</computer>), certaines
<foreign>wordy</foreign>
(<computer>2001:db8:67a::dead:beef</computer>), certaines
<foreign>port-based</foreign> (un serveur <wikipedia name="Hypertext Transfer Protocol">HTTP</wikipedia>
en <computer>2001:db8:67a::80</computer>). Si nmap ne met pas en œuvre les techniques suggérées
par le <rfc num="7707"
local="true"/>, l'outil scan6 de la boîte SI6 le fait. Mais d'abord,
un truc simple, <wikipedia name="ping (logiciel)">pinguer</wikipedia> l'adresse
<foreign><wikipedia>multicast</wikipedia></foreign> de toutes les
machines du réseau local :
<code>
% ping6 -I eth0 ff02::1
PING ff02::1(ff02::1) from fe80::ba27:ebff:feba:9094 eth0: 56 data bytes
64 bytes from fe80::ba27:ebff:feba:9094: icmp_seq=1 ttl=64 time=0.232 ms
64 bytes from fe80::f6ca:e5ff:fe4d:1f41: icmp_seq=1 ttl=64 time=0.809 ms (DUP!)
64 bytes from fe80::a2f3:c1ff:fec4:5b6e: icmp_seq=1 ttl=64 time=1.77 ms (DUP!)
64 bytes from fe80::f6ec:38ff:fef0:d6f9: icmp_seq=1 ttl=64 time=8.21 ms (DUP!)
64 bytes from fe80::223:8bff:fec9:48f2: icmp_seq=1 ttl=64 time=13.0 ms (DUP!)
64 bytes from fe80::215:afff:fe7d:3de5: icmp_seq=1 ttl=64 time=172 ms (DUP!)
</code>
On découvre ainsi bien des machines, sans dépendre de la façon dont
leurs adresses sont affectées. <wikipedia name="Microsoft Windows">Windows</wikipedia> ne
répond pas à ces paquets donc, ensuite, il faut passer à scan6 qui
utilise une combinaison de trucs (par exemple d'envoyer des paquets
avec une option IP inconnue, Windows, suivant la norme, répond alors qu'il ne connait pas) :
<code>
# scan6 -i eth1 -L
fe80::1a03:73ff:fe66:e568
fe80::f6ec:38ff:fef0:d6f9
fe80::a2f3:c1ff:fec4:5b6e
fe80::f6ca:e5ff:fe4d:1f41
fe80::ba27:ebff:feba:9094
fe80::223:8bff:fec9:48f2
fe80::215:afff:fe7d:3de5
</code>
(Vous avez noté la nouvelle, la
<computer>fe80::1a03:73ff:fe66:e568</computer> ?)
scan6 a plein d'options utiles, par exemple d'afficher les adresses
globales (et non plus locales au lien), et les <wikipedia name="Adresse MAC">adresses
MAC</wikipedia> :
<code>
# scan6 -i eth1 -L -e --print-type global
2001:db8:8ad9:84b1:7111:869b:5081:e0ed @ 18:03:73:66:e5:68
2001:db8:8ad9:84b1:: @ f4:ca:e5:4d:1f:41
2001:db8:8ad9:84b1:f6ec:38ff:fef0:d6f8 @ f4:ec:38:f0:d6:f8
2001:db8:8ad9:84b1:a2f3:c1ff:fec4:5b6e @ a0:f3:c1:c4:5b:6e
2001:db8:8ad9:84b1:ba27:ebff:feba:9094 @ b8:27:eb:ba:90:94
2001:db8:8ad9:84b1:223:8bff:fec9:48f2 @ 00:23:8b:c9:48:f2
2001:db8:8ad9:84b1:e4:323a:3c73:c537 @ 00:15:af:7d:3d:e5
</code>
</p>
<p>Cette technique ne marche que sur le réseau local. Mais scan6 peut
faire mieux. Revenons à la classification de Malone un instant. Dans
la même boîte à outils, address6 prend une adresse IP et détermine son
type :
<code>
% address6 -a  2001:7fe::80
unicast=global=global=embedded-port=unspecified

% address6 -a  2001:7fe::1
unicast=global=global=low-byte=unspecified

% address6 -a   2001:db8:2:25e::bad:dcaf
unicast=global=global=embedded-ipv4=unspecified

% address6 -a  2001:db8:8ad9:84b1:ba27:ebff:feba:9094
unicast=global=global=ieee-derived=b8-27-eb

% address6 -a  2001:db8:8ad9:84b1:7111:869b:5081:e0ed
unicast=global=global=randomized=unspecified
</code>
(Notez l'erreur de classification dans la troisième, qui aurait dû
être marquée <foreign>wordy</foreign>.) Pour les adresses IP dérivées
de l'<wikipedia>adresse MAC</wikipedia>, on n'a plus qu'à chercher
dans les bases de préfixes MAC pour savoir que la quatrième adresse
appartient à <link
url="http://hwaddress.com/mac/B827EB-000000.html">un Raspberry
Pi</link>. Enfin, la cinquième adresse est une adresse temporaire
(pour préserver la <wikipedia>vie privée</wikipedia>) du <rfc
num="8981" local="true"/>.</p>
<p>address6 peut aussi travailler sur un
ensemble d'adresses, pour en tirer des statistiques. Ainsi, si je
regarde les lecteurs IPv6 de ce blog (une population dont je ne
prétends pas qu'elle soit représentative de tout l'Internet) :
<code>
% zgrep -h -E  '^[0-9]+:' /var/log/apache2/access.log.2.gz /var/log/apache2/access.log.3.gz \
       /var/log/apache2/access.log.1 /var/log/apache2/access.log |\
   awk '{print $1}' | sort | uniq | address6 -i -s
...
** IPv6 Interface IDs **

Total IIDs analyzed: 172
IEEE-based:      27 (15.70%)            Low-byte:             46 (26.74%)
Embed-IPv4:      10 (5.81%)             Embed-IPv4 (64):       7 (4.07%)
Embed-port:       2 (1.16%)             Embed-port (r):        0 (0.00%)
ISATAP:           0 (0.00%)             Byte-pattern:          2 (1.16%)
Randomized:      78 (45.35%)
</code>
Contrairement aux résultats de Malone en <wikipedia>2008</wikipedia>,
on voit une majorité d'adresses temporaires pseudo-aléatoires (<rfc
num="8981" local="true"/>). La sécurité progresse donc (une étude
analogue sur les clients du site Web de l'<wikipedia name="Internet Society">ISOC</wikipedia>
a montré la même chose). Ici, il s'agit
de clients <wikipedia name="Hypertext Transfer Protocol">HTTP</wikipedia> donc probablement des machines
individuelles. Si on teste sur un tout autre échantillon, les serveurs
de noms des <wikipedia name="Domaine de premier niveau">TLD</wikipedia>, on a un résultat bien
différent :
<code>
% grep : root.zone | awk '{print $5}' | sort | uniq | address6 -i -s
...
** IPv6 Interface IDs **

Total IIDs analyzed: 486
IEEE-based:       2 (0.41%)             Low-byte:            350 (72.02%)
Embed-IPv4:       7 (1.44%)             Embed-IPv4 (64):      56 (11.52%)
Embed-port:      62 (12.76%)            Embed-port (r):        0 (0.00%)
ISATAP:           0 (0.00%)             Byte-pattern:          6 (1.23%)
Randomized:       3 (0.62%)
</code>
On a cette fois une grande majorité de <foreign>low byte</foreign> et
de <foreign>embedded port</foreign> (beaucoup de ces serveurs ont une
adresse IPv6 se terminant par <computer>::53</computer>). C'est
normal, ces serveurs sont publics, ils n'ont pas à se cacher. Même
chose lorsqu'on fait tourner address6 sur des listes comme celle des
serveurs <wikipedia name="Alexa Internet">Alexa</wikipedia>. Et sur des machines qui sont
parfois des clients finaux et parfois des serveurs, les résolveurs
<wikipedia name="Domain Name System">DNS</wikipedia> qui interrogent
<computer>d.nic.fr</computer>, un serveur de
<computer><wikipedia>.fr</wikipedia></computer> ? Le résultat est
logiquement entre les deux :
<code>
** IPv6 Interface IDs **

Total IIDs analyzed: 8756
IEEE-based:    1825 (20.84%)            Low-byte:           4570 (52.19%)
Embed-IPv4:      79 (0.90%)             Embed-IPv4 (64):     211 (2.41%)
Embed-port:     135 (1.54%)             Embed-port (r):       28 (0.32%)
ISATAP:           0 (0.00%)             Byte-pattern:         82 (0.94%)
Randomized:    1826 (20.85%)
</code>
</p>
<p>Armé de cette connaissance, on peut revenir au problème du
balayage. En IPv4, l'espace est tellement petit que l'algorithme le
plus simple (la force brute) est le meilleur. En IPv6, il faut être
plus subtil. À la <wikipedia name="Bataille navale (jeu)">bataille navale</wikipedia>, on n'essaie
pas toutes les cases séquentiellement. On ne le fait pas non plus
aléatoirement. On frappe en fonction des règles qu'on connait sur les
bateaux et leurs positions. C'est ce que fait scan6, qui peut balayer
un réseau distant avec plus d'intelligence que les balayeurs IPv4. Un
avertissement toutefois : en pratique, je trouve les résultats
décevants. Comme l'explique le <rfc num="7707" local="true"/>, le
balayage est <emphasis>possible</emphasis> en IPv6. Mais il est lent,
laborieux, et pas toujours réussi. Voici un exemple qui a marché :
<code>
# scan6 -v -i eth1 -d 2001:db8:2:25e::/64 
Target address ranges (1)
2001:db8:2:25e:0-ffff:0-ffff:0-ffff:0-ffff

Alive nodes:
2001:db8:2:25e::42
...
</code>
Mais, en pratique, outre une patience d'ange, vous aurez souvent besoin
d'aider l'outil. Par exemple, si vous connaissez le type de cartes
Ethernet utilisé (beaucoup d'entreprises utilisent un seul modèle
d'ordinateurs et donc peu de modèles de cartes), vous pouvez guider
l'outil avec cette information (<computer>-K Apple</computer> pour se
limiter aux ordinateurs <wikipedia>Apple</wikipedia>, <computer>-k
52:54:00</computer> pour une plate-forme de
<wikipedia>virtualisation</wikipedia>, où on connait le préfixe
utilisé pour numéroter les cartes). Vous pouvez également guider scan6
avec des options comme <computer>--tgt-low-byte</computer> (ne
chercher que les adresses de type <foreign>low byte</foreign>) :
<code>
# scan6 -i eth1 -v -d fc00:675:ab4:2::/64 --tgt-low-byte -r 200pps                                                
Target address ranges (1)
fc00:675:ab4:2:0:0:0-100:0-1500

Alive nodes:
fc00:675:ab4:2::1
fc00:675:ab4:2::4:1
fc00:675:ab4:2::4:5
...
</code>
Notez que les adresses ayant les deux derniers octets non nuls sont
également trouvées (mais plus lentement : scan6 commence par ce qui est
facile). Notez l'intervalle testé (affiché par
<computer>-v</computer>), syntaxe que vous pouvez aussi utiliser en
entrée pour indiquer quelles adresses doivent être essayées.
Notez aussi l'option de limitation de trafic <computer>-r
200pps</computer>. Ce n'est pas seulement pour éviter d'être détecté,
c'est aussi parce qu'un trafic trop important peut dépasser les
capacités du réseau en face et donc vous ralentir. Enfin,
rappelez-vous qu'un balayage peut vous conduire dans un réseau taquin
comme le <computer>2404:6800:4004:802::/64</computer> où
<emphasis>toutes</emphasis> les adresses répondent (il n'y a
certainement pas 2^64 machines, plutôt un routeur qui répond pour tout
le monde).
</p>
<p>Le code source de scan6 est également instructif. Lorsqu'on balaye,
tous les paquets n'atteignent pas leur destination. Un balayeur
typique va donc stocker toutes les adresses en cours de test dans un
tableau, notant au fur et à mesure lesquelles ont marché. Une telle
mise en œuvre serait catastrophique en IPv6 (un tableau de 2^64
entrées...). scan6 balaye donc sans redondance (un seul paquet, ne
garde que les résultats positifs en mémoire), balaye une seconde fois
et fusionne les résultats, et ainsi de suite.</p>
<p>Autre méthode pour découvrir les machines dans un réseau, par
l'énumération DNS. Il « suffit » de faire des requêtes
<wikipedia name="Domain Name System" anchor="PTR_record">PTR</wikipedia> pour les adresses vraisemblables
(rappelez-vous bien que les adresses ne sont pas attribuées au
hasard). Un outil dans la boîte THC permet cela facilement. On lui
donne un résolveur DNS et un préfixe :
<code>
% dnsrevenum6 127.0.0.1 fc00:675:ab4:2::/64        
Starting DNS reverse enumeration of fc00:675:ab4:2:: on server 127.0.0.1
...
Found: fc00:675:ab4:2::4:1 is ns1.foobar.example.
...
Found: fc00:675:ab4:2::4:12 is mx4.foobar.example.
Found: fc00:675:ab4:2::4:13 is mx5.foobar.example.
...
Found: fc00:675:ab4:2::4:20 is web.foobar.example.
...
</code>
</p>
<p>Autre problème de sécurité, le suivi d'une machine. Dès qu'on a une
adresse IP stable (ou dont une partie est stable), elle peut être
utilisée pour vous suivre à la trace. La solution évidente (et
recommandée par le <rfc num="8981" local="true"/>) est d'avoir des
adresses qui ne sont pas stables, mais qui sont regenérées au hasard
de temps en temps. Parfois, c'est trop radical. On peut avoir envie
d'adresses stables dans le temps mais par destination (toujours la
même adresse quand on parle à <wikipedia>Google</wikipedia>, toujours
la même quand on parle à <wikipedia name="Amazon.com">Amazon</wikipedia> mais différente
de celle utilisée pour Google, pour ne pas permettre des
rapprochements). Cela peut se faire en
<wikipedia name="Fonction de hachage" anchor="Applications_en_cryptographique">condensant</wikipedia> un secret local avec le préfixe de
la destination (<rfc num="7217" local="true"/>).</p>
<p>Bien, passons maintenant à un sujet toujours rigolo et qui offre
plein de perspectives de bogues, la
<wikipedia xml:lang="en" name="IP fragmentation">fragmentation</wikipedia>. On peut la déclencher facilement
en tenant d'envoyer 2 000 octets sur un Ethernet où la
<wikipedia name="Maximum Transmission Unit">MTU</wikipedia> est à 1 500 :
<code>
% ping6 -c 1 -s 2000  2001:5c0:1400:a::56d

% tcpdump ...
08:07:30.906552 ip: (hlim 54, next-header Fragment (44) payload length: 1240) \
        2001:db8:8ad9:84b1:ba27:ebff:feba:9094 > 2001:5c0:1400:a::56d: \
        frag (0x2fe73a49:0|1232) ICMP6, echo request, length 1232, seq 1
08:07:30.913604 ip: (hlim 54, next-header Fragment (44) payload length: 784) \
        2001:db8:8ad9:84b1:ba27:ebff:feba:9094 > 2001:5c0:1400:a::56d: \
	frag (0x2fe73a49:1232|776)
</code>
On voit les deux fragments, de 1 240 et 784 octets. Le premier
contenait l'en-tête <wikipedia name="Internet Control Message Protocol">ICMP</wikipedia>, autorisant tcpdump à
afficher de l'information. Quelles sont les conséquences en sécurité ?
Exactement les mêmes qu'en IPv4. Comme souvent, IPv6 étant juste une
nouvelle version d'IP, les problèmes de sécurité sont très proches
entre les deux versions :
<enum>
<item>Un attaquant peut envoyer des fragments d'un datagramme
incomplet. La cible va les stocker en attendant d'avoir tout et on
peut ainsi l'empêcher de recevoir les vrais paquets (le réassemblage
après fragmentation ne peut pas être sans état).</item>
<item>Chaque fragment indique sa position dans le
<wikipedia>datagramme</wikipedia> original et sa longueur (0|1232 pour
le premier fragment ci-dessus et 1232|776 pour le second). Des
fragments qui se recouvrent sont possibles.</item>
</enum>
</p>
<p>Certaines attaques sont plus faciles si on peut prédire
l'identificateur de fragment utilisé (0x2fe73a49 dans l'exemple
ci-dessus). Cette prévisibilité permet par exemple l'<foreign>idle
scan</foreign> où une machine fait un balayage des
<wikipedia name="Port (logiciel)">ports</wikipedia> ouverts sans se révéler à la cible : le balayeur usurpe
l'adresse IP source d'une tierce machine et lui demande ses identificateurs de
fragment pour voir quelles réponses elle a reçu. L'outil frag6 de la boîte SI6 permet de voir si ces
identificateurs sont prévisibles :
<code>
# frag6   --frag-id-policy  -i eth1 -d  2001:db8:8ad9:84b1:1a03:73ff:fe66:e568                                    
Identifying the 'Fragment ID' generation policy of the target node....
Fragment ID policy: Per-destination IDs with increments of 1 (sdev: 0.000000)
</code>
Ici (la cible est un noyau Linux 3.2), les identificateurs sont
prévisibles mais pour un même pair (PDC : <foreign>Per Destination
Counter</foreign>). frag6 teste avec deux adresses IP source
différentes pour voir cela (utilisez <computer>-vv</computer> pour
voir les identificateurs reçus en mono-adresse et en multi-adresses). La sécurité n'est donc pas menacée, un
attaquant aveugle (non situé sur le chemin des paquets) ne peut donc
pas prévoir quel sera l'identificateur du prochain fragment. Avec une
machine FreeBSD, les identificateurs sont aléatoires, ce qui va aussi :
<code>
Fragment ID policy: Randomized IDs (Avg. inc.: 2497753097, sdev: 1449618001.141603)
</code>
Par contre, les anciens noyaux Linux avaient des identificateurs
complètement prévisibles (compteur global et pas par destination) :
<code>
Fragment ID policy: Global IDs with increments of 1 (sdev: 0.500000)
</code>
(Attention, dès qu'il y a un routeur sur le trajet, frag6 a du mal à
choisir correctement sa propre adresse IP source et vous avez intérêt
à utiliser l'option <computer>-s</computer> pour l'aider). 
</p>
<p>Et les autres attaques utilisant la fragmentation ? Par exemple, pour tenter un
<wikipedia name="Attaque par déni de service">déni de service</wikipedia> en remplissant la table des
fragments en attente de réassemblage, on peut injecter autant de
fragments incomplets qu'on veut avec <computer>--flood-frags</computer> :
<code>
# frag6 -v  --flood-frags 10000  -i eth0 -l -v -d  fc00:1::a00:27ff:fef7:5cd2
</code>
Mais, désolé de vous décevoir, cela ne marche plus avec les systèmes
modernes, qui gèrent leur table proprement.</p>
<p>Bon, maintenant, passons aux attaques contre
<wikipedia name="Neighbor Discovery Protocol">NDP</wikipedia>, le protocole de découverte des voisins en
IPv6, normalisé dans le <rfc num="4861" local="true"/>. Comme avec
<wikipedia name="Address Resolution Protocol">ARP</wikipedia> en IPv4, rien
n'est authentifié (ce qui est normal : on ne peut pas avoir à la fois
sécurité et simplicité d'usage). On peut donc en théorie, lorsqu'on
voit une requête <foreign>neighbor solicitation</foreign>, répondre à
la place de la machine légitime par un <foreign>neighbor
advertisement</foreign> avec sa propre adresse MAC (et capter ainsi
tout le trafic) ou avec une adresse bidon (et faire ainsi un
<wikipedia name="Attaque par déni de service">déni de service</wikipedia>). Je dis « en théorie » car
Fernando Gont note qu'une telle attaque marche mal. Il suggère de
faire plutôt du <foreign>neighbor
advertisement</foreign> gratuit (émis spontanément, pas en réponse à
un <foreign>neighbor solicitation</foreign>). Attention, cela ne
marche que sur le réseau local car les machines refusent les paquets
NDP dont le <foreign>hop limit</foreign> est inférieur à 255 (cf. <rfc
num="5082" local="true"/>). L'outil na6 permet cela (ici, l'adresse
MAC bidon <computer>1:2:3:4:5:6</computer>) :
<code>
# na6 -i eth0 -t 2001:db8:8ad9:84b1:ba27::1 -d ff02::1 -o -E 1:2:3:4:5:6 -v -l
</code>
Notez qu'on a envoyé ce paquet NDP à toutes les machines du réseau
local (<computer>-d ff02::1</computer>). Sur une machine Linux,
l'entrée n'apparait pas immédiatement lors d'un <computer>ip -6
neighbor show</computer> mais, si on tente de joindre cette machine,
on verra bien l'adresse MAC empoisonnée :
<code>
% ip -6 neighbor show
2001:db8:8ad9:84b1:ba27::1 dev eth0 lladdr 01:02:03:04:05:06 DELAY
</code>
(Sur un <wikipedia name="Berkeley Software Distribution">BSD</wikipedia>, cela serait <computer>ndp
-an</computer>.) Ironiquement, l'attaque par déni de service peut
quand même échouer, si le <wikipedia name="Commutateur réseau">commutateur</wikipedia> relaie
tous les paquets et que la machine cible a mis ses interfaces en mode
<foreign>promiscuous</foreign>. Un attaquant qui veut lire le trafic
d'une machine sans être détecté peut aussi indiquer comme adresse MAC
une adresse de <wikipedia name="Broadcast (informatique)">diffusion</wikipedia>...</p>
<p>Comment combat-on cette attaque ? Une solution est de mettre des
entrées statiques dans la table des voisins. (Cette technique est
conseillée dans les documents remis aux participants à des conférences
de sécurité comme <link
url="http://www.nosuchcon.org/">NoSuchCon</link> ou comme celle du
<link url="http://www.ccc.de/">CCC</link>, documents qui indiquent
l'adresse MAC du routeur officiel. Certes, c'est pour IPv4
mais rappelez-vous que le problème est exactement le même pour IPv4 et
IPv6.) Sur un BSD, cela se fait avec <computer>ndp -s IPV6ADDR
MACADDR</computer> et sur un Linux avec <computer>ip -6 neighbor add
IPV6ADDR lladdr MACADDR dev NETWORKIFACE</computer>.</p>
<p>Passons maintenant à un autre protocole utilisant ICMP v6 :
<foreign>Router Discovery</foreign>. C'est grâce à lui qu'une machine
apprend le préfixe d'adresses utilisé sur le réseau, ainsi que le ou
les routeurs en usage. rdisc6 (qui fait partie du paquetage ndisc6
qu'on trouve déjà fait pour tous les bons Unix) permet de voir ces
informations (ici, le routeur est une <wikipedia>Freebox</wikipedia>) :
<code>
% rdisc6 eth0
Soliciting ff02::2 (ff02::2) on eth0...

Hop limit                 :           64 (      0x40)
Stateful address conf.    :           No
Stateful other conf.      :           No
Mobile home agent         :           No
Router preference         :       medium
Neighbor discovery proxy  :           No
Router lifetime           :         1800 (0x00000708) seconds
Reachable time            :  unspecified (0x00000000)
Retransmit time           :  unspecified (0x00000000)
 Prefix                   : 2001:db8:8ad9:84b1::/64
  On-link                 :          Yes
  Autonomous address conf.:          Yes
  Valid time              :        86400 (0x00015180) seconds
  Pref. time              :        86400 (0x00015180) seconds
 Recursive DNS server     : 2a01:e00::2
 Recursive DNS server     : 2a01:e00::1
  DNS servers lifetime    :          600 (0x00000258) seconds
 MTU                      :         1480 bytes (valid)
 Source link-layer address: F4:CA:E5:4D:1F:41
 from fe80::f6ca:e5ff:fe4d:1f41
</code>
La Freebox a donc indiqué que le préfixe de ce réseau est
<computer>2001:db8:8ad9:84b1::/64</computer>, que le routeur est
elle-même, <computer>fe80::f6ca:e5ff:fe4d:1f41</computer>, qu'il y a
deux résolveurs DNS (cette option est décrite dans le <rfc num="8106"
local="true"/>) et que la <wikipedia name="Maximum Transmission Unit">MTU</wikipedia> est de seulement
1 480 octets (<wikipedia name="Free (société)">Free</wikipedia> utilise le
<wikipedia>6rd</wikipedia> du <rfc num="5969" local="true"/>, une
technique de <wikipedia name="Tunnel (réseau informatique)">tunnel</wikipedia>, qui diminue donc la
MTU).</p>
<p>L'outil ra6 permet de générer des <foreign>router
advertisement</foreign> de tous les genres, y compris pour une
attaque (cf. <rfc num="6104" local="true"/>). Par exemple, un <foreign>router
advertisement</foreign> donnant une <foreign>hop limit</foreign>
maximale de 1 (<computer>-s</computer> est l'adresse du routeur, qu'on
va usurper) :
<code>
# ra6 -i eth1 -s fe80::f6ca:e5ff:fe4d:1f41 -d fe80::ba27:ebff:feba:9094 -c 1 -v
</code>
Lorsque <computer>fe80::ba27:ebff:feba:9094</computer> reçoit ce
paquet :
<code>
15:28:35.732604 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 16) \
        fe80::f6ca:e5ff:fe4d:1f41 > fe80::ba27:ebff:feba:9094: \
        [icmp6 sum ok] ICMP6, router advertisement, length 16 \
        hop limit 1, Flags [none], pref high, router lifetime 9000s, \
        reachable time 4294967295s, retrans time 4000s
</code>
Il ne peut plus joindre les machine situées à plus d'une étape de distance :
<code>
% ping6 -n www.dns-oarc.net
...
64 bytes from 2001:4f8:3:2bc:1::8: icmp_seq=10 ttl=58 time=175 ms
64 bytes from 2001:4f8:3:2bc:1::8: icmp_seq=11 ttl=58 time=302 ms
64 bytes from 2001:4f8:3:2bc:1::8: icmp_seq=12 ttl=58 time=181 ms
From 2001:db8:8ad9:84b1:: icmp_seq=13 Time exceeded: Hop limit
From 2001:db8:8ad9:84b1:: icmp_seq=14 Time exceeded: Hop limit
From 2001:db8:8ad9:84b1:: icmp_seq=15 Time exceeded: Hop limit
</code>
ra6 permet aussi d'envoyer de faux RA (<foreign>router
advertisement</foreign>) ayant une MTU ridiculement basse (la plupart
des systèmes refuseront les valeurs trop faibles, toutefois).</p>
<p>Comment empêcher ces attaques <foreign>neighbor discovery</foreign>
et <foreign>router discovery</foreign> ? Outre des logiciels de
supervision comme <link url="http://ndpmon.sourceforge.net/">NDPmon</link>, la meilleure solution est
équivalente à ce qui se fait en IPv4 : que le
<wikipedia name="Commutateur réseau">commutateur</wikipedia> Ethernet refuse les paquets RA
venant sur un port où il n'est pas censé y avoir de routeur. Cette
solution est décrite plus en détail, sous le nom de <foreign>RA
Guard</foreign>, dans le <rfc num="6105" local="true"/>.</p>
<p>L'atelier de Fernando Gont couvrait également les attaques en
<wikipedia>couche 4</wikipedia> ou <wikipedia>couche 7</wikipedia> où
il y a évidemment peu ou pas de différences avec IPv4. Il y a eu aussi
une discussion sur l'importance des <wikipedia name="Pare-feu (informatique)">pare-feux</wikipedia>
en IPv6 et la question de savoir si <link local="nat-et-securite">le
NAT apporte de la sécurité du NAT</link> ou pas, point sur lequel Gont
conseille de ne pas tenter le diable : comme on n'est pas sûr des
machines du réseau local, il vaut mieux mettre un pare-feu à état qui
bloque, par défaut, les connexions entrantes. (Le <rfc num="6092"
local="true"/> a un point de vue différent.)</p>
<p>J'ai fait moi-même un exposé (bien plus court et sans travaux
pratiques) <link local="ipv6-securite">sur la sécurité d'IPv6</link>.</p>
</content>
</entry>
