Exception Handlers Are Baaad
I've said a lot of times that incorrect use of exception handlers will get you hacked. I go into some detail on this in WSCV, due out shortly. It's recently come up in regards to the .ani issue currently making the rounds. From the full disclosure list:
Alexander Sotirov said:
Read our advisory: https://www.determina.com/security.research/vulnerabilities/ani-header.html
It explains that the vulnerable code is wrapped in an exception handler that
recovers from access violations. That means that you can trigger the exploit
multiple times and try different addresses, increasing the chance of hitting the
right one (you only need 128 tries on average)
Not only can things like this happen, which defeats the purpose of ASLR, but the more exception handlers there are to play with, the more targets you can hit by overwriting an exception record.
There are a couple of exceptions to this rule - one of the first is when calling MapViewOfFile – from the SDK:
__try
{
dwLength = *((LPDWORD) lpMapAddress);
}
__except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Failed to read from the view.
}
If this happens, you can safely try and page the memory in, and if it succeeds, continue. If you have /EHa set in your compiler options, doing a catch( … ) is just as bad as hard-coding EXCEPTION_EXECUTE_HANDLER in as the argument to __except. Please note that I am NOT saying not to use C++ exceptions – if your code is exception safe, and releases resources correctly in destructors, AND you understand the exceptions you're catching, it's extremely efficient and the compiler guys tell me this optimizes your perf. I have effectively used try-except as well, but you must understand what you can and cannot catch. Also note that I'm talking user mode programming, NOT kernel mode, which is a different universe.
It's been interesting watching the commentary, trying to figure out how to overcome ASLR, NX, low rights (protected mode IE), etc. As I pointed out in WSCV, ASLR can be defeated if you give the attacker multiple attempts, which is what the overactive exception handler is doing. The right way to do this is to catch very specific exceptions that you understand, and in the case of access violations, it is never really safe to execute the handler – the best you can do (while this still incurs some risk) is to dump the stack and the registers, and then exit the app. This is one reason why we've made the decision that in some cases we just want to take the app down with an unhandled exception. If you are using exception handlers, use SafeSEH – something cool about 64-bit – they go in the binary. One other thing about ASLR – it can take place on really 3 different levels – the stack could be in 256 different places, the heap could start in 256 different places, and any given DLL could be in 256 different places. If the exploit depends on only knowing one of these, you have a 1 in 256 chance, but if the exploit depended on knowing 2 of these, you only have a 1 in 64k chance, which is harder. I view ASLR as a speed bump – it makes worms a lot harder to write, but it won't flat out prevent something from being exploitable at all.
As some of you may recall me saying a couple of posts ago, it's a foolish vendor who treats anything coming from outside as anything except public info. I don't know how the information about this problem got from Determina to the criminals, or even if it was just concurrently discovered – who knows? But my point that we have much more to worry about than people wanting 15 minutes of fame is reinforced by how this one has played out. This isn't the first time I've seen something break loose without public disclosure, and I'm sure it won't be the last.
Comments
- Anonymous
April 04, 2007
The CE compiler team makes the following general recommendation internally:
- Never, ever, use /EHa
- Never try to handle or clean up on Win32 exceptions
- If you think you need to handle Win32 exceptions, see #2
- If you’re sure you need to handle Win32 exceptions, use SEH, not C++ EH When you mess with SEH, you're playing with fire. When you mix SEH with C++ exception handling, you're playing with fire while blindfolded. C++ exception handling is for C++ exceptions. SEH exception handling is for SEH exceptions. Just as you wouldn't catch a C++ exception with an SEH handler (you can, but it's a bad idea), you shouldn't catch an SEH exception with a C++ handler (this seemed like a good idea once upon a time, but experience has shown otherwise). If you are going to do something that might generate a specific SEH exception, go ahead and wrap it in __try/__except, and catch that specific exception. But don't catch SEH exceptions via C++ exception handlers - you don't have enough control to do it safely. And never catch an access violation. The only safe response to an access violation is to crash.
Anonymous
April 26, 2007
Michael Howard here. A core tenet of the SDL is to take and incorporate lessons learned when we issueAnonymous
May 10, 2007
well, you are mostly correct, but here's an exception- what about catching the exceptions so you can write a mini dump and send it to a server for later analysis? (and then you can un/safely crash) [dcl] See the detailed response in latest post -