Überwachung von Schutzlücken: Der unbewachte Gegenpart ist der Fehler
Die meisten Zugriffskontroll- und Validierungslücken sind nicht exotisch – es ist ein Handler in einer Familie, der die Prüfung vergessen hat, die seine Geschwister durchführen. Der admin_delete, der eine Rolle prüft, und der bulk_delete, der dies nicht tut. Der read_bounded, der die Länge validiert, und der read_fast, der ihr vertraut. Das Lesen von Dateien von oben nach unten verbirgt diese; der Vergleich von Gegenparten deckt sie auf. Dies ist einer der ergiebigsten White-Box-Züge.
Die Asymmetrie, die Sie suchen
Wächter → Senke (der beabsichtigte, sichere Pfad)
??? → Senke (ein Gegenpart-Pfad mit fehlendem Wächter – der Fehler)
Wann anwenden
- Eine Senke ist von mehreren Aufrufstellen aus erreichbar und Sie vermuten, dass eine eine Prüfung überspringt.
- Sie prüfen ein Autorisierungsmodell, eine Parser-Familie oder eine Handlergruppe auf eine vergessene Prüfung.
- Ein Befund muss mit seinem „Warum ist das falsch" als konkreter Unterschied zu einem korrekten Gegenpart dargestellt werden.
Umfangsprüfung
Nur autorisierte Quellen. Wenn Sie die Autorisierung nicht benennen können, stoppen Sie.
Die Schleife
-
Wählen Sie einen bewachten Anker. Finden Sie eine Funktion, die vor einer sensiblen Senke validiert – eine Authz-/Besitzprüfung, eine Grenzprüfung, eine Positivliste, ein Sanitizer. Dies ist Ihre Referenz dafür, „wie es hier korrekt aussieht".
-
Verknüpfen Sie den Wächter mit der Senke, die er schützt. Benennen Sie die genaue Prüfung und die genaue Senke. „Korrekt" bedeutet, dass der Wächter die Senke dominiert: Auf jedem Pfad durch den Anker läuft die Prüfung vor der Senke. Die bloße Anwesenheit in der Funktion ist keine Dominanz.
-
Zählen Sie die strukturellen Gegenparte auf. Gehen Sie über gleichnamige Dateinachbarn hinaus – wichtig ist die strukturelle Verwandtschaft: Funktionen, die die gleiche Senke erreichen; Überschreibungen derselben Schnittstelle/virtuellen Methode; Handler in derselben Routentabelle / Dispatch-Map / Befehlsauswahl; parallele Member einer Klasse (
get_x/set_x/delete_x); Aufrufer eines gemeinsamen Helfers, von denen einige das Argument sanieren und andere es roh übergeben. Gegenparte, die dieselbe Senke erreichen, sind das stärkste Signal. -
Vergleichen Sie jeden Gegenpart mit dem Anker – anhand dessen, was der Wächter erzwingt, nicht seines Namens. Fragen Sie für jeden Gegenpart, ob eine äquivalente Prüfung dieselbe Senke dominiert. Klassifizieren Sie die Lücke:
- fehlt – überhaupt keine äquivalente Prüfung.
- umgehbar – vorhanden, aber auf einem Pfad überspringbar (frühe Rückkehr, ein kurzschließendes
||, ein Zweig, der die Prüfung überspringt). - schwächer-als-Gegenpart – eine andere Art von Prüfung: Authentifizierung, wo der Anker Autorisierung durchführt; eine Typenprüfung, wo der Anker Grenzen prüft; ein Feld, wo der Anker auch das Geschwisterfeld prüft.
- nach-Senke – die Prüfung läuft, aber nach der gefährlichen Operation.
- falscher-Kontext – eine echte Prüfung, die die Nutzlastklasse dieser Senke nicht abdeckt (ein Encoder, der für die Sprache der Senke falsch ist).
-
Bestätigen Sie die Erreichbarkeit mit Angreifereingabe. Eine unbewachte Senke ist nur dann ein Fehler, wenn nicht vertrauenswürdige Eingabe sie erreicht. Verfolgen Sie das gefährliche Argument des Gegenparts zurück zu einer echten Quelle (Hand an
adjudicating-taint-paths). Ein Gegenpart, der nur mit Konstanten aufgerufen wird, ist kein Befund. -
Dokumentieren Sie als Unterschied – im Schema. Geben Sie es an als: „Anker A schützt Senke S mit Prüfung C (dominierend); Gegenpart B erreicht S mit
guard_status= <fehlt / umgehbar / schwächer-als-Gegenpart / nach-Senke / falscher-Kontext> und B's Argument ist angreifergesteuert über ." Ausgabe gemäß Befundschema.
Ausgearbeitetes Beispiel
Anker:
delete_own_post(user, post_id)– prüftpost.owner == user.id(dominiert) vordb.delete(post). Gegenpart:admin_bulk_delete(ids)erreicht dieselbedb.delete-Senke; die einzige Hürde ist ein routenebenes@login_required, keine objektbezogene Besitzprüfung. Unterschied:guard_status = schwächer-als-Gegenpart– Authentifizierung vorhanden, Autorisierung (Besitz) fehlt. Erreichbarkeit:idsstammt direkt aus dem Anfragekörper; jeder authentifizierte Benutzer erreicht es. Bestätigter IDOR/BFLA, Schweregrad hoch – „Jeder angemeldete Benutzer löscht die Beiträge jedes Benutzers anhand der ID."
Rationalisierungen, die Sie ablehnen sollten
- „Es gibt eine Prüfung in der Funktion, also ist sie bewacht." → Nur wenn sie die Senke dominiert. Eine Prüfung in einem Zweig, den die Senke überspringt, ist kein Wächter.
- „Beide Funktionen haben eine Authentifizierung, sie sind äquivalent." → Authentifizierung ist nicht Autorisierung; eine Typenprüfung ist keine Grenzprüfung. Vergleichen Sie, was erzwungen wird.
- „Der Gegenpart sieht unbewacht aus – melden Sie es." → Nicht bevor Sie bestätigen, dass Angreifereingabe die Senke erreicht. Unerreichbar ≠ Befund.
- „Nur gleichnamige Dateinachbarn." → Der gefährliche Gegenpart lebt oft in einem anderen Modul, das dieselbe Senke erreicht. Zählen Sie nach Struktur auf, nicht nach Datei.
Praktische Ausführung
Sie benötigen Werkzeuge, die Funktionen nach der Senke gruppieren können, die sie erreichen, und den genauen Code jeder anzeigen, um Wächter-für-Wächter zu vergleichen und die Dominanz zu prüfen. Ein Code-Eigenschaftsgraph macht „welche Gegenparte erreichen diese Senke und welche validieren zuerst" direkt beantwortbar; andernfalls zählen Sie die Gegenparte manuell anhand der Aufrufstellen der gemeinsamen Senke oder des Helfers auf und lesen jede. Der Erreichbarkeitsschritt verwendet adjudicating-taint-paths erneut.
Verwandt
adjudicating-taint-paths– Bestätigen, dass die Senke des Gegenparts mit Eingabe erreichbar ist.hunting-bugs-with-a-code-graph– die Hauptschleife, in die dies einfließt.- FINDING-SCHEMA.md – die Form, die jeder Befund annimmt.