This material was developed with funding from the
National Science Foundation under Grant # DUE 1601612
You ask your family to create a grocery list for this week. The list is very long with many different items. You have a finite budget of $20 and when you add up all the cost of all of the items, it exceeds the $20 limit. Clearly the amount of food items your family wants exceeds the capacity of your budget.
Computer programs often operate on chunks of data. Programs allocate finite-sized blocks of memory, called buffers, to store data as they work on it. So what happens if like our grocery list, too much data is allocated to the buffer? A buffer overflow happens when the amount of data written to or read from a buffer exceeds the capacity of what it can hold. This is like our grocery list in which more items are written to the list than we can afford.
occurs when a program writes more data to the buffer than it is allocated to hold. The extra data can overwrite data values in memory addresses adjacent to the destination buffer unless the program includes sufficient bounds checking. Exploiting a buffer overflow allows an attacker to control or crash the process or to modify its internal variables.
a fixed length block of memory.
To understand why buffer overflows happen, it’s important to know that every individual byte of memory has a corresponding physical numeric address. This physical memory address is much like the aisle identifier for each item on the grocery list. When the processor loads and stores data from main memory (RAM), it uses the physical memory address of the location it wants to read and write from. When you go to the grocery store looking for your grocery items you refer to the aisle number for the items to locate them.
Physical Memory Address
refers to the location of a memory cell in the main memory used by both hardware and software for accessing data. Software, however, does not use physical addresses directly; instead, it accesses memory using a virtual address.
Virtual Memory Address
is an instance of a program running on the computer.
Virtual Memory Addresses
is a binary number in virtual memory that enables software to use a location in the memory to use more space than actually exists in primary storage by temporarily relegating some content elsewhere. The virtual address is then translated to the physical address.
Within our computers, software and the processor operate using virtual memory addresses as well. Our grocery list also has an additional identifier for each item which is the price, and this can be considered a virtual address. The operating system and processor together maintain a mapping between virtual memory addresses and physical memory addresses. Because each process gets its own set of addresses, this prevents one process from damaging the memory of any other.
In our grocery list, the grocery list items (the data) can be overwritten or the aisle numbers (physical address) and the price of the items (virtual address) can be overwritten resulting in exceeding the grocery budget.
The problem of buffer overflows is more serious because it can lead to code execution. This happens because those overflowed buffers don’t just overwrite data, they can overwrite those return addresses. The return address controls which instructions the processor will execute when it's finished with the current function.
ability to execute any commands of the attacker's choice on a computer or to a computer process.
Within our grocery list someone can control the information on the list and thus can use that control to add items they may wish. Similarly, if attackers can control the buffer overflow, they can control the return address and by extension they can choose what code the processor executes next. For example, the same buffer that was used to overwrite the return address can also be used to hold a short snippet of executable code that may download a malicious executable, or could open up a network connection, or do whatever else the attacker instructs.
In some cases, an attacker injects malicious code into the memory that has been corrupted by the overflow. In other cases, the attacker simply takes advantage of the overflow and it’s corruption of the adjacent memory. For example, consider a program that requests a user password in order to grant the user root access to the system. If the correct password is entered the program grants the user root access, and if the incorrect password is entered the user does not receive access. However, there is a possibility of a buffer overflow in this program because the gets() function does not check the size of the buffer that was established to store the password.
The attacker supplies a password input with a length greater than the 15 characters the buffer can hold. Because the gets() function doesn’t check the size of the buffer that was established to store the password, the buffer overflows and the memory immediately following the buffer is overwritten. Therefore, despite the incorrect password being entered, the program will execute the code immediately following the overwritten portion of memory. Specifically, the value of the variable “pass” will be set equal to 1 and the attacker will receive root access despite entering an incorrect password.
To prevent buffer overflow, developers should avoid standard library functions built into programming languages that do not check the buffer size, such as gets, scanf and strcpy. In addition, secure development practices should include regular testing to detect and fix buffer overflows. Another fix, is to have programs check for buffer size when they run, which automatically verifies that data written to a buffer is within acceptable boundaries.
This bit of code says that a buffer has been created which is 15 characters long and the variable pass is initially set to 0.
This subsequent bit of code says that the password entered by the user should be entered into the previous established buffer of 15 characters.
This next bit of code says that if the incorrect password is entered then the program should indicate to the user that the password was incorrect.
This next bit of code says that if the correct password is entered then the program should indicate to the user that the password is correct and the variable pass should be set equal to 1.
This final bit of code says that if a password is entered, the user is given root or administrative rights.