pfSense Plus MIM API toolkit b4acd7ca - Élevé - À distance - IDOR - URL de capacité userkey ACB
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-acb-userkey
Classe : IDOR Portée : Distante
pfSense Plus MIM API (Netgate/pfsense-api b4acd7ca) - Netgate
GET /services/acb et GET /services/acb/bkp prennent userkey comme paramètre de requête non contraint. Le client Python généré place cette clé dans la chaîne de requête. Le YAML ne contient aucun securitySchemes. La possession de la clé de périphérique Auto Config Backup constitue la vérification. Il s'agit d'une URL de capacité.
Une userkey ACB volée ou divulguée liste les sauvegardes hébergées de ce périphérique et récupère le corps d'une révision. La configuration complète se trouve dans ces blobs. Même classe que la clé ACB CE CVE-2024-57273 / SA-25_03 si la clé fuite. Ce CVE concernait la dérivation par bannière SSH. Ce reliquat est le pendant en paramètre de requête de l'API Plus MIM. Je ne redépose pas la dérivation par bannière.
Il s'agit de l'OpenAPI public + client généré pour pfSense Plus Nexus Multi-instance Management (contrôleur sur :8443). Ce n'est pas le paquet REST CE (jaredhendrickson/pfsense-api / pfrest.org). Le serveur est réservé à Plus (payant). Je n'ai pas exécuté pfSense Plus.
| ID | pas encore de CVE |
| Classe | IDOR (URL de capacité) |
| Portée | Distante |
| CWE | CWE-639 |
| CVSS | Élevé : 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N si ces GET honorent userkey sans lier un JWT au périphérique |
| Produit | Netgate/pfsense-api (pfSense Plus MIM OpenAPI + client généré) |
| Affecté | épinglé b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25). Aucun tag. |
| Auth | Spéc. : aucune (securitySchemes absent). userkey est le secret en paramètre de requête. Le JWT/RBAC Plus n'a pas été exécuté. |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1:19171 uniquement. Aucune image Plus. |
Hub de la série : pfsense-api-nexus-mim (ceci est la partie 7).
Nécessite une userkey ACB volée ou divulguée (spéc. : « hexidecimal encoded 32-byte random bytes », 64 hex). La spécification ne lie pas cette clé à un JWT ni au périphérique de l'appelant. Le GET /services/acb/config de classe G11 renvoie la userkey active. Les échantillons G9 définissent verify_ssl=False, donc un MITM de :8443 peut voir la clé sur le réseau. Ce sont des voies de fuite. Ce reliquat est ce que la clé permet d'obtenir une fois exfiltrée.
| Méthode | Sink | Privilège |
|---|---|---|
GET /services/acb?userkey=<stolen> | GetACBList (pfapi_openapi.yml). Généré get_acb_list.py params["userkey"]. | Prouvé en labo (mock) : liste les sauvegardes hébergées de cet appareil. Témoin dans backups[].reason. |
GET /services/acb/bkp?userkey=<stolen>&revision= | GetACB -> RetrievedBackup.backup. Généré get_acb.py params["userkey"] + params["revision"]. | Prouvé en labo (mock) : récupère le corps de la révision. Témoin dans backup. |
| Même chaîne de sauvegarde sur un contrôleur en production | blob ACB hébergé | Déduit : config.xml complet (utilisateurs, clés, paquets) une fois lisible. Le mock a renvoyé un témoin XML en clair. Je n'ai pas communiqué avec acb.netgate.com ni déchiffré un blob en production. |
GET /services/acb/config | ACBConfigInfo.userkey, ACBConfig.encryption_password | Spécification, pas ce labo : secret de capacité en production et mot de passe de déchiffrement. Classe G11 secrets-sur-GET. Non exercé. |
| Méthode | Sink | Privilège |
|---|---|---|
POST /services/acb/restore | Corps RestoreACB { timestamp } | Adjacent fermé : les échantillons envoient toujours un JWT. Pas ce reliquat. Non exécuté. |
POST /services/acb/config remplacer userkey | SaveACBConfig | Adjacent fermé : pas une URL de capacité GET. Non exécuté. |
GET list / GET bkp ne suppriment pas. DELETE /services/acb/bkp/{timestamp} est une opération différente. Non exercée.
Un userkey erroné et un userkey manquant n'ont renvoyé aucun témoin (prouvé en labo).
Prouvé en labo vs déduit : la liste et le bkp avec clé volée ont renvoyé le témoin. Une clé erronée et une clé manquante ne l'ont pas fait. Plus n'a pas été exécuté. Le contenu de config.xml en production et le déchiffrement sont déduits du schéma public (RetrievedBackup.backup est une chaîne ; encryption_password se trouve sur ACBConfig).
Nécessite : un chemin réseau vers les GET ACB du contrôleur MIM, plus un userkey volé/fuité. CVSS 7.5 si ces GET honorent la clé de requête sans lier un JWT à l'appareil. Honnêtement : ce pack prouve que la spécification publique modélise ce contrat, en loopback.
| Surface | Raison |
|---|---|
| Contrôleur pfSense Plus | non exécuté. Aucune image Plus dans ce pack. |
| Paquet REST CE | serveur différent (jaredhendrickson/pfsense-api / pfrest.org). |
| Dérivation de clé ACB via bannière SSH | CVE-2024-57273 / SA-25_03. Ne pas re-signaler. |
POST /services/acb/restore comme cette découverte | les échantillons envoient toujours un JWT. |
php/shell non authentifié depuis le security OAS omis | reliquat de docs. Le mock n'est pas une preuve de serveur 200-sans-JWT. |
userkey manquant | labo 403, aucun témoin. |
userkey erroné | labo liste vide / bkp 403, aucun témoin. |
verify_ssl de la bibliothèque générée | par défaut True. G9 correspond aux échantillons qui le désactivent, pas au défaut du paquet. |
J'ai épinglé Netgate/pfsense-api main b4acd7ca (2026-05-25, « Add Snort-3 API definitions »). Douze chasses sur login/JWT, diagnostics, enrôlement MIM, TLS client, utilisateurs/certificats, paquets, VPN/pare-feu, sécurité OpenAPI, IDOR d'appareil, git/firmware/flux, plus un mock en loopback de chaque opération générée.
Liste d'exclusion d'abord : reliquats CE WebGUI déjà signalés (QinQ parent if, assistant OpenVPN CRLF, CARP VHID, numéro de limiteur, bannière de connexion IPsec). Diagnostics PHP/shell comme pouvoir admin prévu. Le paquet REST CE tiers. Dérivation de bannière CVE-2024-57273.