Despite the added protection provided by Microsoft in Windows 7, Windows buffer overflow attacks remain a very real prospect. In this article, the first in a four-part series, Robert Page, a researcher within Redscan Labs, provides a detailed explanation of what Windows buffer overflow attacks are and presents a technical illustration of how to identify vulnerabilities. Windows buffer overflow attacks have been occurring for over twenty years and can have a devastating impact on corporate data security. The threat from such attacks became a particular problem for some users of Microsoft’s Windows XP platform, prompting Microsoft to introduce significantly enhanced buffer security with Windows 7. However, the threat hasn’t gone away. Researchers at Redscan Labs have been conducting in-depth vulnerability assessments of Windows 7 and have concluded that Windows buffer overflow attacks are as much a threat today as they have ever been.
A buffer overflow occurs when an attacker is able to enter more data into a buffer than has been allocated by the program, leading areas of memory nearby to be overwritten. In particular, if an attacker can overwrite the CPU’s program counter (also known as Extended Instruction Pointer (EIP) on x86 computers) when the function’s epilogue is called, he or she can potentially execute code of his or her choosing rather than return to the calling function. This vulnerability is caused by a lack of sufficient bounds checking by the programmer when using certain functions in C/C++ languages. Exploiting buffer overflow vulnerabilities in recent versions of Windows requires hackers to circumvent two categories of security control:
1. Compiler security options /GS (Control stack checking calls) – A “canary” value is placed after the systems stack. If this value is overwritten execution of the program is terminated. /SafeSEH – A table of a program’s exception handers is created. If a program attempts to call an exception handler outside of this list, execution is terminated.
2. Operating system protection mechanisms Address Space Layout Randomisation (ASLR) – key data areas of an application are randomised in an effort to prevent an attacker from jumping to known functions in memory. Data Execution Prevention (DEP) – Prevents code being run from data pages such as the stack and default heap.
The Call Stack
The call stack is a data structure which stores information about active subroutines in a program. An active subroutine is one that has yet to hand back execution control to the point it was called. The call stack is composed of stack frames. Upon entering a function, a stack frame is created. The frame contains arguments to a given function, its local variables and the address at which the function will execute. Each time a new function is called, a new stack frame is created. When a function returns, its associated stack frame is removed. Figure 1 below gives a simplistic view of the call stack. With Intel CPUs the stack will grow to a lower memory address, so the top of the stack (i.e. buffer in our figure) points to lower memory addresses. A saved copy of the Extended Base Pointer (EBP) register is placed within the call stack. This value points to a fixed location within the stack frame of the function which is running to provide a reference point for further instructions. Following on from this, the frames return address is saved in the Extended Instruction Pointer, (EIP) which points to the next address to be executed. By entering a large string into the buffer, it is possible to overwrite the stack frames’ return address, allowing an attacker to divert execution to its own code. Parameters to a function are pushed onto the stack before the function is called. This may seem complicated, but in essence all we need to remember is if a hacker can overwrite the EIP value stored in the functions stack frame, he or she can gain control of the system.
|Saved Frame Pointer (EBP)|
|Return Address (EIP)|
|Parent Routines Stack|
Initial Discovery The best way to really understand how buffer overflow attacks work is to actually take a look at vulnerable software. In this article, therefore, I am going to walk readers through an example and for my target system, I will be using a 64-bit Windows 7 system running a “Simple Web Server” application which responds to HTTP requests. To follow along with this example, you can download a copy of the vulnerable software from www.exploit-db.com – using the following address: http://www.exploit-db.com/wp-content/themes/exploit/applications/142ba80cfca8f99ac36c92535728844c-sws-2.2-rc2-i686.exe To begin with, Redscan Labs uses the Spike fuzzer to determine if the application will crash if it receives large amounts of data. The table below shows the Spike configuration file (HTTP.spk), and the program being invoked with the generic_send_tcp command.
|root@redscan:~/Desktop# cat HTTP.spk s_string(“GET / HTTP/1.1rn”); s_string(“Host: 192.168.1.20 rn”); s_string(“Connection: “); s_string_variable(“”); s_string(“rn”); s_string(“rn”);root@redscan:~/Desktop# generic_send_tcp 192.168.1.20 80 HTTP.spk 0 0 Total Number of Strings is 681 Fuzzing Fuzzing Variable 0:0 Fuzzing Variable 0:1 Variablesize= 5004 Fuzzing Variable 0:2 Variablesize= 5005 Fuzzing Variable 0:3 Variablesize= 21 Fuzzing Variable 0:4 Variablesize= 3 Fuzzing Variable 0:5 Variablesize= 2 Fuzzing Variable 0:6 Variablesize= 7 Fuzzing Variable 0:7|
After a few seconds of running the Spike, the webserver crashes as shown in Figure 2. We can see that the application has crashed after entering 1824 “A” characters into the connection field of the HTTP request. The EIP now contains the number 41, since this is the hexadecimal representation of the “A” character. Now we know that it is possible to overwrite portions of the systems’ memory by entering long strings of characters, we can use this to take control of the system by overwriting the EIP with an address which points to code of our choosing.
So far, I have explained what Windows buffer overflow attacks are and clarified the role of the call stack. I have then identified a suitable target and illustrated how a ‘fuzzer’ tool can be used to see if the target is vulnerable to a buffer overflow attack (which, in this example, it is). In my next article, I will take this knowledge and start to show you how it can be misused.