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
EXPLOIT-CVE-2026-22778 — Preuve de concept d'exploitation pour CVE-2026-22778, une RCE non authentifiée dans le traitement vidéo de vLLM, démontrant la divulgation d'adresses du tas et un débordement de tampon du tas dans le décodeur JPEG2000 de FFmpeg. Inclut un laboratoire vulnérable pour des tests autorisés. | Kitploit
Outils/GitHubGitHub/joaovicdev/exploit-cve-2026-22778
Analyse des VulnérabilitésExploitationExploitation d'Applications WebFuzzingTests d'IntrusionApprentissage et ÉducationExploitation de BinairesLabs et Pratique
GitHub
joaovicdev/exploit-cve-2026-22778

EXPLOIT-CVE-2026-22778

Voir le dépôt
1il y a 9h 14mPas 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-22778, une RCE non authentifiée dans le traitement vidéo de vLLM, démontrant la divulgation d'adresses du tas et un débordement de tampon du tas dans le décodeur JPEG2000 de FFmpeg. Inclut un laboratoire vulnérable pour des tests autorisés.

Partager

CVE-2026-22778 — Exécution de code à distance dans vLLM lors du traitement vidéo

Laboratoire vulnérable + preuve de concept pour CVE-2026-22778 (CVSS 9.8), une chaîne d'exécution de code à distance non authentifiée dans le chemin d'ingestion multimodale de vLLM.

CVECVE-2026-22778
Avis de sécuritéGHSA-4r2x-xpjr-7cvv
Versions concernéesvLLM >= 0.8.3, < 0.14.1 (déploiements servant des modèles vidéo)
Corrigé dansvLLM 0.14.1
CVSS9.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Bogue sous-jacentCVE-2025-9951 — débordement de tas dans le décodeur JPEG2000 de FFmpeg

La vulnérabilité

Deux failles distinctes enchaînées. Un vllm serve par défaut n'a aucune authentification, donc les deux sont accessibles sans authentification sur /v1/chat/completions et /v1/invocations.

Étape 1 — Divulgation d'adresse du tas (contournement d'ASLR)

Lorsqu'une image ne parvient pas à être analysée, Pillow lève une exception dont le message intègre le repr() de l'objet BytesIO qu'il lisait :

root@kitploit:~
cannot identify image file <_io.BytesIO object at 0x7f4a9c2e1d50>

vLLM transformait les échecs de chargement de médias en HTTP 400 et renvoyait exc.detail au client sans modification (api_server.py) :

root@kitploit:~
async def http_exception_handler(_: Request, exc: HTTPException):
    err = ErrorResponse(
        error=ErrorInfo(
            message=exc.detail,          # <-- divulgue l'adresse telle quelle
            ...

Cette seule adresse réduit l'ASLR du tas d'environ 32 bits d'entropie à environ 3, ce qui rend l'étape 2 exploitable plutôt qu'un simple crash.

Étape 2 — Débordement de tas dans le décodeur JPEG2000

Une video_url est récupérée par le serveur et transmise à OpenCV :

root@kitploit:~
MediaConnector.load_from_url()      vllm/multimodal/utils.py
  -> OpenCVVideoBackend.load_bytes()   vllm/multimodal/video.py
    -> cv2.VideoCapture(BytesIO(data), backend, [])
      -> FFmpeg 5.1.x (fourni avec opencv-python-headless < 4.13)

vLLM a épinglé opencv-python-headless >= 4.11.0, qui fournit FFmpeg 5.1.x. Son décodeur JPEG2000 choisit le plan de destination directement dans la boîte de définition de canaux (cdef) du fichier — libavcodec/jpeg2000dec.c, write_frame_8 :

root@kitploit:~
if (planar)
    plane = s->cdef[compno] ? s->cdef[compno]-1 : (s->ncomponents-1);
...
int w = tile->comp[compno].coord[0][1] - ...;   /* depuis le composant  */
int h = tile->comp[compno].coord[1][1] - ...;   /* pas depuis le plan ! */

plane est contrôlé par l'attaquant mais w/h proviennent du composant en cours de décodage, et rien ne vérifie que l'un tient dans l'autre. Une entrée cdef de cn=0, asoc=2 envoie le composant 0 — le plan de luminance pleine résolution — dans le plan 1, le plan de chrominance sous-échantillonné 2×2.

Pour l'image 150×64 utilisée par cette PoC :

taille
Composant Y (écrit)150 × 64 = 9 600 octets
Plan U (destination)75 × 32 = 2 400 octets
Débordement7 200 octets au-delà de l'allocation

FFmpeg alloue chaque plan comme son propre AVBuffer, donc le débordement traverse les blocs de tas adjacents — y compris les structures AVBuffer contenant un pointeur de fonction free. Combiné à la fuite de l'étape 1, l'écrasement de ce pointeur est ce qui transforme la corruption en exécution de code.

Cette PoC s'arrête à la corruption mémoire. Elle prouve l'écriture hors limites en tuant le processus serveur. Le grooming du tas et l'écrasement du pointeur de fonction ne sont délibérément pas implémentés.

Le laboratoire

lab/app.py est une réimplémentation minimale du chemin d'ingestion multimodale de vLLM 0.13.0 — MediaConnector, ImageMediaIO, OpenCVVideoBackend et le gestionnaire d'erreurs pré-correctif, chacun annoté avec le fichier amont qu'il reflète. Le runtime du modèle est simulé : la vulnérabilité réside entièrement dans l'ingestion de médias, qui s'exécute avant l'inférence et ne nécessite ni GPU ni poids de modèle.

Tout sur le chemin d'attaque est réel — le même appel Pillow qui divulgue l'adresse, et le même appel cv2.VideoCapture vers un opencv-python-headless==4.11.0.86 non corrigé (FFmpeg 5.1.x, libavcodec 59.37.100).

Utilisation

root@kitploit:~
docker compose up -d --build
python3 exploit.py

Options :

root@kitploit:~
python3 exploit.py --target http://localhost:8000
python3 exploit.py --serve                  # livrer la charge utile via HTTP
python3 exploit.py --write-payload evil.jp2 # écrire simplement le fichier malveillant

L'exploit n'utilise que la bibliothèque standard — aucune dépendance.

Sortie attendue

root@kitploit:~
[*] Étape 1 -- Divulgation d'adresse du tas via le message d'erreur PIL
    HTTP 400
    cannot identify image file <_io.BytesIO object at 0xffff8f555300>
[+] Adresse du tas divulguée : 0xffff8f555300
    ASLR contourné : la base du tas est maintenant connue à ~3 bits d'entropie.

[*] Étape 2 -- Débordement de tas dans le décodeur JPEG2000
    Cible vivante : boot_id=95b62f18-13c0-4d6d-97d3-1b029207dc01 pid=1
    Charge utile : 203 octets, JP2 150x64 yuv420p
    cdef mappe le composant 0 -> plan 1 : écrit 9600 octets dans un plan de 2400 octets (débordement de 7200 octets)
    Requête jamais terminée : le serveur distant a fermé la connexion sans réponse
    Sondage de /health pour voir ce qui est arrivé au worker...
[+] Le worker a été tué et redémarré : boot_id 95b62f18-... -> 4494d28c-...
[+] Écriture hors limites confirmée.

Et côté serveur :

root@kitploit:~
$ docker compose logs vllm
cve-2026-22778-lab  | INFO:     POST /v1/chat/completions HTTP/1.1" 400 Bad Request
cve-2026-22778-lab  | corrupted size vs. prev_size
cve-2026-22778-lab  | INFO:     Started server process [1]

Nettoyage :

root@kitploit:~
docker compose down

La charge utile

203 octets, construite de zéro dans build_payload(). Un conteneur JP2 contenant un flux de code JPEG2000 minimal qui déclare trois composants en sous-échantillonnage 4:2:0 (afin que FFmpeg alloue une image yuv420p), plus une boîte cdef qui les remappe :

root@kitploit:~
cn=0, typ=0, asoc=2   <-- composant 0 (pleine résolution) dans le plan 1 (sous-échantillonné)
cn=1, typ=0, asoc=2
cn=2, typ=0, asoc=3

Les données de coefficients sont vides. Le décodeur alloue quand même l'image depuis l'en-tête SIZ et exécute quand même la boucle d'écriture, donc aucune donnée d'image réelle n'est nécessaire.

Correctif

vLLM 0.14.1, via trois PR :

  • #31987 — ajoute sanitize_message(), supprimant at 0x<addr>> des repr d'objets avant qu'ils n'atteignent le client.
  • #32319 — fait passer les chemins d'erreur restants par cette fonction.
  • #32668 — met à niveau opencv-python-headless vers >= 4.13.0, intégrant le correctif FFmpeg pour CVE-2025-9951.

FFmpeg en amont rejette désormais une carte cdef qui n'est pas une permutation des canaux, et dérive le format de pixel des indices remappés :

root@kitploit:~
int cdef_used = 0;
for (i = 0; i < s->ncomponents; i++)
    cdef_used |= 1<<s->cdef[i];
if (cdef_used != ((int[]){0,2,3,14,15})[s->ncomponents])
    return AVERROR_INVALIDDATA;

En remplaçant l'épinglage du laboratoire par opencv-python-headless>=4.13.0, la même charge utile échoue inoffensivement avec error during processing marker segment ff51.

Si vous ne pouvez pas mettre à niveau : ne servez pas de modèles vidéo, placez une authentification devant l'API, et restreignez la récupération de médias avec --allowed-media-domains.

Notes

  • Le laboratoire redémarre automatiquement après chaque crash, donc la PoC peut être exécutée de manière répétée.
  • Sur Apple Silicon, laissez docker compose compiler pour l'architecture arm64 native (par défaut). Forcer --platform linux/amd64 exécute le conteneur sous émulation, où le processus qui avorte reste bloqué au lieu de se terminer et le crash est plus difficile à observer.

Références

  • NVD — CVE-2026-22778
  • Avis de sécurité vLLM — GHSA-4r2x-xpjr-7cvv
  • Avis de sécurité FFmpeg — GHSA-39q3-f8jq-v6mg (CVE-2025-9951)

Avertissement

À des fins éducatives et de tests de sécurité autorisés uniquement. Exécutez-le contre le laboratoire de ce dépôt ou des systèmes pour lesquels vous avez une autorisation explicite de tester.

Télécharger l’outil