Zugehörigkeit von IPv6- und MAC-Adressen speichern
In gängigen IPv4-Netzwerken sorgt der DHCP-Server für die Vergabe von IPv4-Adressen und speichert dabei auch die jeweiligen MAC-Adressen der Clients ab. Dadurch kann zu einem späteren Zeitpunkt nachvollzogen werden, welches Gerät (Benutzer) welche IPv4-Adresse hatte. Bei IPv6 hingegen wird oft die automatische Adressvergabe via SLAAC (Stateless Address Autoconfiguration) verwendet. Dabei werden nicht mehr per se die MAC-Adressen der Clients gespeichert. Eine nachträgliche (forensische) Analyse ist somit nicht direkt möglich.
Ein einfacher Ansatz zur Lösung dieses Problems ist es, mit einem Packet Sniffer im jeweiligen Netzwerksegment die "Duplicate Address Detection" (DAD) ICMPv6-Nachrichten von allen neuen IPv6-Clients mitzuschneiden um somit eine Liste der verwendeten IPv6-Adressen inkl. der entsprechenden MAC-Adressen zu erstellen.
Kernproblem: Wer hatte wann welche IPv6-Adresse?
Bei der Analyse von Firewall-Logs sieht man klassisch nur die reine IPv6-Adresse der jeweiligen Source und Destination. Möchte man nun herausfinden, welche Person oder welcher Host sich hinter der Adresse verbirgt, braucht man mehr Informationen als die reine IPv6-Adresse. Typische Szenarien für eine genauere Analyse könnten dabei sein:
- Zugriff auf eine unerlaubte Ressource innerhalb eines Netzwerks
- Illegales Verhalten im Internet
- Malware-Callback von einem Prozess auf einem Rechner
IPv6-Adressen werden an Clients entweder per "stateful DHCPv6" vergeben oder per automatischer Adressvergabe SLAAC. In beiden Fällen werden die MAC-Adressen nicht gespeichert, da der DHCPv6-Server die Rechner über die DUID (DHCP Unique IDentifier) identifiziert, während für SLAAC gar keine Kommunikation mit einem zentralen Server stattfindet.
Ansatz: Speichern der DAD-Nachrichten
Wenn ein Rechner eine neue IPv6-Adresse benutzen möchte, schickt er zunächst eine Duplicate Address Detection an die Solicited Node Multicast Adresse seiner selbst erzeugten IPv6-Adresse (also quasi "an sich selbst") um zu sehen, ob nicht schon ein anderer Host diese IPv6-Adresse verwendet. Das müssen auch manuell vergebene IPv6-Adressen tun (RFC 4862, Section 5.4, "MUST be performed on all unicast […]" [1]). Die meisten einfachen Switches leiten diese DAD-Nachrichten an alle Ports weiter, da sie keine Listen über die Multicast Listener pro Port führen. Sprich: Obwohl es ein Multicast-Paket ist, leitet der Switch es an alle seine Ports weiter.
Im Normalfall antwortet niemand auf diese DAD-Nachrichten, da die IPv6-Adressen entweder anhand der MAC-Adressen gebaut wurden (EUI-64), randomisiert sind (Windows) oder per Privacy Extensions erzeugt wurden. In allen Fällen sollte eine Dopplung nicht vorkommen. Ausnahme: Bei einer manuellen Vergabe von IPv6-Adressen.
Hinweis: Das Speichern der IPv6-MAC-Bindings ist ohnehin nur für legitime Clients interessant. Ein Angreifer im Netzwerk hat die Möglichkeit, die MAC-Adresse zu verändern, was die Identifizierung des Users ohnehin schier unmöglich macht.
Der Ansatz für das Eingangsproblem ist nun: Ein Server im Layer-2 Netz speichert alle eintreffenden DAD-Nachrichten. In diesen stehen die sendende MAC-Adresse sowie die Target-IPv6-Adresse, wodurch man beide Komponenten plus einen Zeitstempel zur Verfügung hat.
Die DAD-Nachrichten sind eindeutig bestimmbar, da es nur und immer "Neighbor Solicitations" mit einer Source-IPv6-Adresse von "::" sind. Die MAC-Adresse des Clients ist in der Source des Ethernet Frames zu erkennen, während die "Target Address" der Neighbor Solicitation die zukünftige IPv6-Adresse des Clients sein wird. Der folgende Screenshot zeigt die Analyse einer DAD-Nachricht mit Wireshark. Man erkennt sowohl die Source-MAC-Adresse sowie die zukünftige IPv6-Adresse des Hosts:
Tcpdump Skript & Auswertung
Zur Speicherung der DAD-Nachrichten kann ein beliebiger Linux-Host mit installiertem Tcpdump verwendet werden. Es sollte allerdings eine zweite Netzwerkkarte verwendet werden, auf der nur gelauscht wird. Beispielsweise kann auf einem Debian System auf dem Interface eth1 der komplette IPv6-Verkehr wie folgt deaktiviert werden:
sudo sysctl -w net.ipv6.conf.eth1.disable_ipv6=1
Der Tcpdump Filter für DAD-Nachrichten sieht folgendermaßen aus:
ip6[40]=135 and src host ::
Sprich: IPv6-Pakete mit dem ICMPv6 Type 135 (Neighbor Solicitation), sowie einer Source-Adresse von "::". Der vollständige Tcpdump-Befehl, der automatisch alle 24 h ein neues Logfile anlegt, sieht entsprechend so aus:
tcpdump -i eth1 -G 86400 -w '/var/log/dad/dad_%Y-%m-%d.pcap' 'ip6[40]=135 and src host ::'
Die gespeicherten Nachrichten können später einfach ausgelesen und in eine Textdatei geschrieben werden:
tcpdump -e -n -tttt -r dad_2015-01-19.pcap > dad_2015-01-19.txt
Die Log Einträge sehen dann so aus:
2015-01-09 12:21:48.026418 90:18:7c:da:81:46 > 33:33:ff:da:81:46, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:ffda:8146: ICMP6, neighbor solicitation, who has fe80::9218:7cff:feda:8146, length 24 2015-01-09 12:22:45.632341 90:18:7c:da:81:46 > 33:33:ff:da:81:46, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:ffda:8146: ICMP6, neighbor solicitation, who has fe80::9218:7cff:feda:8146, length 24 2015-01-09 12:28:42.093714 40:b0:fa:6e:ed:87 > 33:33:ff:6e:ed:87, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:ff6e:ed87: ICMP6, neighbor solicitation, who has fe80::42b0:faff:fe6e:ed87, length 24 2015-01-09 12:28:43.283808 40:b0:fa:6e:ed:87 > 33:33:ff:f6:11:99, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:fff6:1199: ICMP6, neighbor solicitation, who has 2001:db8:cafe:face:903d:81ad:64f6:1199, length 24 2015-01-09 12:28:43.764744 40:b0:fa:6e:ed:87 > 33:33:ff:6e:ed:87, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:ff6e:ed87: ICMP6, neighbor solicitation, who has 2001:db8:cafe:face:42b0:faff:fe6e:ed87, length 24 2015-01-09 12:32:04.173900 d4:20:6d:dc:82:89 > 33:33:ff:dc:82:89, ethertype IPv6 (0x86dd), length 78: :: > ff02::1:ffdc:8289: ICMP6, neighbor solicitation, who has 2001:db8:cafe:face:d620:6dff:fedc:8289, length 24
Die Zeilen 3-5 zeigen zum Beispiel, dass die MAC-Adresse "40:b0:fa:6e:ed:87" insgesamt drei IPv6-Adressen erzeugt hat: Eine link-local IPv6-Adresse (fe80::) sowie zwei global unicast IPv6-Adressen (2001:db8::), wobei eine davon der MAC-Adresse per EUI-64 entspringt (ff:fe in der Mitte), während die andere per Privacy Extensions erzeugt worden ist.
Um die MAC-Adresse für eine gegebene IPv6-Adresse herauszufinden, kann man die Logfiles einfach per "grep" oder ähnlichen Befehlen durchsuchen:
cat dad_2015-01-19.txt | grep 2001:db8:cafe:face:c09:863b:fe6a:3a9b
Gleichermaßen kann man auch nach einer MAC-Adresse suchen um herauszufinden, welche und wie viele IPv6-Adressen von diesem Client erzeugt worden sind:
cat dad_2015-01-19.txt | grep 40:b0:fa:6e:ed:87
Verlässlichkeit der DAD-Nachrichten
Interessant ist natürlich die Frage nach der Verlässlichkeit dieser Variante. Also wie viele IPv6-MAC-Address-Bindings wirklich gespeichert werden. Da in dem entsprechenden RFC eindeutig die Rede davon ist, dass jeder Client die DAD-Nachrichten schicken muss, könnte man von einer 100 Prozent-Abdeckung ausgehen.
Um das herauszufinden wurde ein Versuch über einen Zeitraum von einem Monat durchgeführt: Der IPv6-Verkehr eines Gästenetzwerks (WLAN) in einem mittelständischen Unternehmen wurde sowohl an dem Übergang zum Internet (Firewall) als auch per eben vorgestelltem Tcpdump-Skript ausgewertet. Die Analyse zeigte folgende Werte (s. a. Abb.3):
- 117 MAC-Adressen in den DAD Logs
- 3047 IPv6-Adressen in den DAD Logs
- 1235 IPv6-Adressen in den Firewall Logs
- --> 10 IPv6-Adressen in den Firewall Logs welche NICHT in den DAD Logs vorhanden waren
Das Ergebnis zeigt, dass lediglich 10 von 1235 IPv6-Adressen nicht per DAD-Nachrichten erkannt wurden. Dies sind 0,8 Prozent. Im Worst Case, also wenn alle fehlenden IPv6-Adressen von verschiedenen MAC-Adressen erzeugt worden wären, würden allerdings 10 von 127 MAC-Adressen fehlen, was 7,8 Prozent entspräche. Es ist aber davon auszugehen, dass lediglich ein paar Clients (= MAC-Adressen) diese 10 IPv6-Adressen erzeugt haben.
Als einfacher Lösungsansatz lässt sich diese Methode per Tcpdump-Skript mit einer Fehlerrate von ungefähr 1 Prozent also durchaus einsetzen.
Adressstatistiken
Obwohl es mit dem eigentlichen Problem nichts zu tun hat, lässt sich durch die DAD-Logs relativ einfach eine Adressstatistik erstellen. So kann man beispielsweise die Anzahl der MAC- sowie der IPv6-Adressen (getrennt in Link-Local und Global Unicast) zählen. Die genauen Befehle dazu sind am Ende des Artikels in den Links hinterlegt. In dem oben erwähnten Mitschnitt der DAD-Nachrichten über einen Monat sah die Statistik wie folgt aus (s. Abb.4).
Man kann gut erkennen, dass etwa die Hälfte der Link-Local-Adressen per randomisierten Interface-IDs erzeugt wurden. Vermutlich sind dies alles Windows-Geräte, da diese per Default ihre Interface-IDs zufällig generieren. Die andere Hälfte erzeugt die Adressen klassisch per EUI-64 unter Verwendung der MAC-Adresse. Wieso die Anzahl der Link-Local-Adressen höher ist als die der MAC-Adressen lässt sich nicht direkt klären.
Ebenfalls gut erkennen lässt sich die flächendeckende Nutzung der Privacy Extensions für Global Unicast IPv6-Adressen. Der Bärenanteil dieser Adressen (Interface-IDs) ist zufällig generiert.
Nachteile und Alternativen
Der hier vorgestellte Ansatz speichert nur die DAD-Nachrichten aus dem einen Layer-2-Netz, in dem der Linux-Host hängt. Für mehrere Netze bräuchte man jeweils einen neuen Sniffer, bzw. eine eigene Netzwerkkarte. Zusätzlich hat die Analyse der DAD-Nachrichten gezeigt, dass nicht 100 Prozent aller IPv6-Adressen gespeichert werden. Ob das für die Produktivsetzung ausreicht, muss der jeweilige IT-Admin selbst entscheiden.
Des Weiteren gibt es die Möglichkeit, dass einzelne Logs falsch sind, nämlich dann, wenn die Duplicate Address Detection fehlschlägt: Wenn PC-2 eine IPv6-Adresse anfragt, die PC-1 bereits besitzt, so speichert das Tcpdump-Skript diese IPv6-Adresse mit der MAC-Adresse von PC-2 (!) ab, obwohl er sie gar nicht bekommt. Da der Logeintrag von PC-1 ebenfalls vorhanden sein sollte, kann man diesen Fehler zumindest erkennen. Man muss in diesem Fall aber bei der Auswertung der Logs aufpassen.
Alternative Methoden für die Zusammenführung von IPv6- und MAC-Adressen wären folgende:
- Gesnifft werden muss am besten am Switch selber, da dieser 100 Prozent des Netzwerkverkehrs sieht. Das heißt, er kann zu jedem IPv6-Paket die MAC-Adresse des Ethernet-Frames auswerten. Die entsprechenden Features heißen unter anderem: IPv6 Guard, IPv6 Snooping, IPv6 Neighbor Discovery Inspection, usw.
- Tools, die sich diesem Problem annehmen sind unter anderem: NDPMon [2], SLAACer [3] oder ipv6mon [4]
- Router Neighbor Cache auslesen: Ein automatisches Auslesen des Caches in kürzeren Intervallen als das automatische Entfernen von Einträgen würde ebenfalls alle MAC-Adressen zum Vorschein bringen. Nachteil: Der Neighbor Cache im Router enthält keine Einträge für Kommunikationspartner innerhalb eines Subnetzes.
Fazit
Der hier vorgestellte Lösungsansatz ist ein relativ einfaches Skript (Einzeiler), welches auf einem beliebigen Linux Host (Raspberry Pi?) ausgeführt werden kann. Ob es bei einer Quote von 99 Prozent im Security-Umfeld eingesetzt werden sollte, bleibt offen. Auch ist die Limitierung auf ein einzelnes Layer-2 Subnetz ungünstig.
Dieser Artikel ist eine Zusammenfassung dreier Blogposts, welche die Grundlagen der DAD-Nachrichten sowie die verwendeten Linux-Befehle detailliert erläutern:
[1] IETF: rfc4862
[2] NDPMon
[3] SLAACer
[4] ipv6mon