
pfSense Plus MIM API toolkit b4acd7ca - Mittel - Remote - Privilegien-Rest - offizielle Beispiele verify_ssl=False
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-example-ssl-verify
Klasse: Privilegien-Überbleibsel Reichweite: Remote
pfSense Plus MIM API (Netgate/pfsense-api b4acd7ca) - Netgate
Generierte Client / AuthenticatedClient standardmäßig mit verify_ssl=True und übergibt dies an httpx. Die Dokumentation bezeichnet verify_ssl=False bereits als Sicherheitsrisiko und zeigt zuerst einen PEM-Bundle-Pfad. Jedes offizielle Python-Beispiel und helper_funcs.py konstruieren sie jedoch weiterhin mit verify_ssl=False. example.js setzt NODE_TLS_REJECT_UNAUTHORIZED=0, sodass der gesamte Node-Prozess die Verifizierung überspringt. Das Login-JSON legt Benutzername und Passwort in Base64 ab. Das ist der OpenAPI-Vertrag, keine Verschlüsselung. TLS ist die Vertraulichkeitsschicht.
Ein On-Path-Peer von :8443 präsentiert ein beliebiges Zertifikat. Das Beispiel sendet dennoch POST an /login. Der Stellvertreter erfasst den Base64-Admin-Login und erzeugt ein JWT. Dieses Token ist die Kette: G4 export-key, G5 ACME dump, G6 Fleet-JWT, G7 ACB userkey, beabsichtigtes php/shell und das JSON, das G1 in SSH interpoliert.
Dies ist Teil 9 des pfSense Plus MIM API Toolkit. Lesen Sie dieses Überbleibsel zuerst, auch wenn es Medium ist. Das gestohlene JWT ist der Weg, über den der Rest von einer Workstation aus erreichbar wird, auf der example.py kopiert wurde.
| ID | noch keine CVE |
| Klasse | Privilegien-Überbleibsel (TLS-Verifizierung im Beispiel deaktiviert) |
| Reichweite | Remote (On-Path zu :8443) |
| CWE | CWE-295 |
| CVSS | Medium: 6.8 CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N |
| Produkt | Netgate/pfsense-api (Plus Nexus MIM Client; nicht das CE REST-Paket) |
| Betroffen | öffentliches main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25) offizielle Beispiele und helper_funcs.py |
| Auth | Operator kopiert und führt ein Beispiel gegen den Controller aus; keine zusätzliche Controller-Rolle |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1:19191. Komponiert kein pfSense Plus. |
AC:H liegt On-Path zwischen der Operator-Workstation und dem MIM-Controller. UI:R ist Kopieren/Ausführen des Beispiels.
Opfer: Operator-Workstation, die ein offizielles Beispiel oder helper_funcs.py gegen https://controller:8443 ausführt. Angreifer: On-Path zu diesem HTTPS (LAN, rogue DHCP, kompromittierter VPN-Hop, ARP). Nicht unauthentifiziertes Internet-zu-Firewall.
| Methode | Sink | Berechtigung |
|---|---|---|
Beliebiges Zertifikat präsentieren, während die Probe /login oder /api/login mit verify_ssl=False / NODE_TLS_REJECT_UNAUTHORIZED=0 per POST sendet | httpx verify=False (Python-Proben) oder Node TLS reject-unauthorized 0 | Vertraulichkeit (lab-proven): das Login-JSON lesen. Lab: Stand-in erfasste base64 admin / lab-controller-secret (captured_b64_admin=yes). Dekodierung ist ein base64 -d. |
Derselbe MITM, 200 LoginResponse | Probe akzeptiert beliebiges Zertifikat | Vertraulichkeit (lab-proven): das Access-JWT stehlen. Lab: INJECT erhielt ein Token, das PFSENSE-API-EXAMPLE-SSL-VERIFY-WITNESS trug. |
Derselbe MITM, Set-Cookie beim Login | Probe kopiert client.get_httpx_client().cookies in AuthenticatedClient | Vertraulichkeit (lab-proven Cookie, abgeleitetes Replay): 24-Stunden-Refresh-JWT. POST /login/refresh mit diesem Cookie plus dem base64-Benutzernamen wiederholen, bis die Refresh-TTL abläuft. Lab erfasste Set-Cookie: refresh=.... Refresh gegen einen Live-Controller wurde nicht ausgeführt. |
| Gestohlenes Bearer an den echten Controller wiederholen (falls der Angreifer auch dorthin routen kann) | Plus MIM /api und /api/device/pfsense/{device_id}/api | Integrität (abgeleitet): admin-äquivalent als der eingeloggte Benutzer auf dieser API. Das Schema umfasst POST /diag/cmd/php, POST /diag/cmd/shell, POST /diag/editfile, POST /diag/backup/restore, POST /diag/control halt/reboot. Hier nicht ausgeführt. Dieses Lab ist ein Controller-Stand-in, nicht Plus. |
| Gestohlenes Bearer als Leftover 6 (Fleet-Token) wiederholen | ein POST /login-JWT, das für jede device_id wiederverwendet wird | Integrität (abgeleitet): mit Firewall B sprechen, nachdem man sich als ein Benutzer authentifiziert hat, der für Firewall A gedacht war. LoginResponse hat keine Allow-List pro Gerät. Pack: pfsense-api-fleet-jwt. Plus RBAC nicht ausgeführt. |
| Gestohlenes Bearer als Leftover 4 wiederholen | GET /system/certauth/{refid}/export-key, GET /system/certificates/{refid}/export-key, GET /system/certificates/{refid}/export-p12 | Vertraulichkeit (abgeleitet): CA- und Leaf-Private-Keys abziehen, PKCS12 dokumentiert ohne Passwortschutz, dann VPN / WebGUI TLS / IPsec imitieren. Pack: pfsense-api-export-key-get. |
| Gestohlenes Bearer als Leftover 5 wiederholen | GET /services/acme | Vertraulichkeit (abgeleitet): Let's-Encrypt-Account-Key und ausgestellte Zertifikatsschlüssel für jeden Hostnamen stehlen, den die Firewall registriert. Pack: pfsense-api-acme-key-dump. |
Gestohlenes Bearer wiederholen oder userkey aus einer Probe leaken, die ACB per GET abruft, als Leftover 7 | GET /services/acb?userkey= und GET /services/acb/bkp?userkey= | Vertraulichkeit (abgeleitet): Auto-Config-Backup-Blobs (vollständige Konfiguration) auflisten und abrufen. Pack: pfsense-api-acb-userkey. |
ControllerSummary-JSON in Richtung Leftover 1 formen | MITM von verify_ssl=False HTTPS liefert das JSON, das example-add-devices.py quote-escaped und dann per .format in SSH einsetzt | Integrität (abgeleitet): $() / Backticks / Newlines in einem Controller-Feld werden als SSHUSER auf jeder Adresse in pfsense_addresses ausgeführt. Pack: pfsense-api-enroll-json-ssh. |
| Antworten in Richtung des Clients injizieren | skip-verify akzeptiert beliebiges Zertifikat | Integrität (lab-proven Token, abgeleitete Fleet): ein JWT prägen, das die Probe behält. Lab: INJECT-Token mit dem Witness. Gefälschte Gerätelisten / Upgrade-Fortschritt / Login-Erfolg gegen eine Live-Probe sind dasselbe Gate. |
POST /diag/control, Firmware-POST, Wiederherstellung eines defekten Backups (nach gestohlenem Bearer) | beabsichtigte Admin-Oberfläche, sobald TLS weg ist | Verfügbarkeit (abgeleitet): halt / reboot / defektes Image. Dasselbe Bearer. Nicht gelabbt. |
Lab-proven vs. abgeleitet: CONTROL-Handshake-Fehler, INJECT-Token und erfasster base64-Admin-Login sind lab-proven auf 127.0.0.1:19191. Replay dieses Bearer auf einen Live-Plus-Controller, diag php/shell, G4-G7, G1-JSON-Formung und Refresh-Cookie-Mint neuer Access-JWTs sind aus der OpenAPI und den Proben abgeleitet.