Blog ·
Ein Schwachstellenscanner sollte null Bytes senden
Die Grenze zwischen Prüfung und Angriff sind die Bytes auf der Leitung. Wie aus diesem Versprechen eine Zahl wird, an der Tests scheitern, mit Messwerten.
Von Provibr
Wenn Sie Infrastruktur für andere Leute betreiben, wollen Sie irgendwann wissen, ob Port 3306 auf einer der Maschinen Ihrer Kunden dem ganzen Internet antwortet. Das ist eine vernünftige Frage, der Kunde will die Antwort haben, und in dem Moment, in dem Sie nachsehen, sind Sie zu einer Partei geworden, die unaufgeforderten Verkehr an eine Maschine schickt, die unter dem Vertrag von jemand anderem steht.
Was das von einem Einbruch trennt, ist nicht Ihre Absicht, und es ist kein Ankreuzfeld in Ihren Geschäftsbedingungen. Es ist das, was den Socket tatsächlich verlassen hat. Alles andere ist eine Erzählung darüber, was den Socket verlassen hat.
Wir haben kürzlich eine Prüfung auf Angriffsfläche in unseren Agenten eingebaut, mit einer Regel, die als Satz in einem Entwurfsdokument begann: keine verändernde Abfrage senden, keinen Anmeldeversuch, keine Standardzugangsdaten, keine Exploit-Nutzlast, kein breites Absammeln von Bannern. So ist aus diesem Satz etwas geworden, an dem ein Test scheitern kann, und so viel kosten die daraus entstandenen Sonden in Bytes.
Ein Versprechen in einem Kommentar ist ein Versprechen mit Haltbarkeitsdatum
Das Problem mit dem Satz oben ist nicht, dass er schwer einzuhalten wäre. Es ist, dass er sich etwa sechs Monate lang leicht einhalten lässt.
Jemand fügt der SMTP-Sonde ein EHLO hinzu, damit sie erkennen kann, ob STARTTLS angeboten wird, was eine wirklich nützliche Information ist. Die vorhandenen Tests laufen weiter durch, denn sie prüfen, was die Sonde gefunden hat, und nicht, was sie gesagt hat. Ab diesem Tag sendet die Software Protokollbefehle an Kundenmaschinen, und im Entwurfsdokument steht weiter, dass sie das nicht tut. Nichts ist rot geworden. Nichts wird es je.
Wir haben also eine Zahl daraus gemacht, wo eine Zahl möglich ist. Jeder Socket, den die Prüfung öffnet, steckt in einem Strom, der geschriebene Bytes zählt, und die Summe reist mit dem Ergebnis zurück. Bei vier der sechs Arten von Sonde prüfen die Tests eine genaue Zahl: null für die beiden, die nichts senden, zweiunddreißig für SSH, acht für PostgreSQL. Die anderen beiden können das nicht, denn ein Client Hello und ein SMB-Negotiate schwanken in der Länge mit dem, was darin angeboten wird; ihre Schranke ist stattdessen eine Form, nämlich eine Nachricht und nichts danach. Ein EHLO zu einer auf null geprüften Sonde hinzuzufügen ist jetzt ein roter Test mit einer Zahl darin.
Zwei Details an diesem Zähler haben sich als wichtig erwiesen.
Er zählt Schreibvorgänge und keine Lesevorgänge. Was die Gegenseite von sich aus preisgibt, haben nicht wir verursacht; was wir senden, schon. Und er ist ein gemeinsamer Zähler statt eines Feldes auf unserem eigenen Stromtyp, denn die TLS-Sonde übergibt ihren Socket einer Bibliothek, die dann ihre eigenen Handshake-Datensätze darüber schreibt. Ohne einen gemeinsamen Zähler wäre die eine Sonde, die fremden Code benutzt, die eine Sonde, die ungezählt bliebe, und genau dort ist ein Byte-Budget am schwersten zu überblicken.
Was jede Sonde kostet
| Sonde | Was wir senden | Was gelesen wird |
|---|---|---|
| Nur öffnen | nichts, geprüft auf 0 Bytes | nichts |
| Banner: FTP, Telnet, SMTP, MySQL | nichts, geprüft auf 0 Bytes | eine begrenzte Begrüßung |
| SSH | eine Identifikationszeile, geprüft auf 32 Bytes | die Identifikationszeile des Servers, dann seine Algorithmenliste, falls er sie von sich aus schickt |
| TLS | ein Client Hello, wechselnde Länge | Server Hello und Zertifikat |
| SMB | ein Negotiate, wechselnde Länge | die Antwort auf das Negotiate |
| PostgreSQL | die SSL-Anfrage, geprüft auf 8 Bytes | ein Byte |
Auf die Eröffnung folgt nichts. Keine zweite Nachricht, kein Keepalive, kein Abschluss eines Handshakes. Sobald die Gegenseite gesprochen hat, schließt sich der Socket.
SSH: zweiunddreißig Bytes, und warum es nicht weiter gehen kann
Im SSH-Protokoll senden beide Enden zuerst eine Identifikationszeile. Unsere ist eine Zeile von zweiunddreißig Bytes, und sie ist das Einzige, was die Sonde schreibt. Danach liest sie: die Identifikationszeile des Servers und dann, falls der Server sie unaufgefordert schickt, seine Schlüsselaustauschnachricht mit den angebotenen Algorithmen darin.
Wichtig ist, was fehlt. Die Sonde sendet nie ihre eigene Schlüsselaustauschnachricht. Das ist keine Richtlinie, es ist eine strukturelle Schranke: Ohne sie kann der Schlüsselaustausch nicht fortschreiten, es kommt nie eine Sitzung zustande, und es gibt daher im Protokoll keinen Zustand, in dem eine Anmeldeanfrage gesendet werden könnte. Kein Anmeldeversuch hört damit auf, eine Regel zu sein, an die sich jemand erinnern muss.
Die Identifikationszeile nennt das Produkt, statt einen Client nachzuahmen. Ein Administrator, der sein Anmeldeprotokoll liest, sollte sehen können, wer sich verbunden hat. Eine neutrale oder gefälschte Zeichenfolge würde eine berechtigte Prüfung wie Ausspähung aussehen lassen, und das ist ein schlechter Tausch für die zwei Sekunden Verschleierung, die sie einbringt.
Es gibt einen Preis, und er verdient es genannt zu werden, weil er als Datenqualitätsproblem auftritt und nicht als Fehler. Manche Server warten auf die Schlüsselaustauschnachricht des Clients, bevor sie ihre eigene senden, und das Protokoll erlaubt beide Reihenfolgen. Wenn das passiert, bekommt die Sonde eine Versionszeile und keine Algorithmenliste. Die Abdeckung für diesen Port ist dann teilweise, und sie muss als teilweise festgehalten werden. Würde sie als vollständig mit leerer Liste festgehalten, käme das Regelwerk zu dem Schluss, dass keine veralteten Algorithmen angeboten werden, was das denkbar schlechteste Ergebnis ist: ein zuversichtliches „sicher“, abgeleitet aus fehlenden Daten.
Die Protokolle, die zuerst sprechen, und die Versuchung zu antworten
FTP, Telnet, SMTP und MySQL begrüßen Sie alle. Die Sonde für diese sendet überhaupt nichts: verbinden, eine begrenzte Anzahl Bytes lesen, schließen. Das ist kein Absammeln von Bannern, denn es gibt keine Möglichkeit, einen solchen Port zu öffnen, ohne die Begrüßung zu empfangen, und es wurde um nichts gebeten.
Die Versuchung mit EHLO ist real, und wir haben uns dagegen entschieden. Zu wissen, ob ein Mailserver STARTTLS anbietet, ist wirklich wertvoll. Es verlangt aber auch, einen Protokollbefehl zu senden, und die Regel handelte von Tatsachen, die die Gegenseite unaufgefordert preisgibt. Die Folge ist, dass ein SMTP-Befund mit einem niedrigeren Schweregrad und einem niedrigeren Vertrauensgrad landet, als er es sonst täte. Das ist der ehrliche Preis, und er sollte im Befund sichtbar sein, statt wegdiskutiert zu werden.
PostgreSQL ist der interessante Zwischenfall. Acht Bytes sind das gesamte SSL-Anfragepaket: eine Länge und eine magische Zahl, was das Erste ist, was jeder Client sendet, und was weder eine Abfrage noch Zugangsdaten noch eine Anmeldung ist. Der Server antwortet mit einem einzigen Byte, das sagt, ob er TLS sprechen wird. Ein Byte Antwort genügt, um eine Datenbank, die Verschlüsselung verlangt, von einer zu unterscheiden, die es nicht tut, und es gibt keine Fassung dieser Prüfung, die weniger sendet.
Ein offener Port ist keine Schwachstelle
Dass Port 445 antwortet, heißt nicht, dass SMB1 aktiviert ist. Das sind zwei getrennte Tatsachen, und sie brauchen zwei getrennte Felder.
Unsere Sonde hält einen Zustand für den Port fest, also ob überhaupt jemand da ist, und höchstens einen Beleg, also was derjenige gesagt hat. Ein Negotiate, das ohne einen alten Dialekt zurückkommt, lässt Sie mit einem offenen Port und sonst nichts zurück, und das ist ein vollständiges Ergebnis und kein teilweises. Die Versuchung, beides zu einem einzigen Schweregrad zusammenzufalten, ist stark, weil dabei ein viel aufregenderes Dashboard herauskommt.
Die Hygiene bei Belegen gehört in denselben Absatz, denn eine Begrüßung ist keine harmlose Zeichenfolge. FTP- und SMTP-Banner tragen in der Praxis den Hostnamen des Kunden, manchmal den Hostnamen seines Kunden und gelegentlich einen Pfad auf der Platte. Sie roh zu speichern bedeutet, dass Ihre Befundtabelle zu einem Ort wird, an dem sich persönliche und strukturelle Informationen über die Netze anderer Leute ansammeln, aufbewahrt so lange wie Befunde aufbewahrt werden, sichtbar für jeden, der einen Befund lesen darf.
Was die Sonde verlässt, ist deshalb ein normalisiertes Protokollkürzel, ein nach einer dokumentierten Regel herausgeschnittenes Versionsfragment, die Anzahl der gelesenen Bytes und ein Hash der rohen Bytes. Der Hash macht zwei Scans vergleichbar, ohne dass jemand den Text aufbewahrt. Diese letzte Eigenschaft ist die, die Sie vermissen, wenn Sie sie auslassen: Ohne sie verlangt die Frage, ob sich das seit dem letzten Monat geändert hat, genau das, was Sie nicht aufbewahren wollten.
Der Sensor hat keine Meinungen
Noch eine Trennung, und sie ist die, die den Rest wartbar macht.
Der Agent misst. Er löst keine Hostnamen auf, führt keine eigene Portliste und wählt keine Ziele aus: Die Adresse und die Ports werden von der Plattform vorgegeben, die vor dem Senden geprüft hat, dass die Adresse dieser Organisation und diesem Server derzeit zugeteilt ist. Ohne Ziele misst der Agent nichts.
Das Urteil fällt auf der Plattform, aus einem Regelsatz, der gelesen und versioniert werden kann. Das ist wichtig, weil ein Befund den Code überlebt, der ihn erzeugt hat. In sechs Monaten wird jemand fragen, warum ein Scan im September als hoch bewertet wurde, und die einzige Möglichkeit, das zu beantworten, ist, die Regeln und die Messwerte als getrennte, einzeln abrufbare Dinge zu haben. Wäre der Schweregrad im Sensor eingebacken, lautete die Antwort, dass diese Version des Agenten das so gesehen hat, und das ist keine Antwort.
Dieselbe Überlegung ist der Grund, warum der Agent sich nach außen verbindet und nie lauscht und warum Zugangsdaten auf dem Host bleiben, statt zu uns zu reisen. Eine Komponente, die immer nur berichtet, was sie gemessen hat, ist eine Komponente, deren Schadensradius sich in einem Satz beschreiben lässt.
Was wir aufschreiben würden
- Das Versprechen in eine Zahl verwandeln. Wenn Ihre Regel davon handelt, was Sie senden, dann zählen Sie, was Sie senden, und prüfen Sie auf die Zahl. Ein Kommentar kann nicht scheitern.
- Strukturelle Schranken bevorzugen. Keine Schlüsselaustauschnachricht zu senden bedeutet, dass Authentifizierung unerreichbar ist, und das ist stärker als eine Regel, die sagt, man solle sich nicht authentifizieren.
- Eine Sonde teilweise sein lassen. Fehlende Daten müssen als fehlend sichtbar sein, denn die Alternative ist ein zuversichtliches Nein, das niemand nachprüfen kann.
- Offen und verwundbar in verschiedenen Feldern halten, und das Regelwerk sie an einer Stelle zusammenführen lassen, die Sie lesen können.
- Keine rohen Banner speichern. Normalisieren, hashen und den Hash zum Vergleich aufbewahren.
- Die Meinung auf die Plattform legen, damit ein Urteil vom letzten Quartal auch in diesem Quartal noch erklärbar ist.
Zur Klarheit über unser eigenes Produkt: Das ist ein Detektor, er sitzt hinter einem Schalter auf Organisationsebene, der derzeit aus ist, und er ist heute nicht käuflich. Die Messwerte oben stammen aus der Umsetzung und ihren Tests, nicht von einer Werbeseite.
Gebaut für Provibr, wo der Agent im eigenen Netz des Kunden läuft. Die Verifikationsseite desselben Entwurfs, der Nachweis, dass ein Hostname der fragenden Person gehört, steht in wie sich der Besitz eines Hostnamens beweisen lässt.