Buffer overflow attacks involve sending overly long input streams to the attacked server, causing the server to overflow parts of the memory and either crash the system or execute the attacker’s arbitrary code as if it was part of the server’s code. The result is full server compromise or Denial of Service.
Some of the well-known Internet worms, including Code Red, Slapper and Slammer, use buffer overflow attacks to propagate and execute payloads. Buffer overflow vulnerabilities are some of the most common programming errors. The CVE vulnerability database indicates that 23% of all vulnerabilities uncovered during 2003 were buffer overflow vulnerabilities.
Applications routinely allocate memory buffers to store different types of data. For example, when the application asks for user input, it allocates a buffer to contain the input.
Consider a simple example in which the user is required to enter a phone number. The programmer might assume that users will not enter a phone number longer than 10 digits. Based on that assumption, the programmer might write the code to allocate a 15-character buffer to contain the returned input. But what would happen if the user returns an input that is 5000 characters long? Obviously, the allocated buffer would be too small to contain all the input. But the real question is what would the server do with the remaining 4,985 characters? Due to the specific structure of the server’s memory, the remaining characters will run over important parts of the application and could cause the system to actually execute parts of the input as if they were legitimate parts of the application code. Carefully crafted inputs can execute arbitrary commands on the server, usually with high permissions. Not so carefully crafted inputs can cause the server to crash while trying to execute meaningless input.
Applications consist of one or more operating system processes. Each process holds a memory block that is divided into three segments:
- Code: This segment contains the actual code for the application, i.e., the assembler instructions that the processor executes. The code execution process is non-linear, meaning that the processor can skip code and call functions on certain conditions. A special pointer, called EIP, or instruction pointer, is used to point to a specific memory address containing the code to be executed next.
- Data: This segment contains the memory space for variables and dynamic buffers.
- Stack: This segment is used for passing data (arguments) to functions and for storing functions’ variables.
Let’s focus for a moment on the stack, which is used to store information associated with function calls and is also the key for buffer overflow attacks. What exactly is a function? A function is a reusable piece of code that can be called from different locations in the code. A function can receive parameters and return a value. Parameters are passed to a function using the stack. Just before calling the function and executing its code, the system pushes the parameters into the stack. The return address, i.e. the address in the code from which the function was called and to which the system needs to return after executing the function, is also pushed into the stack. This is very important in the context of buffer overflow attacks. If the attacker is able to override the return address with a carefully selected address, then arbitrary code execution becomes possible. While executing, the function keeps reading and writing information to the stack. Once the function terminates, all its data elements are removed from the stack, including all parameters. The system then returns to the specific code address that appears on the stack.
How would the attacker override the return address? The attacker has limited control over one aspect of the stack using buffers that store parameters. If the programmer allocates a buffer of a specific size and the attacker provides an input longer than the defined size, the input would most probably overflow the buffer and override other parts of the stack, including the function’s return address that resides on the stack. By overriding part of the stack, the attacker can both inject a malicious execution code and set the return address to point to the malicious code. When the function returns, the attacker’s code is executed.
Although it sounds complicated to implement, skilled attackers easily uncover and exploit buffer overflow vulnerabilities to attack Web applications and databases. Buffer overflow attacks usually appear as very long parameter values associated with HTTP requests. For example, the following HTTP request was used by the Internet worm Code Red to exploit a buffer overflow vulnerability within the Microsoft IIS default.ida default page:
GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN%u9090%u6858%ucbd3%u7801%u9090%u6858%uc bd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u 531b%u53ff%u0078%u0000%u00=a
Buffer overflow attacks are prevented by enforcing boundary checking on input received from users. Each input should be carefully checked by the server to match the size expected. Inputs that exceed the allocated buffer size should be either truncated or blocked.
Buffer overflow attack prevention
|SOLUTION||BLOCKS BUFFER OVERFLOW ATTACKS?|
|Intrusion Detection Systems||No|
|Intrusion Prevention Systems||No|
Trying to uncover buffer overflows at the application level involves sending long parameter values to different parameters on different pages. The size of the parameter which can result in a buffer overflow varies and depends on the buffer size allocated by the application. If the buffer allocated by the application is 10 bytes long then a 50 bytes input might overflow it. On the other hand if the buffer is 300 bytes long then a 50 bytes input will not do any harm. This is why Intrusion Detection and Prevention Systems which are not Web application oriented cannot detect application level buffer overflows – they just cannot know what the allowed size for each parameter is. To know that, the product must learn the normal size of each parameter.
Imperva SecureSphere learns the size constrains of each parameter. Then the product also enforces some correlation rules which enhance the probability of detecting a buffer overflow attack. For example, the product correlates the HTTP request with the HTTP response. Buffer overflow attacks will usually generate error messages. If a long parameter generates an error message SecureSphere alerts for a possible buffer overflow attack. SecureSphere also checks the number of attempts to send long parameters. If the user keeps trying that then SecureSphere also alerts for a possible buffer overflow attack.