XXXX_heap_exploitation.pdf

(311 KB) Pobierz
Understanding the heap by
breaking it
A case study of the heap as a persistent data structure through non-
traditional exploitation techniques
Abstract:
Traditional exploitation techniques of overwriting heap metadata has been discussed
ad-nauseum, however due to this common perspective the flexibility in abuse of the
heap is commonly overlooked. This paper examines a flaw that was found in several
popular implementations of the GSS-API as a method for elaborating upon the true
beauty of data structure exploitation. This paper focuses on the dynamic memory
management implementation provided by the GNU C library, particularly ptmalloc2
and presents methods for evading certain sanity checks in the library along with
previously unpublished methods for obtaining control.
Outline:
0. The heap, what is it?
0.1 How the GNU C library implements it
0.2 Heap data structures
0.3 Implementation of heap operations
0.4 Putting it all together
1. Double free()’s
1.1 What is a double free()
1.2 Traditional double free() exploitation
1.3 Oops, it’s not 1996 anymore or why that technique doesn’t work anymore
2. The example
2.1 Code overview
2.2 Vulnerability 0 – array of pointers double free
2.3 Vulnerability 1 – double free of user-data
2.4 Goals – Write-what-where
3. The effects of a multi-threaded environment
3.1 thread safety in GNU libc’s allocator
1 Justin N. Ferguson
IOActive
3.2 what mutual exclusions don’t provide
3.3 GNU libc’s double free() protection
3.4 Abusing the system with this knowledge
4. Six million ways
4.1 Exploitation method 0: triple free of vulnerability 1 with fastbin’s (not exploitable
in this instance – previously unpublished method)
4.2 Exploitation method 1: double free of vulnerability 1 where thread X invalidates
thread Y’s heap reference (exploitable)
4.3 Expansion on method 1, setuid()/capabilities(7), threads and the heap (using an
unpriv’d thread to screw a priv’d one [linuxthreads specific])
4.4 Exploitation method 2: ptr = (pointer+offset) = pointer ??, double free of
vulnerability 0 where multiple pointers point to the same place (should be
exploitable)
4.5 Exploitation method 3: double free of vulnerability 0 where the backwards link is
overwritten (exploitable??)
4.6 I’m drawing a blank, but I’m sure there are more methods I came up with
5. Extra slides in case I run short
(esoteric stuff in case I run short in the presentation)
5.1 __dso_handle abuse
5.2 ???
Content
0.0 The heap, what is it?
The heap is a global data structure that provides dynamically allocated memory
storage that provides an ‘exists until free’ scope. It provides a compliment to the
stack in that it allows an application to allocate space for variables at run time that
can exist outside the scope of the currently executing function.
0.1 How the GNU C library implements it
The GNU libc library provides an implementation of dynamic memory allocation via
malloc()/free()/realloc()/et cetera as specified the the ISO/IEC C99 standard. This
implementation is provided by ptmalloc2 which was written by Wolfram Gloger and
is based on dlmalloc which was written by Doug Lea.
For those familiar with dlmalloc the only significant differences are that multiple
arenas/heaps are provided and multi-threaded applications are supported in a
‘mostly safe’ manner. For those unfamiliar with dlmalloc/ptmalloc2 the heap is
2 Justin N. Ferguson
IOActive
somewhat of a misnomer in that an application can have multiple heap, but to
simplify a heap is a section of linear memory that is either memory mapped or
obtained via sbrk(). Chunks are allocated either from the chunk of memory
known as the ‘top chunk’ (or sometimes referred to as the wilderness chunk) and
it is treated in a special manner in that it is the only chunk of memory that can
grow by requesting more memory from the system. New chunks are initially
allocated from this top chunk, but as memory use progresses chunks are usually
obtained by searching through a series of lists containing various chunks of free
memory, there are multiple variations on this list, some a doubly linked and sorted
whereas others contain only single links and are all the same size. These free lists
are referred to as bin’s within the implementation and thus this terminology is
continued throughout this paper. In some circumstances, where no chunk fits an
allocation request then it is possible to split an already existing chunk, this leaves
a smaller sub-chunk that is referred to as the last remainder chunk, and is
generally also treated special.
Allocated chunks in the same arena are maintained in the same linear space
and are navigated by size, meaning to find the next chunk of allocated memory
the pointer to the current chunk plus its size are summed together and then
aligned to find the next chunk. The allocated chunks of memory have the
characteristic that they may not directly border another allocated chunk, which
implies that all allocated blocks of memory either border the top chunk or a free
chunk.
Conceptually the heap can be visualized as one or more sections of linear
memory that contain any number of free and allocated blocks of memory
interspersed with each other. This provides an interesting possibility as a write to a
heap under invalid circumstances can overwrite metadata in a deallocated
chunk of memory, of if the write occurs to a dangling pointer, to an allocated
chunk of memory. An arena/heap is maintained via a series of data structures
which are described below in the next section.
0.2 Heap data structures
0.2.0 heap and arena data structures
The glibc heap is implemented via the following data structures, in order of their
appearance on a heap. The first is the heap_info
typedef struct _heap_info {
mstate
ar_ptr; /* Arena for this heap. */
struct _heap_info * prev; /* Previous heap. */
size_t
size; /* Current size in bytes. */
char
pad[-5 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
mstate ar_ptr:
3 Justin N. Ferguson
IOActive
a pointer to the heaps arena, this implies a one-to-
one relationship between heaps and arenas (jf: dc)
struct _heap_info *ptr
a pointer to the previous heap_info structure, the
heap_info structures are maintained in a circular
singular linked list (jf: dc)
size of the current heap
used for padding to ensure proper alignment
size_t size
char pad[…]
The heap_info structure is the first structure in a given heap, by implication you
would think it to be an incredibly important structure however when reviewing
operations it seems almost superfluous. The structure defines the most basic
information necessary for heap operations. Most importantly it specifies the size
of the heap and provides a pointer to the arena data structure.
The next structure that is more frequently used is the malloc_state structure, or
mstate.
struct malloc_state {
mutex_t
int
mutex; /* Serialize access. */
flags; /* Flags (formerly in max_fast). */
#if THREAD_STATS
/* Statistics for locking. Only used if THREAD_STATS is defined. */
long
stat_lock_direct, stat_lock_loop, stat_lock_wait;
#endif
mfastbinptr
fastbins[NFASTBINS]; /* Fastbins */
mchunkptr
top;
mchunkptr
last_remainder;
mchunkptr
bins[NBINS * 2];
unsigned int
binmap[BINMAPSIZE];
/* Bitmap of bins */
struct malloc_state *next;
/* Linked list */
INTERNAL_SIZE_T
system_mem;
INTERNAL_SIZE_T
max_system_mem;
};
mutex_t mutex:
Used to ensure synchronized access to
the various data structures employed by
the ptmalloc implementation, it is
normally obtained prior to calling the
_int_XXX() function, for instance when
you call free(), you’re actually calling
public_free() (jf: fix caps), which among
other things locks the mutex and calls
_int_free()
4 Justin N. Ferguson
IOActive
int flags:
Used to represent the various
characteristics of the current arena, for
instance if there are fastbin chunks or
not, if memory is non-contiguous, et
cetera.
long stat_lock_direct:
long stat_lock_loop:
long stat_lock_wait:
mfastbinptr fastbins[…]:
Used to provide various locking statistics.
This array is the array of fastbin’s which is
used as a bin for housing chunks that
allocated and free()’d, their operations
are quicker in large part due to less
operations being performed on them.
An in-depth look fastbin’s are discussed
below/later.
The top is a special chunk of memory,
that borders the end of available
memory, is not in any bin, represents
the total unallocated space for a given
arena and from subsystem initialization
always exists. Memory allocation
semantics are discussed later, along
with the description of the
malloc_chunk/mchunkptr data structure
Used when a small request for a chunk
of memory that does not fit exactly into
any given chunk of memory. It is the
remainder of the space left when a
chunk is split to accommodate a small
allocation request.
The bins array is similar to the fastbins
array in that it operates as a list of free
chunks of memory, however it is used
for larger ‘normal’ chunks; bins are
described in detail below.
Used as a one-level index to help speed
up the process of determining if a given
bin is definitely empty. This helps speed
up traversals by allowing the allocator
to skip over confirmed empty bins.
mchunkptr top:
mchunkptr last_remainder:
mchunkptr bins[…]:
unsigned int binmap[…]:
5 Justin N. Ferguson
IOActive
Zgłoś jeśli naruszono regulamin