Buffer Overflow, What Can Go Wrong and How to Fix It
Buffer overflow is a vulnerability, which is usually caused by uncareful handling of user input, but it does not end there. Most of the time it happens when data is being copied into a buffer, which does not have enough space and as a result part of the process memory is being overwritten. It might seem as not that big of a deal at first, but it should not be underestimated.
Here is a very basic example of a variable overflow:
In this example we are continuously adding 10 to a variable. It may seem like this code will never exit the while statement, because we can keep adding 10 to a variable forever, but that's not quite how it works in programming languages. The thing is that every variable type has some amount of memory allocated to store it's value, thus creating a limit. In this case I created an Integer, which only can store values that can be represented in 4 bytes of space (approximately from -2 billion to +2 billion). When we reach the maximum positive value and try adding 1 to it - we get the lowest value and vice versa.
Here is a debugger view of what happens:
Circled in blue is our value:
In this example we never modify variable 'i' directly, so like in the previous example it might seem like the content of the list "if" statement will never be executed. But this statement is only true as long as the parameter we pass to the program is less than 6 character long. When we use "XXXXXA" as a parameter it will set variable 'i' to 65 (or 0x41 in hex == 'A'). The reason why this happens is because Integer is declared after the Char array in memory and, since we do not specify how many chars to copy, function strcpy() copies everything that was passed to it. Here is a demonstration of what happens in the memory dump:
0x00, 0x94, 0xFF, 0x61, 0x00 are values in our buffer before executing strcpy(). Next 4 bytes (0x00) represent our integer value. Stepping over 2 times produces the following result:
Here is a simplified diagram of what happens in memory:
Now we can modify variables, but our capabilities do not end there. Let's take a look at the final example:
Like in the previous examples we never call the function directly, but with buffer overflow it is possible to overwrite the return pointer from main() function and replace it with the pointer to CanWeGetHere() function. In doing so we will overwrite other important pointers and possibly crash the program after executing the content of CanWeGetHere, but it does not really matter since it's just a demo.
Alright, so what do we need to accomplish our mission? First of all - we need to know where exactly user input is being copied to (0x0061FF2B), where is the closest return pointer (0x0061FF3C) and where do we want to jump (0x00401450, pointer to CanWeGetHere function). Once we know all that we need to generate a string, which will overwrite return pointer: "AAAAAAAAAAAAAAAAA" + 0x50 + 0x14 + 0x40. This is how our program looks like when we run it:
Whenever our program reaches return statement - it will jump to where we told it to.
Well, exploitation is fun and all, but how do we defend against buffer overflow attacks?
First of all by utilizing only safe functions in your code (replacing strcpy with strcpy_s/strncpy/strlcpy, which only copies specified number of bytes), checking lengths manually would not hurt.
Enabling security features in your compiler does a pretty good job as well (In g++ it's -fstack-protector-all -D_FORTIFY_SOURCE=2). Even if you decide not to use safe functions (which I strongly advise against), your program will detect when buffer has been overflown and crash, preventing further damage.
Another way to check for vulnerabilities and bugs in your code is by using static analysis tools, such as this one or this one.
If you still have any questions, please feel free to leave a comment or email me.
References, if you want to know more:
https://developer.apple.com/library/content/documentation/Security/Conceptual/SecureCodingGuide/Articles/BufferOverflows.html
https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88046682
https://www.cs.utexas.edu/~shmat/courses/cs380s_fall09/cowan.pdf
https://www.owasp.org/index.php/Buffer_Overflow
https://www.geeksforgeeks.org/c-data-types/
https://x64dbg.com/#start
Here is a very basic example of a variable overflow:
In this example we are continuously adding 10 to a variable. It may seem like this code will never exit the while statement, because we can keep adding 10 to a variable forever, but that's not quite how it works in programming languages. The thing is that every variable type has some amount of memory allocated to store it's value, thus creating a limit. In this case I created an Integer, which only can store values that can be represented in 4 bytes of space (approximately from -2 billion to +2 billion). When we reach the maximum positive value and try adding 1 to it - we get the lowest value and vice versa.
Here is a debugger view of what happens:
Circled in blue is our value:
Finally, value overflowed and we exited the loop:
This is just a simple variable overflow and it does not necessarily require user input. Let's take a look at something more interesting now:In this example we never modify variable 'i' directly, so like in the previous example it might seem like the content of the list "if" statement will never be executed. But this statement is only true as long as the parameter we pass to the program is less than 6 character long. When we use "XXXXXA" as a parameter it will set variable 'i' to 65 (or 0x41 in hex == 'A'). The reason why this happens is because Integer is declared after the Char array in memory and, since we do not specify how many chars to copy, function strcpy() copies everything that was passed to it. Here is a demonstration of what happens in the memory dump:
0x00, 0x94, 0xFF, 0x61, 0x00 are values in our buffer before executing strcpy(). Next 4 bytes (0x00) represent our integer value. Stepping over 2 times produces the following result:
Here is a simplified diagram of what happens in memory:
Now we can modify variables, but our capabilities do not end there. Let's take a look at the final example:
Like in the previous examples we never call the function directly, but with buffer overflow it is possible to overwrite the return pointer from main() function and replace it with the pointer to CanWeGetHere() function. In doing so we will overwrite other important pointers and possibly crash the program after executing the content of CanWeGetHere, but it does not really matter since it's just a demo.
Alright, so what do we need to accomplish our mission? First of all - we need to know where exactly user input is being copied to (0x0061FF2B), where is the closest return pointer (0x0061FF3C) and where do we want to jump (0x00401450, pointer to CanWeGetHere function). Once we know all that we need to generate a string, which will overwrite return pointer: "AAAAAAAAAAAAAAAAA" + 0x50 + 0x14 + 0x40. This is how our program looks like when we run it:
Whenever our program reaches return statement - it will jump to where we told it to.
Well, exploitation is fun and all, but how do we defend against buffer overflow attacks?
First of all by utilizing only safe functions in your code (replacing strcpy with strcpy_s/strncpy/strlcpy, which only copies specified number of bytes), checking lengths manually would not hurt.
Enabling security features in your compiler does a pretty good job as well (In g++ it's -fstack-protector-all -D_FORTIFY_SOURCE=2). Even if you decide not to use safe functions (which I strongly advise against), your program will detect when buffer has been overflown and crash, preventing further damage.
Another way to check for vulnerabilities and bugs in your code is by using static analysis tools, such as this one or this one.
If you still have any questions, please feel free to leave a comment or email me.
References, if you want to know more:
https://developer.apple.com/library/content/documentation/Security/Conceptual/SecureCodingGuide/Articles/BufferOverflows.html
https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88046682
https://www.cs.utexas.edu/~shmat/courses/cs380s_fall09/cowan.pdf
https://www.owasp.org/index.php/Buffer_Overflow
https://www.geeksforgeeks.org/c-data-types/
https://x64dbg.com/#start
Good post. Keep it up.
ReplyDelete