Heap Layout Optimisation for Exploitation (Technical Report)

Over the past decade a number of papers [5], [7], [8], [10] have approached the problem of Automated Exploit Generation (AEG) for stack-based buffer overflows. These papers describe algorithms for automatically producing a control-flow hijacking exploit, under the assumption that an input is provided, or discovered, which results in the corruption of an instruction pointer stored on the stack. However, stack-based buffer overflows are just one type of vulnerability found in software written in C and C++. Out-of-bounds (OOB) memory access from heap buffers is a common flaw in such software and, up to now, has received little attention in terms of automation. Heap-based memory corruption differs significantly from stack-based memory corruption in that with the latter the data which the attacker may corrupt is limited to whatever is on the stack, and thus can be varied by changing the execution path used to trigger the vulnerability. In contrast, for heap-based corruption it is the physical layout of dynamically allocated buffers in memory which determines what gets corrupted. Thus, the attacker must reason about heap layout in order to automatically construct an exploit; it is this problem which we address. To leverage OOB memory access as part of an exploit, an attacker will usually want to position some dynamically allocated buffer D, the OOB access destination, relative to some other dynamically allocated buffer S, the OOB access source.1 The desired positioning will depend on whether the flaw to be leveraged is an overflow or an underflow, and the control the attacker has over the offset from S that will be accessed. The key point is that the attacker wants to position S and D so that, when the vulnerability is triggered, D is corrupted with the least collateral corruption of other heap-allocated data, and without triggering a page fault. We say a heap layout is optimal if it minimises the distance between the source and destination. For example, suppose S is a buffer of size x and the flaw is an overflow that writes an attacker-controlled sequence of bytes starting at S and finishing at S + x+ 128. Furthermore, suppose D is a buffer that contains a function pointer p at offset 0. In order to corrupt p, an attacker must find a way to transition the heap layout into a state such that D is allocated at an address for which D − S + x ≤ 128. Allocators do not typically expose an API to allow a user to control relative positioning of allocated memory regions. In fact, the ANSI C specification [2] explicitly states The order and contiguity of storage allocated by successive calls to the calloc, malloc, and realloc functions is unspecified. The second major difficulty is that applications that use dynamic memory allocation typically do not expose an API allowing an attacker to directly interact with the allocator in an arbitrary manner. An exploit developer must first discover the allocator interactions that can be indirectly triggered via the application’s API, and then leverage these to solve the positioning problem. In practice, both problems are usually solved manually or with minimal partial automation, and this requires expert knowledge of the internals of both the heap allocator and the application’s use of it. In this technical report2, we first focus on the positioning problem under the assumption that one knows the interactions with the allocator that can be triggered. There is no existing analysis of the complexity of this problem, and no prior empirical work indicating the difficulty of solving real instances automatically. To establish a baseline approach, therefore, we present a pseudo-random black box algorithm that searches for an optimal layout. This has the merit of being practically and theoretically straightforward, and provides a comparison point for future work on more sophisticated solutions. We run this algorithm on a set of carefully-designed synthetic benchmarks, in order to provide an analysis of the factors that are most significant in determining the difficulty of individual instances. We then present a proof-of-concept system for fully automatic heap layout optimisation (HLO) on the PHP language interpreter. This system first maps the application’s interface to allocator-interaction sequences. It then uses the above search algorithm using the API exposed by the application. We evaluate the system on three vulnerabilities in PHP, showing that—despite its simplicity—the search algorithm can solve real-world instances3 .