CS 161 Computer Security Paxson Spring 2011 1 20 Memory safety Attacks and Defenses In the next few lectures we will be looking at software security problems associated with the software implementation You may have a perfect design a perfect specification perfect algorithms but still have implementation vulnerabilities In fact after configuration errors implementation errors are probably the largest single class of security errors exploited in practice We will start by looking at a particularly prevalent class of software flaws those that concern memory safety Memory safety refers to ensuring the integrity of a program s data structures preventing attackers from reading or writing to memory locations other than those intended by the programmer Because many security critical applications have been written in C and because C has peculiar pitfalls of its own many of these examples will be C specific Implementation flaws can in fact occur at all levels in improper use of the programming language the libraries the operating system or in the application logic We will look at some of these others later in the course 1 Buffer overflow vulnerabilities We ll start with one of the most common types of error buffer overflow also called buffer overrun vulnerabilities Buffer overflow vulnerabilities are a particular risk in C Since it is an especially widely used systems programming language you might not be surprised to hear that buffer overflows are one of the most pervasive kind of implementation flaws around As a low level language we can think of C as a portable assembly language The programmer is exposed to the bare machine which is one reason that C is such a popular systems language A particular weakness that we will discuss is the absence of automatic boundschecking for array or pointer access A buffer overflow bug is one where the programmer fails to perform adequate bounds checks triggering an out of bounds memory access that writes beyond the bounds of some memory region Attackers can use these out of bounds memory accesses to corrupt the program s intended behavior Let us start with a simple example char buf 80 void vulnerable gets buf 1 20 CS 161 Spring 2011 Material courtesy Prof David Wagner 1 of 14 In this example gets reads as many bytes of input as are available on standard input and stores them into buf If the input contains more than 80 bytes of data then gets will write past the end of buf overwriting some other part of memory This is a bug This bug typically causes a crash and a core dump What might be less obvious is that the consequences can be far worse than that To illustrate some of the dangers we modify the example slightly char buf 80 int authenticated 0 void vulnerable gets buf Imagine that elsewhere in the code there is a login routine that sets the authenticated flag only if the user proves knowledge of the password Unfortunately the authenticated flag is stored in memory right after buf If the attacker can write 81 bytes of data to buf with the 81st byte set to a non zero value then this will set the authenticated flag to true and the attacker will gain access The program above allows that to happen because the gets function does no bounds checking it will write as much data to buf as is supplied to it In other words the code above is vulnerable an attacker who can control the input to the program can bypass the password checks Now consider another variation char buf 80 int fnptr void vulnerable gets buf The function pointer fnptr is invoked elsewhere in the program not shown This enables a more serious attack the attacker can overwrite fnptr with any address of their choosing redirecting program execution to some other memory location A crafty attacker could supply an input that consists of malicious machine instructions followed by a few bytes that overwrite fnptr with some address A when fnptr is next invoked the flow of control is re directed to address A Notice that in this attack the attacker can choose the address A however they like so for instance they can choose to overwrite fnptr with an address where the malicious machine instructions will be stored e g the address buf 0 This is a malicious code injection attack Of course many variations on this attack are possible for instance the attacker could arrange to store the malicious code anywhere else e g in some other input buffer rather than in buf and re direct execution to that other location Malicious code injection attacks allow an attacker to seize control of the program At the 1 20 CS 161 Spring 2011 Material courtesy Prof David Wagner 2 of 14 conclusion of the attack the program is still running but now it is executing code chosen by the attacker rather than the original software For instance consider a web server that receives requests from clients across the network and processes them If the web server contains a buffer overrun in the code that processes such requests a malicious client would be able to seize control of the web server process If the web server is running as root once the attacker seizes control the attacker can do anything that root can do for instance the attacker can leave a backdoor that allows them to log in as root later At that point the system has been owned Buffer overflow vulnerabilities and malicious code injection are a favorite method used by worm writers and attackers A pure example such as we showed above is relatively rare However it does occur for instance it formed the vectors used by the first major Internet worm the Morris worm Morris took advantage of a buffer overflow in in fingerd the network finger daemon to overwrite the filename of a command executed by in fingerd similar to the example above involving an overwrite of an authenticated flag But pure attacks as illustrated above are only possible when the code satisfies certain special conditions the buffer that can be overflowed must be followed in memory by some security critical data e g a function pointer a flag that has a critical influence on the subsequent flow of execution of the program Because these conditions occur only rarely in practice attackers have developed more effective methods of malicious code injection 2 Stack smashing One powerful method for exploiting buffer overrun vulnerabilities takes advantage of the way local variables are laid out on the stack We need to review some background material first Let s recall C s memory layout text region 0x00 0 heap stack 0xFF F The text
View Full Document