, Matasano 2008-04-15
How nasty is the Flash vulnerability Dowd found?
Combined with any DNS vulnerability or any high-profile cross-site scripting vulnerability, the weaponized version of this attack would probably clock in at tens of thousands of compromised browsers per minute.
Is this a new bug class?
Sort of. It depends on what you mean by the term class. For example: most researchers consider heap overflows a seperate bug class from stack overflows. In reality, though, the same underlying coding error causes both vulnerabilities: poorly bounded copies. On the other hand, epistimologically, integer overflows are a new bug class, because the underlying coding error is a type violation, which creates an unbounded copy.
See how I used the word epistemologic there? That means you dont care about the difference. Wild writes from NULL pointers are probably their own bug class.
So this is like the heap overflow revelation in the late 90s? NULL pointers are exploitable now?
No. Learn everything you can from Dowds paper and NULL pointers still arent usually exploitable:
They need to be written to, not read from; lots of fuzzer advisories trace down to loads, not stores, from NULL.
The offset needs to be controlled by the attacker; most of the time, offsets are hardcoded (most offsets are structure references).
The wild write needs to happen before any pointer loads that will crash the program.
Is there a pattern worth looking for here? Absolutely. Look for things that can return NULL that have random-access indexing. Malloc is a perfect example.
Wait a minute. Didnt you say people shouldnt check malloc?
Yes. This bug is a perfect case in point for why Im right.
Consider: it is not the case that the Flash runtime never checks for allocation failure. What happened is, the Flash developers have an allocation checking regime that defaults to unchecked, and requires them to audit every allocation.
The way it should work is, by default, when using the simplest, most common allocation calls (malloc, or, in Flash, mem_Alloc), the program should abort if malloc fails. Returning and catching NULL is inadequate.
But we cant just abort when any given malloc fails! What about user-specified sizes? You dont have to abort on every malloc. You just have to abort by default. When you know youre taking a value from a user, or any other unsafe input, you should use unsafeAlloc, which is simply malloc. Then you audit your code for the 3 places in the whole project that use unsafeAlloc and make sure the checking regime works.
Doesnt runtime security, like in Vista, solve most of these problems?
Maybe, maybe not. Obviously it didnt here, because Flash turned runtime security off.
But look at the bigger picture. Runtime security measures like ASLR and cookies and W^X memory all address the dumb exploit pattern. The dumb exploit pattern is an artifact of hardcoded runtimes generated by C compilers. When your exploit is shotgunned in through a dumb runtime, you lose both predictability and control of the target program. Thats basically what runtime security is capitalizing on: your exploit doesnt know where DLLs are based, and so it cant return directly into them.
The problem is, the hardcoded runtimes are going away. The vast majority of code written going forward targets extremely complicated runtimes, like the bytecode VM in ActionScript. In a bytecode VM scenario, an exploit has much more flexibility:
There might be 10x as many places to overwrite that will compromise the target; for instance, the abstract syntax tree objects containing method tables.
Valuable information might be readily accessible from known relative offsets or, better still, from registers kept loaded with intepreter state.
Just as with ActionScript, the content buffer that vectors your exploit in might be executable in the target runtime, leaving you only with the problem of compromising the verifier.
Just as with ActionScript, there may be an extremely powerful executive running on top of the CPU, rather than just machine code instructions running directly on the CPU.
These are all ways that high-level languages make runtime security harder.
But high-level languages are supposed to be a huge security win!
They probably are. But remember, even in the most intricate schemes (and Javscript compiled to a bytecode VM that runs off the system stack qualifies), high-level languages are really just glue around low-level languages: the most interesting features in Python, Ruby, and Javascript are implemented natively.
So, you get two interesting phenomenon:
You need to audit the runtime to make sure that the C code that implements the core language isnt vulnerable (this is why Perl was a bad bet in 1995, when everyone was saying that buffer overflows were Cs fault).
You need to audit all the native extensions (such as Quicktime for Java), bearing in mind that unlike a server or a client, the attack surface for a language extension is arbitrary callers with arbitrary arguments - a much more painful place to be.
Has Mark Dowd simply outclassed us? Should we pack it up and quit?
Yes. But dont feel bad about that. Youre a human being, and hes a remorseless killing machine. Big Blue crushed Kasparov, and now hes not the prime minister of Russia! At a certain point, you have to concede the field, moving on to games where human beings still have the advantage. Computers havent solved Go, for instance. For us researchers, I suggest we take advantage of Mark Dowds robotic inability to love, and take up the arts, such as watercolors or interpretive dance.
Comments
