Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
tiandy-research — Ce dépôt contient les résultats de mes recherches d'août 2020 sur le firmware des IPC/NVR de Tiandy. J'ai trouvé deux vulnérabilités qui pourraient être utilisées pour récupérer à distance le mot de passe administrateur et obtenir un accès root à l'appareil. | Kitploit
Outils/GitHubGitHub/zb3/tiandy-research
Sécurité des Systèmes EmbarquésCassage de Mots de PasseEscalade de PrivilègesAnalyse des VulnérabilitésExploitationTests d'IntrusionAuthentificationArticles et RechercheRed TeamingAnalyse de Micrologiciel
GitHubzb3/tiandy-research
302il y a 5 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

tiandy-research

Ce dépôt contient les résultats de mes recherches d'août 2020 sur le firmware des IPC/NVR de Tiandy. J'ai trouvé deux vulnérabilités qui pourraient être utilisées pour récupérer à distance le mot de passe administrateur et obtenir un accès root à l'appareil.

Voir le dépôt

tiandy-research

Ce dépôt contient les résultats de mes recherches d'août 2020 sur le firmware des IPC/NVR de Tiandy (ces appareils sont également vendus sous le nom OMNY). Ces « recherches » n'étaient pas exhaustives, mais j'ai trouvé plusieurs méthodes pour récupérer le mot de passe administrateur à distance, activer telnet et changer le mot de passe root.

Il est difficile de dire exactement quelles versions sont concernées, car nous ne pouvons télécharger que les plus récentes. Toutes ces versions téléchargeables sont concernées :

root@kitploit:~
DVRS_V9.12.7.20200422
DVRS_V11.7.4.20200721
NVSS_V13.6.1.20200723
NVSS_V22.1.0.20200722

Non seulement il existe différentes branches pour différents appareils, mais certains composants sont versionnés et mis à niveau séparément, comme l'API web, où j'ai trouvé un contournement de l'authentification qui ne fonctionne que pour les versions publiées depuis mi-2019, quel que soit le numéro de version du firmware. Si vous en savez plus sur les versions concernées, votre aide serait appréciée.

Je fais ici une divulgation complète, mais c'est raisonnable. Un correctif du fournisseur (peu probable puisqu'ils ne répondent pas) ne ferait pas disparaître le problème, surtout quand aucun appareil en ligne n'a le dernier firmware (et de loin). La véritable vulnérabilité est que ces appareils sont exposés à Internet. Et c'est quelque chose que les utilisateurs finaux doivent corriger, pas Tiandy.

En bonus, j'inclus également l'outil de dépaquetage du firmware et quelques informations sur la façon d'accéder aux flux via RTSP/RTMP (bonne chance pour trouver cela dans le manuel).

Contenu

D'abord, je présente les scripts :

  • Récupération du mot de passe
  • Obtenir root

Ensuite, j'essaie d'expliquer brièvement ce que font ces scripts et pourquoi. Je ne répète pas le code, mais j'essaie de fournir assez de contexte pour que vous puissiez comprendre le code :

  • Vue d'ensemble
  • Les vulnérabilités
  • Au-delà de la récupération du mot de passe

Enfin, cela devient relativement technique :

  • Dépaqueter le firmware
  • Trouver des appareils Tiandy sur Internet
  • Bonus : URLs RTSP et RTMP

Récupération du mot de passe

Vous aurez besoin de Python 3 avec PyCrypto.

D'abord, essayez recover.py. Cela nécessite que le port 3001 soit accessible :

root@kitploit:~
python3 recover.py [HOST]

si tout se passe bien, les identifiants administrateur devraient s'afficher.

Si ce port n'est pas accessible, la méthode web pourrait fonctionner. Cela nécessite l'URL :

root@kitploit:~
python3 cgi_recover.py http://123.45.67.89
python3 cgi_recover.py https://123.45.67.89

Si rien de tout cela ne fonctionne, vérifiez si telnet est activé. Si c'est le cas, vous pouvez obtenir directement un accès root à l'appareil, il suffit de casser ce hash :

root@kitploit:~
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh

(assurez-vous d'ouvrir une PR si vous arrivez à le casser :D)

Obtenir root

Ancien firmware

Dans les anciens firmwares NVR V7, vous pouvez exécuter des commandes directement :

root@kitploit:~
python3 ftpupdate.py [host] [adminpass] '[cmd]'

mais cela ne produit aucune sortie. Pour faciliter cela, j'ai inclus ce raccourci :

root@kitploit:~
python3 ftpupdate.py [host] [adminpass] adduser [username] [password]

Cela ajoutera un autre utilisateur avec l'uid 0.

Firmware plus récent

D'abord, activez telnet en utilisant :

root@kitploit:~
python3 telnet.py [host] [adminpw]

ou pour les appareils récents :

root@kitploit:~
python3 cgi_recover.py [host] telnet

Ensuite, vous pouvez écraser /etc/passwd (je suppose que vous savez comment cela fonctionne). Essayez d'abord filetransport.py (pour les NVR) :

root@kitploit:~
python3 filetransport.py [host] [adminpass] put /etc/passwd <[source_file]

cela ne donne aucun retour, vous devez tester en essayant de vous connecter...

Pour les modèles IPC où filetransport.py ne fonctionne pas, essayez upgrade_rw.py :

root@kitploit:~
python3 upgrade_rw.py [url] [adminpass] /etc/passwd <[source_file]

(cela ne donne aucun retour non plus)

Enfin, pour les appareils encore plus récents, cela peut aussi être fait via l'API web :

root@kitploit:~
python3 cgi_recover.py [url] write /etc/passwd <[source_file]

Si aucune de ces méthodes n'a fonctionné (vérifiez si vous pouvez vous connecter), réessayez toutes ces méthodes mais écrasez /config/etc/passwd à la place. Dans certaines versions du firmware, /etc/passwd est un lien symbolique vers ce fichier. Enfin, vous pouvez aussi essayer d'écraser /tdfs/etc/passwd, mais après cela, un redémarrage de l'appareil pourrait être nécessaire ; pour redémarrer, utilisez :

root@kitploit:~
python3 reboot.py [host] [adminpass]

Vue d'ensemble

Les anciens firmwares V7 (IPC et NVR) ne semblent pas être concernés, mais si vous avez le mot de passe administrateur, pour les NVR il y a une RCE authentifiée (ftpupdate.py), et pour les IPC, le script upgrade-rw.py peut être utilisé pour écraser /etc/passwd.

Les versions ultérieures du firmware NVR (V9 et V11) comportent un compte par défaut qui, combiné à une élévation de privilèges « passive », permet de récupérer le mot de passe administrateur. Nous pouvons ensuite écraser /etc/passwd avec filetransport.py.

Bien que le compte par défaut ne soit pas présent dans le firmware IPC, une autre méthode de récupération apparaît : la méthode PSW. C'est un mécanisme de récupération de mot de passe sans aucune sécurité. Il est présent dans toutes les versions téléchargeables du firmware depuis V9. Alors que filetransport.py ne fonctionne que sur les NVR, upgrade_rw.py atteint le même objectif sur les IPC en utilisant le mécanisme de mise à niveau, nous pouvons donc toujours obtenir l'accès root.

Le firmware de 2019 introduit un autre vecteur d'attaque : un contournement de l'authentification via l'API web. En exportant le fichier de configuration sans authentification, nous pouvons récupérer le mot de passe et préparer un paquet de mise à niveau pour écraser des fichiers arbitraires.

En parlant de vulnérabilités, il y en a 4 :

  • Identifiants telnet codés en dur (ancien firmware NVR)
  • Élévation de privilèges authentifiée (n'importe quel utilisateur peut lire le mot de passe administrateur)
  • Récupération de mot de passe non sécurisée (clé de chiffrement symétrique intégrée dans le binaire)
  • Contournement de l'authentification de l'API web (l'ajout de certaines chaînes au chemin de l'URL désactive l'authentification)

Notez que je n'ai pas étudié les fonctions « cloud », c'est-à-dire s'il est possible d'énumérer les appareils et donc de se connecter à des appareils non exposés à Internet (comme c'est le cas avec les appareils Xiongmai).

Les vulnérabilités

Identifiants telnet codés en dur pour l'ancien firmware

Dans les anciennes versions, telnet est activé par défaut et voici ce que l'on trouve dans le fichier /etc/passwd :

root@kitploit:~
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh

(le mot de passe root est mis à jour dynamiquement ; je n'ai pas non plus cassé ce hash, donc les pull requests sont plus que bienvenues :D)

L'utilisateur support (présent en réalité dans toutes les versions du firmware) peut sembler non privilégié, mais bien sûr, cet utilisateur a suffisamment de privilèges pour lire le mot de passe Admin et écraser les scripts d'initialisation inscriptibles par tous dans /etc/init.d ou même en créer de nouveaux :)

Le compte par défaut + l'élévation de privilèges authentifiée

Conceptuellement, la méthode est très simple. Nous envoyons un paquet de connexion et lisons la réponse. C'est tout, car la réponse « connexion réussie » contient les identifiants de tous les utilisateurs, quels que soient nos privilèges. C'était déjà le cas dans V7, mais pratiquement cette méthode n'est devenue utile que lorsque le compte par défaut a été introduit dans le firmware NVR. Le « Default » inamovible n'a aucun privilège à distance, donc vous ne pouvez rien faire avec. Enfin, peut-être sauf lire le mot de passe administrateur...

Bien que cela semble trivial, cela n'a pas été si trivial à implémenter. Un protocole personnalisé est utilisé pour la communication, et les mots de passe sont chiffrés avec DES mais avec les bits inversés (la partie la plus difficile a été de comprendre cela), avec une clé transmise par le serveur. Comme il n'y a pas de dérivation de clé, un espion pourrait facilement tout déchiffrer. Néanmoins, il faut encore comprendre que les bits sont inversés, ou réimplémenter le tout à partir de zéro...

Voir la fonction recover_with_default dans le fichier recover.py pour l'implémentation.

Récupération de mot de passe non sécurisée - la méthode PSW

En analysant le binaire, il est difficile de ne pas remarquer ce mécanisme. Son but unique est de... rendre possible la récupération de mot de passe, et il fait bien ce travail. Trop bien, dirais-je...

Que se passe-t-il ici ? Je pense que cela était destiné à être un mécanisme de récupération de mot de passe, probablement créé pour que les fournisseurs puissent offrir un moyen aux propriétaires d'appareils de récupérer leurs mots de passe.

Je peux émettre l'hypothèse que le processus était censé être le suivant :

  1. Vous entrez votre e-mail ou votre téléphone lors de la configuration de l'appareil
  2. Vous demandez à Tiandy de récupérer votre mot de passe
  3. Tiandy envoie un « paquet magique » à votre appareil et obtient un e-mail/téléphone et des données chiffrées pour dériver le code de sécurité.
  4. Tiandy déchiffre et dérive le code de sécurité et l'envoie via ce canal de communication.
  5. Vous entrez ce code de sécurité dans votre programme client qui envoie un second paquet.
  6. Voilà. Le client déchiffre la réponse et vous montre les identifiants.

Tout cela est bien, sauf qu'il manque une chose... où est la sécurité ? Nulle part, semble-t-il. Rien ne nous empêche d'envoyer ce paquet, de dériver le code de sécurité et de récupérer le mot de passe de n'importe quel appareil accessible.

Je trouve cela étonnant, car ce n'est pas comme s'il y avait une faille dans le mécanisme qui défait la sécurité. Elle est simplement absente. Il n'y a rien à corriger, mais cela ne ressemble pas non plus à une porte dérobée évidente pour moi. Cela laisse des traces dans les journaux et comporte 3 schémas de dérivation différents, chacun plus sophistiqué que le précédent. Cela a pris du temps à implémenter...

Pour en revenir à la méthode, pour que cela fonctionne, l'appareil doit avoir un téléphone/e-mail associé. En regardant l'ancienne version, j'ai vu que seul l'administrateur pouvait le faire, mais j'ai ensuite trouvé un contournement. Étonnamment, dans le firmware plus récent, ce contournement n'est plus nécessaire, car il est explicitement possible de changer l'e-mail de l'appareil sans authentification. Et c'est là que je pense que la porte dérobée était censée se trouver :)

Sur le plan technique, ce mécanisme est en réalité assez compliqué et a été le plus difficile à rétro-concevoir et à réimplémenter. Il existe 3 versions de ce mécanisme, chacune utilisant un algorithme différent pour dériver le code de sécurité. Outre le DES avec bits inversés, un chiffrement de substitution personnalisé avec une clé codée en dur est impliqué. Mais tout cela pour rien, car Tiandy ne peut pas rendre un chiffrement symétrique avec une clé codée en dur sûr, quel que soit l'effort fourni.

Une chose que j'ai observée est que, comme le code de sécurité change chaque minute, il est possible que le processus d'origine échoue simplement parce que le code a changé entre le paquet de l'étape 3 et celui de l'étape 5, quel que soit le peu de temps écoulé entre l'envoi de ceux-ci. J'ai pris cela en compte pour que mon script réessaie le processus si le code s'avère invalide.

Tout le processus, y compris la définition de l'e-mail (que nous n'avons pas besoin de posséder), est implémenté dans le fichier recover.py.

Le contournement de l'authentification de l'API web

Celui-ci fonctionne avec les versions de firmware plus récentes (2019 et après) qui ont l'interface web « moderne » (celle avec la « carte ». J'aime cette carte même si l'Australie semble un peu déformée).

Ce contournement est simple. Alors que la plupart des points de terminaison de l'API sont authentifiés, il existe quelques exceptions. Cependant, la vérification permettant de savoir s'il faut ignorer l'authentification et la correspondance du point de terminaison à activer sont implémentées à des endroits différents. Dans la plupart des cas, l'authentification est ignorée lorsque le chemin de l'URL est égal à une chaîne donnée, ce qui est sécurisé.

Mais les versions récentes introduisent une autre exception, qui est activée lorsque les chaînes Record/DownLoad et ID= existent simplement quelque part dans le chemin de l'URL.

Pour les points de terminaison où le chemin complet est comparé, cela reste sécurisé. Puisque Security/users est l'un de ces points de terminaison, nous ne pouvons pas récupérer le mot de passe directement. Heureusement pour nous, le point de terminaison d'exportation de la configuration est sélectionné en vérifiant si le chemin de l'URL commence par une chaîne donnée (via strncmp), nous pouvons donc simplement ajouter ces chaînes au chemin et exporter le fichier de configuration.

La récupération du mot de passe à l'aide de cette faille est implémentée dans cgi_recover.py.

Au-delà de la récupération du mot de passe

Théoriquement, l'administrateur peut mettre à niveau le firmware, et le firmware n'est ni signé ni chiffré. Mais avons-nous vraiment besoin de préparer un paquet de firmware personnalisé ? Parfois non. Parfois oui, et j'ai été assez fou pour l'implémenter...

Pour l'ancien firmware NVR

Si vous avez le mot de passe, il y a une vulnérabilité d'injection de commande que vous pouvez utiliser : le script ftpupdate.py. Ce qui se passe, c'est que nous demandons à l'appareil de récupérer une mise à niveau via ftp et ftpget est utilisé pour effectuer cette tâche. Sans surprise, nos paramètres vont directement dans la fonction system().

Firmware plus récent

Dans le firmware NVR, le protocole binaire comporte la commande FILETRANSPORT qui fait exactement ce que son nom indique. Il n'y a en fait rien à ajouter, car vous pourriez aussi bien télécharger le SDK et utiliser la même commande. Bien sûr, je voulais la réimplémenter, donc pour voir comment cela fonctionne, regardez filetransport.py.

Les modèles IPC n'ont cependant pas cette commande, mais comme je l'ai dit plus tôt, nous pouvons toujours mettre à niveau le firmware. Bien que préparer la flash complète soit irréaliste, les paquets de mise à niveau de Tiandy nous permettent de remplacer des fichiers individuels, ce qui est exactement ce dont nous avons besoin (voir le dépaquetage du firmware).

Seulement, ce n'est pas si simple. Le format de fichier « box » contient des métadonnées, puis un tableau de fichiers. Le premier fichier doit être nommé ProductModule et doit contenir des paramètres d'appareil correspondants, sinon la mise à niveau ne se poursuivra pas. Nous avons besoin non seulement des valeurs de ces paramètres, mais aussi de ces paramètres eux-mêmes. De plus, la partie métadonnées (y compris la version du fichier box) est également vérifiée.

Assembler cela manuellement semble irréaliste, mais heureusement il y a une autre façon. Les exports de fichiers de configuration utilisent le même format de fichier « box », avec toutes les métadonnées correspondantes et le fichier ProductModule inclus, sans le champ du type de mise à niveau.

J'ai réussi à comprendre comment remplir ce champ, et donc à implémenter ce processus. Bien que le mécanisme soit également présent dans le firmware NVR, il ne fonctionne pas de la même manière, mais il n'y a aucun intérêt à poursuivre l'analyse puisque les NVR ont la commande FILETRANSPORT décrite précédemment.

Le script upgrade_rw.py utilise le processus de mise à niveau. Le nom suggère cependant quelque chose de plus... C'est parce que lors de l'exportation du fichier de configuration, nous spécifions quels fichiers exporter par nom et, sans surprise, n'importe quel fichier fonctionne. Nous pouvons donc télécharger la box et ensuite lire ce fichier en utilisant le même code que celui utilisé pour extraire le firmware.

L'export et la mise à niveau peuvent également être effectués via l'API web. Dans ce cas, il n'est pas possible de lire des fichiers arbitraires. J'ai quand même voulu implémenter cela car l'API semble plus stable, voir cgi_recover.py.

Ce que je n'ai pas examiné

Sur les modèles prenant en charge FTP, il pourrait être possible d'injecter des commandes shell dans le mot de passe utilisateur (lorsqu'une commande est exécutée pour ajouter cet utilisateur afin qu'il puisse se connecter via FTP).

Trouver des appareils Tiandy sur Internet

Les appareils Tiandy ont le port 3001 ouvert. C'est le port nécessaire pour les méthodes non-web. Les modèles plus récents ont le RTSP sur le port 9100 en plus du port 554, et ils ont aussi le RTMP sur le port 1935. Les modèles IPC utilisent le port 8082 pour ONVIF. HTTP et HTTPS fonctionnent sur leurs ports standard.

Les appareils avec l'ancienne interface web (utilisant notre bien-aimée technologie ActiveX) contiennent l'un des éléments suivants dans leur réponse HTTP :

root@kitploit:~
<title>Net Video Browser</title>
root@kitploit:~
tdvideo.css

Les appareils avec la nouvelle interface web (cette fois en utilisant... Flash) contiennent ceci dans la réponse :

root@kitploit:~
res/app-0.1.0.css

(l'en-tête Last-Modified se fait un plaisir de nous révéler la date de publication exacte)

Nous pouvons également identifier ces appareils par le certificat, bien que HTTPS ne soit pas toujours activé. Il n'y a que deux certificats utilisés pour tous les appareils et ils peuvent être trouvés dans le firmware téléchargé, ce qui rend leur épinglage inutile.

Le plus ancien :

root@kitploit:~
C=CN, ST=Tianjin, O=Tiandy Tech, CN=dvr_ui

Le plus récent :

root@kitploit:~
C=CN, ST=Tianjin, L=Tianjin, O=Tiandy Tech Ltd, CN=NetDevice

Au fait... Le support HTTPS est implémenté via un processus stunnel séparé. Cela fonctionne, mais sans surprise, l'adresse IP est perdue en cours de route, donc les journaux indiquent toujours 127.0.0.1.

URLs RTSP et RTMP de Tiandy

Tiandy prétend que ses appareils prennent en charge RTSP et RTMP. C'est cool, mais ce que nous ne trouvons pas dans le manuel, c'est comment utiliser réellement ces protocoles, car nous ne trouvons pas les URL RTSP et RTMP nécessaires. Heureusement, j'ai cette information comme sous-produit de l'analyse, je peux donc la partager.

URLs RTSP

Pour NVR :
Pour voir le flux en direct du canal C (commençant à 1) avec le type de flux S (1, 2, 3) :

root@kitploit:~
rtsp://username:password@host/C/S

Pour IPC :
Pour voir le flux en direct avec le type de flux S :

root@kitploit:~
rtsp://username:password@host/S

URLs RTMP

Les URLs RTMP ne sont pas si simples car elles nécessitent un hash personnalisé pour que la requête puisse être authentifiée. Cependant, RTMP permet également de lire le contenu enregistré.

L'URL pour le flux en direct est :

root@kitploit:~
rtmp://host/live/C/S/authstring

où C est le canal, S est le type de flux.

L'URL pour la lecture est :

root@kitploit:~
rtmp://host/vod/START-STOP/C/S/authstring

où START et STOP sont des horodatages Unix.

authstring est calculé comme suit :

root@kitploit:~
base64("username:"+md5("username:password")+":unix_timestamp")

L'outil rtmpauth.py peut le générer :

root@kitploit:~
python3 rtmpauth.py username password

Comme cet horodatage est vérifié et que la différence ne peut pas dépasser 2 jours, il y a des limites :

  • la caméra doit avoir l'heure correctement réglée
  • une URL RTMP cessera de fonctionner après 2 jours

Dépaqueter le firmware

Les mises à niveau du firmware sont emballées dans un format de fichier « box » propriétaire qui n'est ni signé ni chiffré. Ce format est en réalité très simple du point de vue du dépaqueteur. Il y a un en-tête que nous sautons, puis un tableau de fichiers à dépaqueter, où chaque fichier a un en-tête de taille fixe contenant le nom du fichier et sa taille (deux fois), puis les données suivent.

L'outil unbox.py dépaquette le fichier dans un répertoire nommé comme le fichier box ou dans le répertoire spécifié :

root@kitploit:~
python3 unbox.py [box_file]
python3 unbox.py [box_file] [target_dir]

Cet outil devrait être sûr à utiliser (j'ai écrit cette ligne, puis j'ai revérifié l'outil et trouvé une vulnérabilité... oups) car les chemins absolus sont convertis en chemins relatifs, .. est remplacé par __ et il n'y a pas de liens symboliques.

Parfois, vous devrez exécuter cet outil deux fois, car vous remarquerez que le fichier contenu dans un .box est un autre .box.

Télécharger l’outil