Google NUL Poison attack
- Required reading
- Constraints and and
- Heap manipulation
Memory corruption vulnerabilities can arise from very benign programming errors and can lead to arbitrary code execution if exploited by a skilled attacker.
One byte overflows are no different and can be leveraged to craft fully fledged exploits against binaries linked to the Gnu C Library’s memory allocator, which is derived from ptmalloc (pthreads malloc), which in turn is derived from dlmalloc (Doug Lea malloc).
This technique was originally discovered by Google Project Zero’s team, as an
updated version of The House of Einherjar,
NUL byte overflow exploitation technique dating several years prior to 2014.
As many modern heap exploitation techniques, it can be used to leak memory addresses by obtaining two malloc chunks overlapping the same memory region. One considered free and the other one allocated and attacker controlled.
This post covers backward consolidation specifically, but the principles can be applied to forward consolidation as well.
The reader should be familiar with malloc internals before reading the following chapters:
Constraints and and
NUL termination errors
One of the core differences in this version of the attack
is the lack of control of the
termination errors are typical of string related tasks,
therefore an attacker would not be able to
as they would terminate the string supplied
prematurely, being restricted to impractically
0x0000000000000090 would terminate the string
provided before overflowing into the
Even worse, they might not be able to control the
prev_size quadword at all
, which might have program-defined value (such as a string suffix).
In order to achieve its goal, which is creating two overlapping chunks, an
attacker needs to be able to somewhat control memory allocations.
Such degree of control over the memory layout may look unrealistic at first sight, but its actually a very common instance of any program running a scripting engine.
Initial memory state
Note: this assumes a GLIBC version < 2.26
Start by allocating 4 consecutive chunks
D:will of sizes
0x20 respectively. Note that chunk
D is only used
to prevent consolidation with the top chunk and as such is not strictly necessary.
B, the runtime will set
C.prev_size = 0x210 and
B is added to the unsortedbin as its size does not fit any of the
fastbins (singly-linked lists holding sizes from
Leveraging the overflow
Now it’s the time to use the overflow bug at the attacker’s disposal:
B and decrease its size from
Keep in mind that
C.prev_size is still
Request a chunk
B1 of size
0x100. Malloc searches through its unsortedbin
for a block of size greater than or equal to
B, it triggers remaindering, linking the remaining
bytes into the unsortedbin.
Request a chunk
B2 of size
0x100: malloc tries to access the next chunk at
&B2+chunk_size(B2) and tries to set its
prev_inuse bit to 1. Fortunately, this happens to be exactly
C, therefore leaving its fields untouched.
Any requested size is fine, requesting a
0x100 chunk requests the last
remainder leaving the heap in a cleaner state.
B1, setting up a backward consolidation that starts from chunk
C and goes all the way back to
this triggers the backward consolidation and create a free chunk spanning from
C therefore overlapping
B2, which is still allocated.
Allocating a big enough chunk will trigger remaindering once again and links
the remainder into the unsortedbin, thus setting the first two quadwords of
to the address of the unsortedbin.
Leakage of memory addresses
If this attack is used in the first stage of an exploit, usually an attacker
leaks libc and heap addresses via this memory setup:
Leaking a libc address is as simple as getting an chunk into the unsortedbin (therefore setting its forward and backward pointers) and reading one of these values by reading memory from a chunk overlapping the one just free’d.
« CVE-2018-1160: Netatalk RCE