首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >GGML_GGUF 文件格式漏洞深度解读与挖掘思路

GGML_GGUF 文件格式漏洞深度解读与挖掘思路

作者头像
枇杷熟了
发布2026-03-26 13:57:25
发布2026-03-26 13:57:25
1650
举报
文章被收录于专栏:黑伞安全黑伞安全

全网 GGUF 漏洞挖掘体系综述

从内存破坏、模板投毒到供应链治理


导读

  • 阅读目标:理解 GGUF 格式的双重安全风险(解析器内存破坏 vs 模板逻辑投毒)
  • 适用人群:安全研究员、AI 基础设施工程师、模型运维人员
  • 核心收获:掌握从 Fuzzing 到静态审计的完整挖掘链路,获取工程化防御清单
  • 复现成本:中(需 C/C++ 基础与 ASAN 调试环境)
  • 风险等级:高(RCE + 供应链劫持)

摘要

本文深入剖析本地大模型推理生态中的核心文件格式 GGUF 存在的安全隐患。研究指出,GGUF 不仅是静态权重的载体,更因内嵌元数据与图灵完备的 Jinja2 模板而成为“活跃”的攻击面。通过解析器路径,攻击者可利用整数溢出(CVE-2024-25664 等)触发堆缓冲区溢出,实现远程代码执行(RCE)[1];通过模板路径,攻击者可在量化模型中植入恶意逻辑,利用 Hugging Face 的展示盲区实施供应链投毒与 Prompt 劫持[2]。

本文基于 Databricks、Cisco Talos 及 Pillar Security 的公开研究成果,提供了漏洞复现证据(ASAN 日志、PoC 片段)与挖掘方法论(Sanitizers、FormatFuzzer、静态审计)。最后,针对企业级应用,提出了包含 CI/CD 门禁、安全算术检查及模板白名单在内的工程治理清单,并探讨了“逻辑与数据分离”的未来演进方向。

术语小卡

  • GGUF:二进制模型格式,支持 mmap 直接加载,追求推理效率。
  • Chat Template:基于 Jinja2 的对话模板,定义 Prompt 结构,含逻辑控制。
  • Wraparound:整数回绕,N × Size 溢出导致分配变小,引发堆溢出。
  • Checked Arithmetic:使用 __builtin_mul_overflow 等防止算术溢出的安全编程范式。
  • Reproducible Builds:可复现构建,确保产物与源一致,提升供应链可验证性。

本文贡献

  • 双轨风险模型:系统性拆解解析器 RCE 与模板投毒的攻击面。
  • 证据链复核:集成 Talos ASAN 日志与 Databricks PoC,验证溢出机理[1]。
  • 结构化 Fuzz:提出基于 010 Editor 模板的格式化 Fuzzing 流程[3]。
  • 模板治理:构建“签名—白名单—透明化”的模板安全生命周期[2]。
  • 工程门禁:量化安全算术与 CI/CD 阈值,避免回归与漏检。

背景与问题陈述

随着 llama.cpp 等本地推理引擎的普及,GGUF 已成为 Hugging Face 上最流行的模型分发格式之一[1]。社区为了适配不同档次的硬件,衍生出 Q2_K、Q4_K_M、Q8_0 等繁杂的量化版本。这种“同一模型、多种文件”的生态现状,使得单一源头审计变得极其困难,任何一个量化变体都可能成为攻击者的载体。

现有防线存在盲区:ProtectAI、JFrog 等扫描工具主要侧重 Pickle 反序列化与传统恶意代码特征,往往忽略 GGUF 内部的模板逻辑。这创造了一个危险真空地带:攻击者可以发布一个通过静态扫描的 GGUF 文件,却在推理时通过渲染恶意模板执行 Prompt 注入或钓鱼攻击[2]。

历史一再证明:当文件格式开始承载逻辑时,它就不再是纯粹的数据。Google Project Zero 的 Mateusz Jurczyk 在“Effective File Format Fuzzing”中指出,任何复杂的解析器都是潜在攻击面[3]。GGUF 正处于这一演进的最新节点,它不仅包含张量数据,还封装了复杂的 KV 元数据和活跃的 Chat Template 逻辑。

攻击面框架:解析器路径 vs 模板路径

可控输入风险矩阵

关键字段

数据类型

操作类型

典型后果(CVE)

n_kv

uint64

malloc(n_kv * sizeof(kv))

整数回绕导致堆溢出(CVE-2024-25664)[1]

str.len

uint64

calloc(len + 1)

分配过小导致堆越界写(CVE-2024-25665)[1]

arr.n

uint64

批量分配/循环写入

批量越界写(CVE-2024-25667)[1]

GGUF_TYPE_SIZE[idx]

Index

数组索引查表

索引越界,获取错误 Size 导致溢出[1]

n_tensors

uint64

malloc(n_tensors * sizeof(info))

分配回绕,循环越界(CVE-2024-25666)[1]

解析器路径(Memory)

机理:利用整数溢出导致分配大小远小于实际写入量。

代码语言:javascript
复制
// 危险模式
size_t size = count * sizeof(Item);
void* ptr = malloc(size); // 溢出后 size 变小
// 循环按 count 写入,堆破坏

影响:RCE、DoS。

模板路径(Logic)

机理:在 GGUF 元数据中注入恶意 Jinja2 模板。由于量化模型常有独立元数据,攻击者可进行“供应链错位”投毒[2]。

隐蔽触发示例

  • • HTML 上下文:仅当用户请求生成网页/代码时注入恶意 JS。
  • • 登录诱导:检测到“login”关键词时伪造密码框。

证据与复现要点

内存破坏:源码与日志对照

Databricks 与 Talos 的发现揭示了 gguf_init_from_file 中的致命缺陷[1][4]。下列对照展示漏洞代码与 ASAN 现场:

代码语言:javascript
复制
// 1. 读取 n_kv (攻击者可控: 0x55...5a)
fread(&ctx->n_kv, ...);

// 2. 乘法回绕 (Wraparound)
// 0x55...5a * 48 = 0xE0 (高位截断)
size_t size = ctx->n_kv * sizeof(gguf_kv);
ctx->kv = malloc(size); // 分配极小堆块

// 3. 越界写入
for (i = 0; i < ctx->n_kv; ++i) {
  ctx->kv[i] = ...; // 远超分配范围,触发 Heap Overflow
}
代码语言:javascript
复制
==3991119==ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 8 at 0x610000000200 thread T0
#0 gguf_fread_str ggml.c:18658
#1 gguf_init_from_file ggml.c:18796
#2 llama_model_loader ...
0x610000000200 is located 0 bytes to the right of 192-byte region
allocated by thread T0 here:
#0 __interceptor_malloc ...
#1 gguf_init_from_file ...

复现 Checklist

  • • 编译参数:-fsanitize=address,undefined -g -O1
  • • 触发用例:将 Header 中 n_kv 设为 0x555555555555555a
  • • 最小退出条件:PoC 文件 payload 后立即截断(EOF),确保 malloc 已执行、fread 失败暴露 ASAN 报警。

模板投毒:Hugging Face UI 盲区

代码语言:javascript
复制
攻击者准备仓库文件1:clean_model.fp16.gguf(干净模板)文件2:poisoned_model.q4_k_m.gguf(恶意模板)Hugging Face UI 仅扫描文件1,显示“安全”用户为省显存下载 Q4 版本结果:用户获得恶意模板

核查步骤:逐个读取 GGUF 头部、提取 tokenizer.chat_template 字段,进行差分比对(见“实战案例:模板差异审计”)。

实战案例:从 PoC 到工程复现

案例 1:解析器整数溢出(CVE-2024-25664)

目标:构造极小 GGUF 文件,使 n_kv 极大但文件体积极小,欺骗分配器。

失败与坑位:文件过短会直接触发 EOF 返回 NULL,未执行到 malloc。需保证 Magic/Version 合法、payload 足以进入分配,再以 EOF 终止。

修复代码片段(Checked Arithmetic)

代码语言:javascript
复制
// 修复前
// ctx->kv = malloc(ctx->header.n_kv * sizeof(struct gguf_kv));

// 修复后 (使用 __builtin_mul_overflow)
size_t size_kv;
if (__builtin_mul_overflow(ctx->header.n_kv, sizeof(struct gguf_kv), &size_kv)) {
  return NULL; // 溢出检测
}
ctx->kv = malloc(size_kv);

案例 2:模板差异审计(Template Diff)

目标:验证同仓库下 FP16 原版与 Q4 量化版模板是否一致。

代码语言:javascript
复制
# 伪代码:提取并比较两个 GGUF 文件的模板字段

def extract_template(gguf_path):
    reader = GGUFReader(gguf_path)
    return reader.get_field("tokenizer.chat_template")

t1 = extract_template("model-fp16.gguf")
t2 = extract_template("model-q4_k_m.gguf")

if t1 != t2:
    print("[ALERT] Template Mismatch Detected!")
    print(diff(t1, t2))
else:
    print("[PASS] Templates are identical.")

审计结果:实战中发现多个社区量化模型为适配特定工具擅改 System Prompt,虽未必恶意,但证明供应链不透明。

研究方法:Sanitizers、Fuzz 与静态审计

动态检测(Sanitizers)与 Harness

编写极简 Harness 提高 Fuzz 吞吐率,避免加载完整运行时,仅保留解析逻辑:

代码语言:javascript
复制
#include "ggml.h"
// 编译:gcc -g -O1 -fsanitize=address,undefined harness.c ggml.c -o harness

int main(int argc, char **argv) {
  if (argc < 2) return 1;
  struct gguf_init_params params = {
    .no_alloc = true, // 仅解析元数据,不分配张量内存
    .ctx = NULL,
  };
  struct gguf_context * ctx = gguf_init_from_file(argv[1], params);
  if (ctx) gguf_free(ctx);
  return 0;
}

格式 Fuzzing(FormatFuzzer)

  • 解析模板:使用 010 Editor 的 gguf.bt 理解文件结构[3]。
  • 变异策略:重点变异 n_kvn_tensorsstr.len,尝试边界值(UINT64_MAX)。
  • 覆盖度度量:关注异常路径(Error Handling)的覆盖率,确保错误处理逻辑被充分测试。

静态审计规则集(Semgrep)

漏洞模式

Semgrep 逻辑

Malloc Overflow

malloc($X * $Y) 且无 mul_overflow 检查

Calloc Overflow

calloc($LEN + 1)(LEN 为最大值时回绕)

Unchecked Return

fread(...) 未检查返回值即使用数据

Index OOB

TypeSize[$IDX] 来自文件且未检查范围

防御与治理(工程落地清单)

模板治理流程

  1. 开始流程 → 系统启动模板安全检查流程。
  2. 模型导入 → 用户或系统尝试加载GGUF模型文件。
  3. 签名校验 → 系统检查模型是否具备可信的数字签名:
    • 若签名不可信 → 直接拦截阻断,流程结束。
    • 若签名可信 → 进入下一步白/黑名单检查
  4. 白/黑名单检查 → 系统根据预设名单对模型进行归类:
    • 若模型在白名单中 → 系统展示工具信息,允许用户加载,流程结束。
    • 若模型在黑名单中 → 直接拦截阻断,流程结束。
    • 若模型不在任何名单中(未知) → 进入沙箱/隔离环境进行安全分析。
  5. 沙箱/隔离分析 → 在受控环境中对模型进行动态行为监控。
  6. 人工审计 → 安全人员对隔离环境中的模型行为进行手动审查。
  7. 加入白名单 → 若人工审计确认模型安全,将其加入白名单。
  8. 展示工具信息 → 系统向用户展示模型相关信息。
  9. 用户加载 → 用户正常加载并使用模型。
  10. 流程结束 → 安全检查完成。

工程防御清单

  • 安全算术:所有分配长度计算强制使用 __builtin_mul_overflow 检查。
  • 默认禁用:推理工具默认不信任 GGUF 内嵌模板,除非显式 override 或加入白名单。
  • CI/CD 门禁:ASAN 回归测试必须 100% 通过;Fuzzing 每周至少运行 100 核心小时。
  • 透明度披露:发布模型时提供《模板完整性报告》,列出模板哈希与签名。

红队演练与蓝队对策

红队视角(Attack)

  • 触发词埋设:选择高频词("login"、"help")或长尾词(特定报错代码)。
  • 文件欺骗:利用文件列表顺序,将正常文件置顶,恶意文件混入量化列表。
  • 混淆技术:使用 Jinja2 编码特性(如十六进制)隐藏恶意 payload。

蓝队视角(Defense)

  • 静态扫描:建立规则库扫描常见 Web 攻击特征(<script>iframe)。
  • 动态审计:使用自动化 Harness 发送触发词集,监控渲染结果是否包含 HTML 标签。
  • 仓库差分:自动脚本拉取所有 GGUF 变体,计算模板哈希相似度。

复现与回归工程手册

环节

规范与标准

环境基线

GCC/Clang 最新版;开启 ASAN/UBSAN;覆盖 x86_64 与 ARM64 双架构

样本库管理

建立 corpus/ 目录,命名规范 cve-{id}-{field}-overflow.gguf;强制版本化管理

CI 集成

Pre-commit 阶段 Sanitizer 快扫;Nightly 阶段长时 Fuzzing

输出物

周报包含:新增 Crash 数、修复率、模板差分命中数、覆盖率变化

跨格式对比与研究议程

安全没有银弹。GGUF 在性能上无可匹敌,但安全性仍需补课。

格式

RCE 风险

逻辑/Prompt 风险

签名/验证链

生态工具成熟度

Pickle

极高(设计缺陷)

无标准

高(PyTorch 原生)

SafeTensors

极低(纯张量)

支持 Hash

中(HF 推广)

ONNX

中(解析器)

中(图逻辑)

支持

高(工业标准)

GGUF

高(C 解析器)

极高(内嵌模板)

社区依赖(弱)

极高(量化推理标准)

观点小结:未来核心在于“逻辑与数据分离”。理想状态下,GGUF 回归纯数据容器(类似 SafeTensors),将 Chat Template、Tokenization 逻辑剥离为独立、可审计的代码文件。然而,鉴于 llama.cpp“单文件分发”的巨大便利,这一拆分面临用户习惯阻力。短期内,“可验证量化”(Verifiable Quantization)——证明 Q4 模型确实源自特定 FP16 模型且无篡改——是工程攻坚方向。

总结与行动建议

GGUF 的兴起标志着“模型即代码”时代的到来,但也暴露了 AI 基础设施在传统二进制安全与供应链安全上的双重短板。对于安全从业者,这既是挑战也是机遇。

读者行动项

  • 立即行动(Now):启用 ASAN/UBSAN;审计现有 GGUF 库,提取并比对模板。
  • 近期计划(Next Week):建立模板白名单与签名流程;固化加载器基线;集成 Semgrep 规则。
  • 中期目标(Next Month):推进逻辑-数据分离的内部方案与可验证量化实验。

引用与致谢

  1. 1. Databricks. GGML GGUF File Format Vulnerabilities. https://www.databricks.com/blog/ggml-gguf-file-format-vulnerabilities
  2. 2. Pillar Security. LLM Backdoors at the Inference Level: The Threat of Poisoned Templates. https://pillar.security/blog/llm-backdoors-at-the-inference-level-the-threat-of-poisoned-templates
  3. 3. Mateusz Jurczyk. Effective File Format Fuzzing – Thoughts, Techniques and Results (BlackHat EU 2016). https://blackhat.com/docs/eu-16/materials/eu-16-Jurczyk-Effective-File-Format-Fuzzing-Thoughts-Techniques-And-Results.pdf
  4. 4. Cisco Talos. TALOS-2024-1912 Heap-based buffer overflow in GGUF string array parsing (llama.cpp). https://talosintelligence.com/vulnerability_reports/TALOS-2024-1912
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 枇杷熟了 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全网 GGUF 漏洞挖掘体系综述
    • 导读
    • 摘要
    • 术语小卡
    • 本文贡献
    • 背景与问题陈述
    • 攻击面框架:解析器路径 vs 模板路径
      • 可控输入风险矩阵
      • 解析器路径(Memory)
      • 模板路径(Logic)
    • 证据与复现要点
      • 内存破坏:源码与日志对照
      • 模板投毒:Hugging Face UI 盲区
    • 实战案例:从 PoC 到工程复现
      • 案例 1:解析器整数溢出(CVE-2024-25664)
      • 案例 2:模板差异审计(Template Diff)
    • 研究方法:Sanitizers、Fuzz 与静态审计
      • 动态检测(Sanitizers)与 Harness
      • 格式 Fuzzing(FormatFuzzer)
      • 静态审计规则集(Semgrep)
    • 防御与治理(工程落地清单)
      • 模板治理流程
      • 工程防御清单
    • 红队演练与蓝队对策
      • 红队视角(Attack)
      • 蓝队视角(Defense)
    • 复现与回归工程手册
    • 跨格式对比与研究议程
    • 总结与行动建议
    • 引用与致谢
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档