Memory management is a task known to demand high discipline and carefulness from software developers. Neglecting these requirements causes not only unstable but also vulnerable code. Exploitation of a memory corruption vulnerability can crash the application, manipulate data or in the worst case enable the attacker to execute arbitrary code on the machine running the application. Depending on the context of the vulnerable application, this possibly implies further exploitation steps such as the escalation of privileges, installation of a backdoor or leakage of confidential data.
Most modern programming languages thus decide to take over the task of memory management and have runtime environments containing garbage collectors. Still, there are several reasons why manual memory management is used directly or indirectly. High-level languages like Java or C# provide a binary interface to interact with low-level code. This feature is often utilized to implement performance-critical sections of an application in an efficient programming language or make use of existing libraries written in other languages. Interpreters or virtual machines of these languages themselves are usually written in a native language producing compilation artifacts which are understood by the processor. Another reason for manual memory management is the increasing distribution of embedded systems and Internet of Things devices. They foster efficient implementations to lower power consumption and minimize hardware requirements.
Making use of manual memory management always carries the potential for memory corruptions. In order to create secure software applications, developers need to know about possible attack vectors and mitigation strategies. At the same time, fully understanding memory corruption vulnerabilities requires in-depth knowledge about memory management and process execution. While many tutorials are available online, most of them are incomplete, outdated, not intended for beginners or not accessible for further improvement. This tutorial aims at providing its readers a theoretical understanding of memory corruption fundamentals, exploitation techniques and protection mechanisms. Paired with a collection of practical examples and a public platform, it represents a solid and open information source on this topic.
Although the concepts are valid for other operating systems as well, Linux is chosen as the primary platform for this tutorial. Reason for this is the high number of freely available tools and the openness of the system. Unless otherwise noted, this tutorial focuses on applications compiled for the widespread x86 processors.
To fully understand this tutorial, a basic knowledge of the C programming language and assembly is required. Additionally, the reader is expected to be confident in using a Linux operating system and its command line.
All visualizations and sample applications contained in this tutorial were self-created and are stored in an svn repository. Use the following command to check the repository out on your machine:
$ svn checkout svn://svn.proggen.org/wiki/memory-corruption
This work is published under a Creative Commons Attribution-ShareAlike 4.0 International License. If you share this work or create derived work based on it, please give appropriate credit by providing a link to the start page of this tutorial and indicate if changes were made. Furthermore, your contributions must be distributed under the same license as the original work.
|Overview||Continue with information about the author of this tutorial →|