Stack is protected: so we don't need secure coding?
Do anti-exploitation strategies displace secure programming?

Rumors say you were able to change the color from blue to red.
In a recent article I summed up some oldskool stack-overflow techniques - very 90ies. Today's situation differs, because of certain compiler extensions or operating system specifics. One might assume that because of these new and modern implementations (stack-)overflow exploits have no meaning today. And in fact if we take a look at the last Windows IIS 6.0 FTP vulnerability, we realize that it isn't exploitable on a never NT 6 host. What a pity. But why?
What prevents stack-smashing nowadays?
Bounds Checking
The overflow itself is a problem mainly based on the fact that there're checks for array and pointer references in respect of the buffer sizes. The programmer has to implement these checks. But if we could check every array or pointer with "Bounds Checking", any buffer overflow vulnerability would be unexploitable. There's a conceptual paper detailing that by Richard Jones and Paul Kelly from the Imperial College of Science in London. This has been implemented as a GCC patch: at the cost of performance. - So it's not a solution at all. It's very effective against Heap, BSS, Stack and stack overflows; but currently doesn't scale very well of course.
Stack Guard
Stack Guard is really used nowadays since GCC 4.1. The approach is directly countering the general methodology: it implements an integrity check right before the return address on the stack-frame. This is called Canary.
- #993333;">int main #009900;">(#993333;">int argc#339933;">, #993333;">char #339933;">*argv#339933;">*#009900;">[#009900;">]#009900;">) #009900;">{
- #993333;">char foo#009900;">[#0000dd;">42#009900;">]#339933;">;
- strcpy #009900;">(foo#339933;">, argv#009900;">[#0000dd;">1#009900;">]#009900;">)#339933;">;
- #b1b100;">return #0000dd;">0#339933;">;
- #009900;">}
If you grep through the assembly (gcc -S -o stacky.s stacky.c && cat stacky.s | grep canary_death_handler) you'll realize a function call that specifically instructs the program whose flow got altered to terminate in case the integrity has been damaged. More details are mentioned in Phrack 38 e. g. and numerous other papers. There're different kinds of Carnaries and so on. Basically it's that. However of course you should get a patched (recent) GCC and debug the hell out of the binaries it produces. You don't want to miss the real fun ;).
I'm not sure right now, but IBM's SSP concept seems to be very similar.
/GS
Actually this is the answer why the current IIS FTP exploit from milw0rm doesn't sucessfully target the vulnerability on newer Windows boxes. - M$ has an option similar to StackGuard for the Visual Studio C compiler since version 7: /GS. Server 2k3 and surely anything newer got compiled with it. It's sometimes called "Security Cookie".
There're certain differences: the Carnary is not static but consists of random values which get XORed with the return address. - And, and that's much more valuable: the Carnay is located before the frame-pointer; so it can detect frame-pointer overwrites reliably.
It reduces the chances getting a stack-overflow (I'd say) effectively. However BSS and or Heap overflows don't get prevented with this extension.
Stack Shield
This is different. It also adds option to the function pro- and epilog but:
The Stack Shield protection system copy the RET address in an unoverflowable location (the begining of the DATA segment) on function prologs (on function beginings) and check if the two values are different on function epilogs (before the function returns). If the two values are different the RET address has been modified so Stack Shield terminates the program or try to let the program run ignoring the attack (risking at maximum a program crash).
- Simply said: it blocks stack-smashing but doesn't detect it. You can explore it with your debugger of choice.
Libsafe
Libsafe is not a compiler extension. It dynamically loads the specific functions without being visible: instead of strcpy() from the standard C library it'll use strpcy() which checks the bounds. While this is quite complex and works fine against stack-overflows, it doesn't work for library functions libsafe doesn't check, doesn't work for frame-pointer overwrites, doesn't work for setjmp or longjmp constructs, BSS or Heap overflows.
The process environment
There're different platform specific countermeasures: a non-executable stack today is considered being standard in all major operating systems. - On Linux mainly there's PaX, which also adds ASLR; of course non-executable pages too. It randomizes Kernel and User stacks. I think it's awesome.
Windows systems have a quite strong ASLR, too. In fact the process environment within never Windows systems is strongly secured. There's WehnTrust, which contains sophisticated exploit mitigations. It even prevents SEH overwrites. ;)
So why secure coding?
When I do a code-review I sometimes fall on deaf ears because programmers nowadays believe they've got an easy job because of this. Have they? Can you just code like a first semester college student nowadays without producing dangerous situations? Let's ignore design errors for a moment. Let's even ignore that widely deployed embedded systems (routers. mobiles and stuff) very often do not have sophisticated exploit mitigation strategies. And let's ignore that specific vulnerabilities aren't prevented and that different platforms have specific weak-points.
The problem still is: it's possible. You can successfully exploit a stack-overflow on a newest Ubuntu that has got StackGuard enabled. You can exploit Windows systems that are used in production/critical environments. There's a chance you can. Maybe currently it requires some more sophistication end effort, maybe it's kind of complex. But at the end of the day we rely on systems. And just because there's a fall-back routine that doesn't allow every script-kiddy to write reliable exploits, by trying more often the success-rate isn't important: it just has to work once. And the last persons who get to know that it does is the programmer.
So don't forget the secure coding standard ;).
Have fun,
wishi

Post new comment