pfSense Plus MIM API toolkit b4acd7ca - Élevé - À distance - Reliquat de privilèges - example-add-devices.py JSON vers SSH
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-enroll-json-ssh
Classe : Reliquat de privilège Portée : Distante
Boîte à outils pfSense Plus MIM API (b4acd7ca) - Netgate
example-add-devices.py est la méthode documentée pour enregistrer le contrôleur Nexus sur chaque appareil pfSense Plus via SSH. Il fait un json.dumps de GET /mim/controller/identity, remplace uniquement ", puis applique .format deux fois sur ce blob dans un script POSIX curl -d à guillemets doubles. Paramiko exec_command exécute le script en tant que SSHUSER (valeur par défaut de l'exemple : admin) sur chaque adresse de pfsense_addresses.
json.dumps plus replace('"', '\\"') garde les guillemets fermés. $(), les backticks et ${...} ne sont pas des métacaractères JSON. Ils restent actifs à l'intérieur de la chaîne -d à guillemets doubles toujours ouverte. OpenSSH exec est un shell. C'est là le reliquat.
Il ne s'agit pas du paquet REST CE tiers. C'est le client OpenAPI officiel et les exemples pour le contrôleur pfSense Plus Nexus Multi-instance Management. Je n'ai pas composé Plus. Le labo est l'interpolation épinglée plus un faux /var/run/pfnet-controller.sock.
| ID | pas encore de CVE |
| Classe | Reliquat de privilège (JSON du contrôleur vers SSH d'enrôlement) |
| Portée | Distante (sur le chemin vers CONTROLLER_URL pendant que l'exemple définit verify_ssl=False, ou un écrivain des champs chaîne de ControllerSummary) |
| CWE | CWE-78 |
| 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 Plus MIM) |
| Affecté | main public b4acd7ca21dbca739a530403a1f62a7440f7726f example-add-devices.py |
| Auth | l'opérateur exécute l'exemple documenté. L'attaquant est sur le chemin, ou peut écrire les chaînes de résumé. La connexion au contrôleur a toujours lieu en premier. |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1:19101 uniquement. Pas d'image Plus. |
Partie 1 de la série sur les reliquats Nexus MIM. Frères : enroll-autoadd, unix-sock-noauth, example-ssl-verify (G9 est la façon dont un pair sur le chemin façonne ce JSON), fleet-jwt, export-key-get.
Le reliquat est une substitution de commande à l'intérieur de la chaîne -d à guillemets doubles toujours ouverte. json.dumps plus la passe de guillemets gardent la chaîne fermée. $(), les backticks et ${...} survivent et s'exécutent en tant que SSHUSER lorsque OpenSSH exec le script.
| Méthode | Sink | Privilège | Prouvé en labo ou déduit |
|---|---|---|---|
Placer $() (ou des backticks / ${...}) dans un champ chaîne ControllerSummary, puis laisser l'opérateur exécuter example-add-devices.py | controller_info.replace('"', '\\"') puis device_script.format(...) puis sshclient.exec_command(device_script) (example-add-devices.py ~104-161) | Shell en tant que SSHUSER (échantillon par défaut admin ; l'admin SSH de pfSense est généralement équivalent à root) sur chaque adresse dans pfsense_addresses | Prouvé en labo sur l'interpolation : INJECT vpn_listenaddr=$(printf %s PFSENSE-API-ENROLL-JSON-SSH-WITNESS >/oracle/witness) a survécu à l'échappement des guillemets uniquement (dollar-paren-survived=yes) et a écrit le témoin (inject-oracle=yes). Paramiko/SSH lui-même n'est pas dans ce compose. |
MITM TLS de GET /api/mim/controller/identity pendant que l'échantillon utilise verify_ssl=False | Même analyse ControllerSummary puis même script | Même shell. Tous les champs ControllerSummary sont str ou Unset, donc un corps JSON MITM qui se type-parse suffit. | Déduit de l'échantillon (example-add-devices.py login Client et AuthenticatedClient définissent tous deux verify_ssl=False). Le labo poste directement l'objet summary. Frère : example-ssl-verify. |
Écrire des caractères de substitution dans name ou vpn_listenaddr sur le contrôleur, attendre le prochain enroll | Même sink | Même shell lorsqu'un opérateur exécute ensuite l'échantillon | Déduit. Nécessite une écriture préalable de ces champs (déjà admin du contrôleur, ou le frère unix-sock-noauth). |
Même shell, clés supplémentaires via ControllerSummary.additional_properties | Le même dump inclut des clés MITM supplémentaires (to_dict copie les restes après from_dict) | Les champs supplémentaires passent dans -d et dans le shell | Déduit de to_dict. Le labo injecte uniquement via vpn_listenaddr. |
| Méthode | Sink | Privilège | Prouvé en labo ou déduit |
|---|---|---|---|
| Lire la sortie standard de la station de travail d'enrollment | print("CONTROLLER_SUMMARY:", controller_info) | Identité du contrôleur key, Netgard vpn_pubkey / vpn_netkey / adresses d'écoute | Déduit du print de l'échantillon. Le labo n'imprime pas de blob de contrôleur réel. |
| Sniffer ou MITM le canal exec SSH | La charge utile exec_command(device_script) est le JSON -d de curl | Même identité de contrôleur sur le fil vers chaque appareil | Déduit. AutoAddPolicy sur ce canal est un rapport frère. |
| Cas CONTROL sur le gadget | POST /case name=control | Un vpn_listenaddr honnête atteint le socket unix sans modification | Prouvé en labo. 192.0.2.10:51820 posté tel quel, pas d'oracle (control-clean=yes). |
| Méthode | Sink | Privilège | Prouvé en labo ou déduit |
|---|---|---|---|
Commande injectée en tant que SSHUSER | Même exec_command | Arrêter pfnet-controller, effacer l'enrollment, redémarrer, ou autrement retirer l'appareil du MIM | Déduit comme effet de bord du shell. Le labo écrit uniquement le fichier témoin. |
Nécessite : le chemin d'échantillon officiel (enrollment par l'opérateur). UI:N pour le pair sur le chemin une fois cet échantillon en cours d'exécution. La connexion au contrôleur se produit toujours en premier.