Day 9: Arbitrary Read

Finish to arbitrary read GOT table and bypass ASLR in llama.cpp

Author HungNguyen

#1. The perfectly round number 0 LOL

A month ago, when I started researching the first CVE (CVE-2026-34159) vulnerability in the RPC structure of the llama.cpp project, almost every part of the system felt unfamiliar to me, from ASLR mechanism, GOT table, tensor matrix structure, up to pointers on the RAM of RPC server

At that time, I even misunderstood that the Libc Base was the starting point of the GOT table, or mistakenly thought that the remote_ptr pointer returned from the response was the addr of buffer containing raw data. Many times server crash due to SIGSEGV error throughtout one week of debugging

Looking back now, most of those crash happened simply because I was interacting with memory structures that I did not yet understand


#2. Breaking The System Down

The turning point came when I started rebuilding its internal model from scratch

Instead of focusing on payloads and exploit code, I began auditing the implementation line by line, watch the general view of bug files, and sketching memory layouts on paper

During this process, I discovered that the ALLOC_BUFFER command actually creates two separate memory entities with their own function

  • remote_ptr point to a ggml_backend_rpc_buffer object allocated on the heap. Managing the backend buffer and storing the function pointers used by rpc layer
  • buffer_base respresents the memory region used to store tensor data

This changed how I approached the vuln, make me feel lighter for this researching


#3. Building an Arbitrary Read Primitive

The root cause of CVE-2026-34159 is an unsafe deserialization path inside deserialize_tensor

By sending a crafted tensor with buffer = 0, the server follows a code path that skips several important validation checks. As a result, an controlled value from client can be written directly into the tensor’s data field

Controlling a pointer alone is not enough. The challenge is converting that primitive into a reliable memory disclosure mechanism without crashing the server

To perform this, I combined serveral RPC commands into a single attack chain

  1. Construct a malicious graph using RPC_CMD_GRAPH_COMPUTE
  • That command have memcpy function, so when the bound checking was bypassed, I changed the copied data to an abr target addr
  • Point that to a stored data desination tensor (put legit buffer base to store that)
  1. Trigger GGML_OP_CPY
  • Set operation of destination tensor to above command, which used to copy data from src tensor to dst tensor
  1. Retrieve by RPC_CMD_GET_TENSOR
  • This command send tensor data to client, so using it like a good shoppee shipper

This transforms a pointer control bug into arb read primitive


#4. ASLR bypass

Even with arbitrary memory disclosure, ASLR still prevents direct access to useful runtime addresses

To bypass ASLR, I firstly leaked a function pointer stored inside the RPC buffer management structure. Because this pointer belongs to libggml-base.so, it provides a reliable reference into the loaded library image

Starting from this leaked address, I aligned it to page boundaries and scanned backwards page by page until the ELF header signature (0x464c457f) was found. Once the ELF header was located, the base address of libggml-base.so became known

From there, using offsets obtained from static analysis (objdump -R), I calculated the address of a GOT entry and used the arbitrary read primitive to leak its contents. The leaked GOT value revealed a runtime libc address, which in turn allowed calculation of the libc base address

At this point, ASLR was effectively neutralized


#5. Looking back

The most important lessong from this month was not how I can do it, it was learning to reason about system from the first principles

This bug is relatively small, but building an accurate model of how memory, objects, tensors and rpc command hit me down any times

Although I have only Arb Read, for me it is a journey of thinking and problem sovling mindset change that is so worth appreciating

Soon I will probably have to pause this research for a while to solidify the knowledge I just learned by playing CTF with other heap challenges, then return to reach the milestone of arb write along with RCE