
Documente et reproduit une faille d'authentification fail-open dans SONiC gNMI où une map UserAuth vide permet des écritures gNMI Set et gNOI non authentifiées, avec un banc d'essai en boucle locale.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sonic-gnmi-noauth
SONiC gNMI f13a08e0440f - SONiC Foundation / sonic-net
NOS SONiC communautaire. Pas Dell Enterprise SONiC. Pas SonicWall SonicOS. Le comité n'émet pas de CVE. gnmi-native.sh sait que l'omission de --client_auth désactivait entièrement l'authentification, donc quand user_auth est absent, il force le mode cert. Fail-closed. Ensuite, il ne passe jamais --ca_crt quand les certificats sont absents. setupFlags désactive le cert car il n'y a pas de CA. authenticate() traite la map vide comme un succès. Les écritures native et translib restent compilées (ENABLE_NATIVE_WRITE=y). Deux ensembles de flags de production, même contournement : ToR par défaut --noTLS --bind_address 127.0.0.1 ; SmartSwitch DPU --insecure --allow_no_client_auth, bind vide, toutes les interfaces, port 8080.
Un UserAuth vide après la désactivation du cert, c'est du gNMI Set et des écritures gNOI non authentifiés. Un DPU sans certificats est distant sur :8080.
| ID | pas encore de CVE |
| CWE | CWE-306, CWE-287 |
| CVSS | Critique : 9.8 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (DPU sans cert). Le ToR par défaut est le même contournement sur 127.0.0.1:8080 (Élevé, local). |
| Produit | sonic-gnmi / sonic-buildimage |
| Affecté | sonic-gnmi jusqu'à master f13a08e0440f ; launcher 9495839742e4 |
| Auth | non authentifié |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Sur un SmartSwitch DPU sans certificats gNMI : depuis le réseau, TCP :8080, pas de JWT, pas de PAM, pas de cert client. Appeler gnmi.gNMI/Set (CONFIG_DB natif / translib). Appeler gnoi.debug.Debug. Redémarrer. Réinitialisation d'usine. File.Put sous /tmp, /var/tmp, /host.
Sur un ToR/leaf par défaut sans certificats : tout processus capable d'atteindre 127.0.0.1:8080 fait la même chose. Le conteneur gnmi est en host net, donc ce loopback est celui de l'hôte.
C'est une réécriture de config du switch, et des commandes hôte en tant que admin, sans s'authentifier. La whitelist de Debug inclut docker, config, redis-cli, sonic-installer, reboot. L'admin par défaut est dans docker et %sudo. Pas le mot de passe admin par défaut documenté. KillProcess renvoie toujours Unauthenticated sur un UserAuth vide. Ne l'utilisez pas comme oracle de succès.
J'ai lu SECURITY.md d'abord. sonic-net/SONiC est le wiki. Le code est dans les arbres frères sonic-net/*. Puis dix chasses sur ces pins : injection CLI, auth REST, gNMI Set, hostcfgd PAM, RESTCONF, ZTP, image Redis/sshd/sudo, défauts FEATURE, GCU/SSTI, DHCP/LLDP/SNMP. Pas de switch réel. Le seuil était Critique/Élevé.
La majeure partie de ce seuil est déjà fermée ou non par défaut. sonic-restapi est INCLUDE_RESTAPI ?= n. Le launcher de production de RESTCONF force PAM. Le Redis hôte est sur 127.0.0.1 sans requirepass, ce qui est un premier saut, pas une trouvaille. Le conteneur gnmi n'est pas optionnel. INCLUDE_SYSTEM_GNMI = y. La FEATURE gnmi est activée. Host net, host pid, host userns.
Je n'ai pas monté une image sonic-vs complète. Le lab est un mince wrapper gRPC autour d'extraits vérifiés par SHA256 de setupFlags et authenticate() du pin f13a08e0440f. Les deux listeners ont renvoyé SONIC-GNMI-NOAUTH-WITNESS avec auth_enabled=false et enable_native_write=true. Un UserAuth par mot de passe sans identifiants est Unauthenticated. C'est le vrai contournement, pas un stub qui réussit toujours.
Fausses pistes déjà consignées : KillProcess Unauthenticated (ce RPC rejette déjà un UserAuth vide - le lab exige le contournement de authenticate() sur le chemin Set) ; Probe OK quand le UserAuth par mot de passe est activé et sans identifiants (alors l'oracle est un stub) ; un gadget docker gNOI Debug, payload nsenter, reverse shell. Du théâtre. Pointer ça vers une box Dell Enterprise SONiC, ou un SonicWall. Mauvais produit.
cd lab
./run.sh
Cible uniquement 127.0.0.1:18080 (ToR en clair) et 127.0.0.1:18081 (DPU TLS-insecure). Mince gRPC, pas une image DPU complète. Extraits de pin hachés au build contre sonic-gnmi f13a08e0440f.
IOC tor-connect 127.0.0.1:18080 plaintext no-metadata
IOC tor-check witness=SONIC-GNMI-NOAUTH-WITNESS auth_enabled=false enable_native_write=true user_auth_any=false mode=tor
IOC dpu-connect 127.0.0.1:18081 tls-insecure no-client-cert no-metadata
IOC dpu-check witness=SONIC-GNMI-NOAUTH-WITNESS auth_enabled=false enable_native_write=true user_auth_any=false mode=dpu
IOC tor-negative status=UNAUTHENTICATED
IOC dpu-negative status=UNAUTHENTICATED
SUCCESS SONIC-GNMI-NOAUTH who=unauth tor=18080 dpu=18081 SONIC-GNMI-NOAUTH-WITNESS
Si UserAuth est vide après le retrait du cert, ne servez pas Set/gNOI write, ou n'écoutez pas hors du loopback. Copiez UserAuth aussi sur le chemin --noTLS. Provisionnez des certificats serveur et une CA pour que --ca_crt soit défini et que le mode cert ne soit pas désactivé. Ne faites pas tourner un SmartSwitch DPU sans cert (--insecure --allow_no_client_auth avec CA vide) sur un :8080 joignable. Les deux listeners doivent renvoyer Unauthenticated pour un UserAuth vide sur le chemin d'écriture.
telemetry.go · server.go · whitelist.go · command.gognmi-native.sh · rules/config · init_cfg.json.j2