pfSense Plus MIM API toolkit b4acd7ca - Élevé - À distance - Privilège résiduel - Paramiko AutoAddPolicy enroll
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-enroll-autoadd
Classe : Reliquat de privilège Portée : Distante
pfSense Plus MIM API (Netgate/pfsense-api) b4acd7ca - Netgate
example-add-devices.py est la méthode documentée pour enregistrer le contrôleur Nexus auprès de chaque équipement pfSense. Il n'appelle jamais load_system_host_keys(). Il définit paramiko.AutoAddPolicy() puis connect puis exec_command(device_script). Le commentaire indique de retirer AutoAdd lorsque les équipements sont déjà dans known_hosts. La configuration par défaut livrée est AutoAdd.
Le premier contact SSH avec une nouvelle machine accepte n'importe quelle clé d'hôte qui répond. L'authentification par mot de passe ou par clé est présentée à ce pair. La sortie standard est passée à json.loads puis envoyée via POST /mim/devices au véritable contrôleur.
Il ne s'agit pas du paquet REST CE tiers. Il s'agit de l'OpenAPI officiel plus le client Python généré pour pfSense Plus Nexus Multi-instance Management. Le serveur est réservé à Plus. Le laboratoire est un gadget SSH Paramiko. Je n'ai pas communiqué avec un contrôleur Plus en production.
| ID | pas encore de CVE |
| Classe | Reliquat de privilège (Paramiko AutoAddPolicy sur le SSH d'enrôlement) |
| Portée | Distante (sur le chemin vers le SSH de l'équipement lors du premier contact) |
| CWE | CWE-322 |
| CVSS | Élevé : 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Produit | Netgate/pfsense-api (boîte à outils client Plus Nexus MIM) |
| Affecté | main b4acd7ca21dbca739a530403a1f62a7440f7726f example-add-devices.py |
| Auth | L'opérateur exécute l'exemple officiel ; l'attaquant est sur le chemin vers le SSH de l'équipement |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1:19111 uniquement. Pas d'image Plus. |
AC:H correspond au premier contact / à la position sur le chemin. Un poste de travail qui possède déjà les véritables clés d'équipement dans known_hosts et dont la ligne AutoAdd a été retirée n'est pas concerné par ce reliquat.
Mêmes reliquats d'épinglage : interpolation JSON de ControllerSummary dans le shell d'enrôlement (G1) et les exemples forcent verify_ssl=False (G9). Hub de la série : pfsense-api-nexus-mim.
Se placer sur le chemin vers une adresse SSH de premier contact dans pfsense_addresses pendant que l'opérateur exécute l'exemple. AutoAdd est toujours activé.
| Méthode | Sink | Privilège |
|---|---|---|
Se placer sur le chemin vers une adresse SSH de premier contact dans pfsense_addresses | set_missing_host_key_policy(paramiko.AutoAddPolicy()) puis connect (example-add-devices.py:151-160) | Intégrité (prouvé en labo) : une clé d'hôte inconnue est acceptée. Labo : AutoAddPolicy s'est connecté (autoadd=yes). RejectPolicy a échoué (reject-control=yes). |
Même session, réponse à exec_command(device_script) | stdout analysé comme DeviceIdentity (example-add-devices.py:161-187) | Intégrité (prouvé en labo) : exec a renvoyé un JSON d'identité contenant PFSENSE-API-ENROLL-AUTOADD-WITNESS (identity-json=yes). |
| Même MITM, lecture de la charge utile exec | device_script est le curl -d de ControllerSummary laissé par G1 | Recon (déduit du code source) : clé d'identité du contrôleur, vpn_pubkey / vpn_netkey / adresses d'écoute de Netgard. Non extrait par ce labo. |
| Même MITM, authentification par mot de passe ou clé | SSHUSER / SSHPASS ou agent/clés (example-add-devices.py:156-160) | Recon (déduit) : identifiants ou clés présentés à l'hôte factice. Le labo n'a utilisé l'authentification par mot de passe que comme chemin d'exemple SSHPASS. |
Même JSON stdout, add_controlled_device.sync | POST /mim/devices sur le vrai contrôleur | Intégrité (déduit) : enregistre les clés Noise/VPN de l'attaquant et l'address. De plus, le handshake n'a pas été exécuté dans ce labo. |
| Le MITM est le serveur SSH | tout exec envoyé par le client, en tant que SSHUSER | Intégrité / disponibilité (déduit) : exécuter, abandonner ou ignorer le script d'enrôlement. Les appels au socket Unix sur le vrai appareil n'ont lieu que si le MITM les relaie. |
Prouvé en labo vs déduit : la connexion AutoAdd, l'échec de RejectPolicy et le JSON d'identité avec le témoin sont prouvés en labo. L'extraction de la clé du contrôleur, le vol d'identifiants, le POST /mim/devices d'un appareil factice et l'exécution des vrais curls sur socket Unix sont déduits du même chemin d'exemple.
Prérequis : l'opérateur exécute l'exemple officiel contre une adresse SSH dont la clé d'hôte n'est pas déjà épinglée, avec AutoAdd activé. Chemin réseau vers ce SSH. AC:H correspond au premier contact / sur le chemin.
| Surface | Raison |
|---|---|
RejectPolicy sur le même hôte inconnu | Labo : reject-control=yes. Paramiko refuse la clé. |
Poste de travail avec les vraies clés d'appareil dans known_hosts et la ligne AutoAdd supprimée | Le mode prévu par le commentaire. L'exemple ne charge jamais ces clés sauf si vous ajoutez l'appel. |
| Connexion au contrôleur HTTPS | verify_ssl=False est un reliquat d'un exemple voisin (G9), pas ce sink. |
| MIM sur socket Unix sur le vrai pare-feu | Uniquement si le MITM relaie exec. Ce labo ne communique jamais avec /var/run/pfnet-controller.sock. |
Client généré avec verify_ssl=True par défaut | Le défaut de la bibliothèque n'est pas le reliquat. Les exemples forcent False. |
Plus RBAC / :8443 en direct | Ce labo est un gadget Paramiko. Je n'ai pas communiqué avec un contrôleur Plus. |
| Internet non authentifié vers 8443 | La connexion émet toujours un JWT. Ce n'est pas cette découverte. |
| Diagnostics PHP/shell | Pouvoir admin prévu pour un JWT de flotte. Ce n'est pas cette découverte. |
J'ai épinglé github.com/Netgate/pfsense-api main b4acd7ca21dbca739a530403a1f62a7440f7726f après les reliquats du WebGUI CE. Cet arbre est de l'OpenAPI plus du Python généré pour Plus Nexus MIM. J'ai lu la boucle d'enrôlement dans example-add-devices.py. La politique de clé d'hôte est AutoAdd. Les secrets se trouvent sur le même canal exec. L'exemple n'appelle jamais load_system_host_keys().