← THE INDEX  ·  WRITEUP

ASLR Bypass via Lua Function Pointer Leak in Aiven Managed Valkey

Any authenticated Valkey user can read 12+ C function pointer addresses from the server process by calling tostring() on Lua function objects, defeating ASLR for the valkey-server process.

Summary

Any authenticated user on Aiven's managed Valkey service can leak heap and code-segment memory addresses of the valkey-server process. The Lua scripting environment exposes the redis and server tables, which contain C function references. Lua's default tostring() behavior for C functions returns the literal memory address of the C function pointer, for example function: 0x7f76122ca790. The Valkey Lua sandbox does not override tostring() to suppress this. Calling it on every entry in the redis table reveals 12 or more distinct virtual memory addresses in the server's code segment.

Impact

Address Space Layout Randomization is the primary operating system defense against reliable exploitation of memory corruption bugs. Knowing one function pointer's address reveals the load address of the code segment, allowing an attacker to calculate the address of any function or ROP gadget in the binary. This makes any memory corruption vulnerability in the Valkey server significantly easier to exploit reliably.

Additional information exposed through other commands on the same instance: - CLIENT LIST reveals the internal IPv6 address of the server (fda7:...) - MODULE LIST reveals the full filesystem path to loaded shared libraries - HELLO reveals server configuration details - os.clock() via Lua reveals approximate process uptime in CPU seconds

A server restart randomizes the addresses (confirmed via previous crash tests), so the leak is valid only until the next restart.

Root cause

In Lua 5.1, tostring() on a C function value returns the string "function: 0x<address>" where the address is the actual memory location of the C function. Valkey inherits this behavior because the sandbox does not override tostring() for function values. The redis and server global tables in the EVAL environment contain many C function references that correspond to Valkey's internal command implementations. Overriding tostring() to return an opaque label (for example, "function: redis.call") for function values would eliminate the leak.

Proof of concept

The script below connects to Aiven Valkey over TLS and prints all C function pointer addresses from the redis table. All credentials and host identifiers have been replaced with placeholders.

Disclosure and fix

Reported to Aiven through their bug bounty program. Aiven triaged this as P3 (Medium). The recommended fix is to patch the Lua sandbox initialization to override tostring() for function values:

local _orig_tostring = tostring
tostring = function(v)
    if type(v) == "function" then
        return "function"
    end
    return _orig_tostring(v)
end

Alternatively, the redis and server tables can be replaced with proxy tables that wrap each function reference in a userdata that does not expose an address via tostring().