The attack we have just deconstructed is called a stack smashing attack. The term was coined by the hacker with the handle Aleph One in his famous 1996 article in Phrack Magazine titled Smashing the Stack for Fun and Profit, which you can still find online. The reason for the name is obvious. The attack overwrites or smashes important data on the stack to enable illicit actions. Revisiting the three security properties we briefly discussed in the introductory lecture, confidentiality, integrity,and availability, we can see that stack smashing is a violation of integrity. The attack has corrupted important data in the program and enabled further corruption of data on the system by allowing arbitrary code to run on behalf of the attacker. Stack smashing can also reduce availability by simply crashing the program or injecting code to make it unresponsive. For the remainder of this unit we will take a brief look at other attacks that are a variation of stack smashing. They too will take advantage of bugs involving the use of memory, but they will consider memory allocated in different places, and they may read memory illicitly rather than write to it. Another sort of attack is a heap overflow attack. While stack smashing overflows a stack allocated buffer, you can also overflow a buffer allocated by malloc which resides on the heap. This code gives an example. At the top we define a struct, vulnerable_struct, that has two fields, the first is buff, a character pointer, the second is the compare function pointer. Below, we see a function, foo, that takes a vulnerable struct as an argument along with two character pointer arguments. To begin, the first line of the function copies one into buff, the second line copies two past one into buff. Finally, the third line calls the compare function pointer, passing buff as an argument and comparing it against the foobar file pointer. Now you may have noticed that this code is only going to work properly if the string length of one and two is less than the maximum length of the buffer into which they were copied. Otherwise, we will overwrite the compare function pointer. Just as when we overwrite the return address in a stack smashing attack, the adversary may be able to control how this overwrite happens and get the program to run code of his choice. There are many variants of this basic heap overflow attack. One variation applies to programs written in C++, which extends C with support for object orientated programming. C++ objects consist of data and methods as defined by a class. Classes support inheritance. So a method in a parent class can be overrridden by a method defined in inheriting child class. C++ supports sub-type polymorphism so that a child class's object can be used where a parent class object is expected. As a result, the compiler cannot be sure whether an object declared to have a type T really does have type T or has a type that inherits from T. To handle this situation all objects are compiled to have what is called a vtable. This is an array containing pointers to the code of each of the objects' methods. The code used to call a method simply indexes the vtable using a fixed offset that corresponds to the desired method. Now for this to work, the vtable has to be at a standard location within an object. Wherever it happens to be, the fields containing the object's data are nearby. If one of those fields is subject to a buffer overflow, then the vtable could be corrupted and a method function pointer overwritten. This is analogous to the situation we just saw with the vulnerable struct in C. Both this and the earlier attack we saw overflowed a buffer into another field of the same object. An alternative is to overflow into an adjacent object. For example, one containing a function pointer. This is more challenging because the attacker may need to work to get the right kind of object nearby the one he can overflow, but it can be done. A related attack aims to overflow not a program object but instead the metadata that malloc uses to keep track of heap allocated memory. Oftentimes the memory just before the pointer returned from malloc contains a header. This header may contain pointers, for example, linking the returned object into a list of allocated data. Data not currently in use by the program will be linked in a free list instead. By corrupting this data, an attacker can cause the code implementing malloc and free to carry out actions to his advantage. Another sort of attack that's often considered in its own right is an integer overflow attack. These attacks rely on the fact that in C, a variable has a maximum value, and when that value is exceeded, the variable's value will wrap around. In this case, we're reading in from the network using the packet_get_int function. Suppose that the adversary has control of the other side of the network and is sending a very large number. In fact, suppose the number is 1,073,741,824, and that the size of a character pointer on our architecture is 4, in other words, it's a 32-bit architecture. Obviously nresp is greater than zero, and so we will malloc a buffer into which we store a response. Now the adversary has arranged it so that this very large number times 4, wraps around to 0. Many malloc implementations will happily allocate a size zero buffer, and then, the subsequent writes to that buffer are overflowing it. Of course, just as in all of the other attacks that we have seen, this overflow may be controllable so that the adversary can inject code or otherwise have his way. Many of the attacks we have shown so far affect code, return addresses, and function pointers, but we can also affect data as well. For example, the attacker might overrun a buffer to modify a secret key to be one known to him and therefore he can decrypt future intercepted messages using that key. He might also modify state variables to bypass authorization checks, for example, we showed this with the authenticated flag when first introducing the idea of buffer overflows. He might also modify interpreted strings, used as part of subsequent commands sent to other programs. For example, server programs that communicate with databases will often do so using SQL. SQL commands may be overwritten by buffer overflows to get the attacker access to arbitrary portions of the database. So far we've just been interested in what happens when you write past the end of a buffer, but a bug could also permit reading past the end of the buffer, this might leak secret information. As an example, consider this program, the program is going to read into buf from stdin, then it will echo back the number of characters specified. Here we're reading in an integer, we first read into the buffer and then call the atoi function to convert the contents of that buffer, a string, into an integer length. Next we read in a message. Finally, we echo back that message by iterating up to the length specified, printing out the characters one at a time. Where's the problem? The problem is that the length that was specified in the first read may exceed the length of the message provided in the second read. If it does, it's going to print out characters beyond what was read in. Here's an example run of this program. We start the server, enter in a number, and then enter a message. In this case, the number does correspond to the length of the message and the program echoes back the message as expected. Here the number is slightly less than the length of the message and, as expected, fewer characters are returned. Here, the number is greater than the length of the message, and we can see that extra data is printed out beyond what was entered. This data is leaked. It was whatever read in previously. The Heartbleed bug is an example of a high profile buffer overflow, discovered in early 2014, that involves reading data rather than writing it. By some estimates, Heartbleed affected nearly 600,000 servers on the Internet. The bug was in the implementation of the so-called heartbeat functionality of the SSL protocol. This functionality allows a client to send a heartbeat message to the server, asking it to respond back to confirm the connection is still active. The heartbeat message contains a length field that indicates the length of the portion of the message to echo back. The bug in the SSL server was that it did not check the length was accurate. In fact, it could be much longer than the heartbeat message itself. By specifying a long length, the attacker could get the buggy server to read beyond the buffer containing the heartbeat message and therefore, return whatever was in nearby memory. Depending on the activities of the server prior to the overflow, nearby memory could contain things of interest to the attacker, such as passwords, cryptographic keys, or other items specific to the server using SSL. Another interesting memory bug occurs when dealing with stale memory. A dangling pointer bug occurs when a pointer is freed but the program continues to use it. An attacker may be able to arrange for the freed memory to be reallocated, and then under his control prior to the program using the pointer that was previously freed. So here's an example at the bottom. We have a struct again with a compare function pointer in it. Here we allocate it, and then free it. Now, suppose some time goes by and malloc is called and it reuses the memory that we just freed, allocating it now to this buffer pointed to by q. q stores to it some random value. Worse, maybe the attacker can control what was stored to the value using q. Now later on, the program reuses p despite the fact that it freed it by calling the compare function pointer. And in this case, it has to reference a dangling pointer and is going to go straight to the memory that the attacker put there. In fact, it was just this sort of bug that played a huge role in the attack that China had on Google back in 2010. An invalid pointer was accessed after an object was deleted in Internet Explorer.