A buffer overflow occurs when a program or process attempts to write more data to a fixed length block of memory, or buffer, than the buffer is allocated to hold. Since buffers are created to contain a defined amount of data, the extra data can overwrite data values in memory addresses adjacent to the destination buffer unless the program includes sufficient bounds checking to flag or discard data when too much is sent to a memory buffer.
Exploiting a buffer overflow allows an attacker to control or crash the process or to modify its internal variables. Buffer overflow always ranks high in the Common Weakness Enumeration/SANS Top 25 Most Dangerous Software Errors and is specified as CWE-120 under the Common Weakness Enumeration dictionary of weakness types. Despite being well understood, buffer overflows continue to plague software from vendors both large and small.
A buffer overflow can occur inadvertently, but it can also be caused by a malicious actor sending carefully crafted input to a program that then attempts to store the input in a buffer that isn't large enough for that input. If the excess data is written to the adjacent buffer, it overwrites any data held there. If the original data includes the exploited function's return pointer -- the address to which the process should go next -- an attacker can set the new values to point to an address of his choosing. The attacker usually sets the new values to point to a location where the exploit payload has been positioned. This alters the execution path of the process and effectively transfers control to the attacker's malicious code.
Programming languages like C and C++ are prone to buffer overflow attacks as they have no built-in protection against accessing or overwriting data in any part of their memory and as actors can perform direct memory manipulation with common programming constructs. Modern programming languages like C#, Java and Perl reduce the chances of coding errors creating buffer overflow vulnerabilities, but buffer overflows can exist in any programming environment where direct memory manipulation is allowed, whether through flaws in the program compiler, runtime libraries or features of the language itself.
Techniques to exploit buffer overflow vulnerabilities vary based on the operating system and programming language, but the goal is always to manipulate a computer's memory to subvert or control program execution. Buffer overflows are categorized according to the location of the buffer in the process memory, the two main types being stack-based overflow and heap-based overflow.
The stack is a continuous space in memory used to organize data associated with function calls, including function parameters, function local variables and management information, such as frame and instruction pointers.
The heap is a memory structure used to manage dynamic memory. Programmers often use the heap to allocate memory whose size is not known at compile time, where the amount of memory required is too large to fit on the stack or where the memory is intended to be used across function calls.
Other buffer-related attacks include integer overflow, which is when a number is used in an operation, the result of which requires more memory to store. For example, 8 bits of memory are required to store the number 192. If the process adds 64 to this number, the answer 256 will not fit in the allocated memory, as it requires 9 bits.
Format strings attacks alter the flow of an application by using string formatting library functions like printf and sprintf to access other memory space.
The most common reason why buffer overflow attacks work is because applications fail to manage memory allocations and validate input from the client or other processes. Applications developed in C or C++ should avoid dangerous standard library functions that are not bounds checked, such as gets, scanf and strcpy, and instead use libraries or classes explicitly created to perform string and other memory operations securely. User input and data from untrusted sources should always be validated to ensure that they are within the bounds of what's expected and to prevent overly long input values.
Vendors issue patches and updates for their software to fix buffer overflow vulnerabilities that have been discovered, but there is still a period of risk between the vulnerability being discovered and the patch being created and deployed.
Most operating systems have introduced runtime protections to make it harder for overflow buffer attacks to succeed. Address space layout randomization randomly arranges the address space positions of key data areas of a process, including the base of the executable and the positions of the stack, heap and libraries. This makes it difficult for an attacker to reliably jump to a particular function in memory.
Data Execution Prevention marks areas of memory as either executable or nonexecutable. This prevents an attacker from being able to execute instructions written to a data area via a buffer overflow.