Buffer Overflow
Learn about the types of buffer overflow attacks, examples, and how to prevent them.
Buffer overflow is a software coding error or vulnerability that can be exploited by hackers to gain unauthorized access to corporate systems. It is one of the best-known software security vulnerabilities yet remains fairly common. This is partly because buffer overflows can occur in various ways and the techniques used to prevent them are often error-prone.
The software error focuses on buffers, which are sequential sections of computing memory that hold data temporarily as it is transferred between locations. Also known as a buffer overrun, buffer overflow occurs when the amount of data in the buffer exceeds its storage capacity. That extra data overflows into adjacent memory locations and corrupts or overwrites the data in those locations.
A buffer overflow attack takes place when an attacker manipulates the coding error to carry out malicious actions and compromise the affected system. The attacker alters the application’s execution path and overwrites elements of its memory, which amends the program’s execution path to damage existing files or expose data.
A buffer overflow attack typically involves violating programming languages and overwriting the bounds of the buffers they exist on. Most buffer overflows are caused by the combination of manipulating memory and mistaken assumptions around the composition or size of data.
A buffer overflow vulnerability will typically occur when code:
The buffer overflow exploit techniques a hacker uses depends on the architecture and operating system being used by their target. However, the extra data they issue to a program will likely contain malicious code that enables the attacker to trigger additional actions and send new instructions to the application.
For example, introducing additional code into a program could send it new instructions that give the attacker access to the organization’s IT systems. In the event that an attacker knows a program’s memory layout, they may be able to intentionally input data that cannot be stored by the buffer. This will enable them to overwrite memory locations that store executable code and replace it with malicious code that allows them to take control of the program.
Attackers use a buffer overflow to corrupt a web application’s execution stack, execute arbitrary code, and take over a machine. Flaws in buffer overflows can exist in both application servers and web servers, especially web applications that use libraries like graphics libraries. Buffer overflows can also exist in custom web application codes. This is more likely because they are given less scrutiny by security teams but are less likely to be discovered by hackers and more difficult to exploit.
Common consequences of a buffer overflow attack include the following:
There are several types of buffer overflow attacks that attackers use to exploit organizations’ systems. The most common are:
Nearly all applications, web servers, and web application environments are vulnerable to buffer overflows. Environments that are written in interpreted languages, such as Java and Python, are immune to the attacks, with the exception of overflows in their interpreter.
Buffer overflow attacks are typically caused by coding errors and mistakes in application development. This results in buffer overflow as the application does not allocate appropriately sized buffers and fails to check for overflow issues. These issues are particularly problematic in the programming language C/C++ as it does not have buffer overflow protection built in.
This programming language is not the only one vulnerable to buffer overflow attacks. A buffer overflow program in Assembly, C, C++ or Fortran is also particularly vulnerable and more likely to enable attackers to compromise a system. However, applications written in JavaScript or Perl are typically less vulnerable to buffer overflow attacks.
Application developers can prevent buffer overflows by building security measures into their development code, using programming languages that include built-in protection, and regularly testing code to detect and fix errors.
One of the most common methods for preventing buffer overflows is avoiding standard library functions that have not been bounds-checked, which includes gets, scanf, and strcpy. Another common method is to prevent buffer overruns by using bounds-checking that is enforced at runtime. This automatically checks that the data written to a buffer is within the appropriate boundaries.
Modern operating systems now deploy runtime protection that enables additional security against buffer overflows. This includes common protection like:
Implementing security measures around development code and operating systems is not enough to protect organizations’ systems. When a buffer overflow vulnerability is discovered, it is crucial to quickly patch the software and ensure it is made available to all users.
A common buffer overflow example is when an attacker injects their malicious code into corrupted memory. Or they may simply take advantage of the buffer overflow and the adjacent memory corruption.
For example, a simple buffer overflow can be caused when code that relies on external data receives a ‘gets()’ function to read data in a stack buffer. The system cannot limit the data that is read by the function, which makes code safety reliant on users entering fewer than ‘BUFSIZE’ characters. This code could look like this:
“...
char buf[BUFSIZE];
gets(buf);
…”
Other buffer overflow attacks rely on user input to control behavior then add indirection through the memory function ‘memcpy()’. This accepts the destination buffer, source buffer, and amount of bytes to copy, fills the input buffer with the ‘read()’ command, and specifies how many bites for ‘memcpy()’ to copy.
“...
char buf[64], in[MAX_SIZE];
printf("Enter buffer contents:\n");
read(0, in, MAX_SIZE-1);
printf("Bytes to copy:\n");
scanf("%d", &bytes);
memcpy(buf, in, bytes);
…”
Another scenario for buffer overflow is when data properties are not verified locally. The function ‘lccopy()’ takes a string and returns a heap-allocated copy with uppercase letters changed to lowercase. The function does not perform bounds-checking as it expects ‘str’ to be smaller than ‘BUFSIZE’. An attacker can bypass the code or change the assumption of the size to overflow the buffer. An example of this code is:
“char *lccopy(const char *str) {
char buf[BUFSIZE]; char *p;
strcpy(buf, str);
for (p = buf; *p; p++) {
if (isupper(*p)) {
*p = tolower(*p);
}
}
return strdup(buf);
}”
Another example of buffer overflow is when code is too complex to predict its behavior. The below example is from the libPNG image decoder, which is used by browsers like Mozilla and Internet Explorer. The code appears safe as it checks the variable-length size but performs a ‘png_ptr->mode’ check that makes it more complicated. This can result in blind length checks in the ‘png_crc_read()’ call, which shows the importance of minimizing the complexity of code in memory operations.
“if (!(png_ptr->mode & PNG_HAVE_PLTE)) {
/* Should be an error, but we can cope with it */
png_warning(png_ptr, "Missing PLTE before tRNS");}
else if (length > (png_uint_32)png_ptr->num_palette) {
png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
return;
}
...
png_crc_read(png_ptr, readbuf, (png_size_t)length);”
A buffer overflow attack works when an attacker manipulates coding errors to overwrite computing memory. They can then carry out malicious actions like stealing data and compromising systems.
Buffer overflow is a vulnerability because it overflows memory storage capacity, which overwrites memory data.
A buffer stack overflow is a software coding error hackers can use to exploit a vulnerability and gain unauthorized access to corporate systems.
Please fill out the form and a knowledgeable representative will get in touch with you soon.