This New Vulnerability: Dowd’s Inhuman Flash Exploit
The evidence is now overwhelming that Mark Dowd was, in fact, sent back through time to kill the mother of the person who will grow up to challenge SkyNet. Please direct your attention to Dowd’s 25-page bombshell on a Flash bytecode attack.
Some context. Reliable Flash vulnerabilities are catastrophes. In 2008, we have lots of different browsers. We have different versions of the OS, and we have Mac users. But we’ve only got one Flash vendor, and everyone has Flash installed. Why do you care about Flash exploits? Because in the field, any one of them wins a commanding majority of browser installs for an attacker. It is the Cyberdyne Systems Model 101 of clientsides.
So that’s pretty bad-ass. But that’s not why the fate of humanity demands that we hunt down Dowd and dissolve him in molten steel.
Look at the details of this attack. It’s a weaponized NULL pointer attack that desynchronizes a bytecode verifier to slip malicious ActionScript bytecode into the Flash runtime. If you’re not an exploit writer, think of it this way: you know that crazy version of Super Mario Brothers that Japan refused to ship to the US markets because they thought the difficulty would upset and provoke us? This is the exploit equivalent of that guy who played the perfect game of it on YouTube.
Let’s break it down a bit:
Start with the vulnerability.
It’s an integer overflow, but not a simple one.
When the Flash runtime reads in scene data from a SWF file, there’s a numeric field that, when bounds-checked, is interpreted as a signed number, but when used is treated as unsigned. So there are values the field can take that are treated as tiny and innocuous at time-of-check, but actually evaluate as huge numbers at time-of-use.
A by-the-numbers integer overflow normally knocks the bounds checking off a strncpy or memcpy call, turning code that carefully copies, say, 1k of memory into code that will copy 2 megs of data, splattering it all over process memory. Not here. Instead, Flash uses the malicious number as a count of bytes to allocate.
When you ask Flash to allocate several gigs of memory all at once, the allocation fails, returning NULL. Attempt to use that NULL address and you will crash the program. This happens all the time in real code. Many crashes are traceable to NULL pointers. And, since nothing (usually) lives at NULL, NULL pointer crashes are usually code for “not exploitable”.
Not this time. Flash forgets to check that allocation failed, a ludicrously common error. It then uses that pointer with an offset controlled by the attacker. NULL isn’t valid. NULL plus 1024 isn’t valud. But NULL + 0x8f71ba90 is, as is NULL + N for any N that addresses valid memory.
To this address, controlled by attackers via wild offset, Flash writes a value that is also controlled by the attacker. This is the write32 pattern: a vulnerability that gives the attacker the means to set any one value in memory to a value of their choosing. Game over.
Except not quite.
The exploit doesn’t actually get to offset an arbitrary number of bytes from 0. A complicated set of conditions constrains the address it writes to and the value it gives it.
The the actual write occurs via a structure offset. Flash is hardcoded to translate your offset into another number. Working offsets, as it turns out, will be greater than 0x80000000, and will be evenly divisible by 12 after 4 is added to them. Note: I thought I was hardcore when I wrote shellcode with no lowercase letters for the IMAP vulnerability in the ’90s.
That’s not all. The value that Flash will write to the wild pointer isn’t totally controlled by the attacker either. It’s cast up from a 16 bit integer to a 32 bit integer, and has another variable subtracted to it. This is the point in the report that I started giggling uncontrollably, embarassing myself at the coffee shop.
The net result of this silliness is that it’s hard to do what attackers normally do with a write32 vulnerability, which is to clobber a function’s address with a pointer back to their buffer, so that their shellcode is called when the clobbered function is called. So Dowd’s exploit takes things in a different direction, and manipulates the ActionScript bytecode state.
ActionScript bytecode state; yeah, about that. ActionScript is Javascript that controls Flash animations. But the Javascript system used by Flash is pretty advanced; for performance, it transforms Javascript into bytecodes for a VM. For a bytecode VM, ActionScript is pretty tight; its runtime stack is integrated with the CPU’s runtime stack. The memory it uses to execute code is the same memory that the Flash C-code runtime uses to manage its own state.
ActionScript is a register-based VM, meaning that its bytecode instructions concern themselves chiefly with moving values in and out of memory slots that simulate CPU registers. Those registers live in the runtime stack and are accessed by indexing. Meaning, a malicious Flash bytecode instruction can index its way to an arbitrary address on the system stack. Game over.
Except not quite.
You can’t just inject malicious bytecodes.
Flash players have to execute bytecode sklorked directly off of web pages, most of which are controlled by organized criminals. So Flash doesn’t execute arbitrary bytecodes; they’re verified before execution. The verifier ensures, among other things, that register accesses from the bytecode stream reference valid register slots.
But. For performance, the Flash VM is broken into a two-pass system with a verifier that validates bytecode (time-of-check) and an executive that later evaluates it (time-of-use). And the interpretation of bytecode differs at time-of-check and time-of-use. Here’s the situation:
The verifier ignores undefined bytecodes.
The verifier keeps a table in memory that defines how long any one bytecode instruction is.
The bytecode length table is a valid target of the NULL pointer overwrite.
The executive has totally different machinery for interpeting bytecode.
Clobber the right value in the length table, and you can make an unused bytecode instruction that the verifier ignores seem much longer than it is. The “extra” bytes slip past the verifier. But they don’t slip past the executive, which has no idea that the unused bytecode has trailing bytes. If those trailing bytes are themselves valid bytecode, Flash will run them. Unverified. Giving them access to the whole system stack. Game over.
Except not quite.
The Koopa shell on the second platform is a trap and if you touch it you die.
Ok actually there’s no catch. Dowd’s exploit uses a NULL pointer write32 to knock the locks off the bytecode interpreter in Flash, so that his SWF file can run bytecode that will rewrite the system stack.
But, just to rub it in, or because this stuff just comes natural to you when you are manufactured by a malicious cluster of supercomputers inside SkyNet instead of nurtured by loving human parents, Dowd gives himself additional constraints.
To wit: his exploit must (because he’s messing with us) corrupt the Flash runtime, rewrite it to execute his trojan, and leave it running steady as if nothing had happened. Meaning:
His modification to the verifier can’t break existing instructions.
His bytecode has to swap values into the stack instead of clobbering them directly.
Portions of his shellcode have to run as both Flash bytecode and an X86 first-stage shellcode boot.
Two fun details.
First, even though IE and Firefox use different Flash builds, the addressing inside them is compatible. The exploit works in both places.
Second, Flash isn’t compiled with ASLR. So the attack works on Vista.
Mass casualty. Go Flash!
94 Comments so far
Leave a reply





Oh, the *sweet* *sweet* vindication. I remember an argument that I have had twice in the last several years about whether one should check the return value of malloc. I argued that it should always be done for two reasons: Reading address zero might crash, but not necessarily zero-plus-offset and because a compare register to zero is so free performance-wise that it isn’t even funny.
Guess who was arguing the contrary
?
Love, love, love the Pitfall banners.
“A by-the-numbers integer overflow normally knocks the bounds checking off a strncpy or memcpy call, turning code that carefully copies, say, 1k of memory into code that will copy 2 megs of data”
Do you mean 2 gigs? I don’t know how a signed-unsigned issue would result in anything to do with 2 megs.
[…] How nasty is the Flash vulnerability Dowd found? […]
Hal: most integer overflows don’t literally shove 2 gigs down the target’s throat, even though the count value says they will. “2 gigs” is usually a synonym for “unbounded”.
Dino: you are the opposite of vindicated. See the followup post.
Dino, you have that argument with everyone.. and you are still wrong
Who malloc()s and then starts writing into the returned memory at some funky offset?
Everyone thinks of using the VM as some efficient spare data structure, but no one actually does it because in the end it doesnt pay off (also it is gross).
[…] Matasano Chargen » This New Vulnerability: Dowd’s Inhuman Flash Exploit “It’s a weaponized NULL pointer attack that desynchronizes a bytecode verifier to slip malicious ActionScript bytecode into the Flash runtime.” Very entertaining writeup of some incredible exploitation. (tags: security exploit) […]
Also: compare-to-zero overhead is obviously not the argument.
I once took over a codebase from which I was able to remove wait for it TWO THOUSAND LINES OF CODE because the code not only religiously checked malloc returns but also wait for it wait for it RETURNED NEGATIVE ONE through EVERY CODE PATH which could have an allocation failure, all the way back down to the run loop in main().
You know what main() did when it got that -1? Yeah.
The arguments against checking malloc are:
* It totally cruds up your code without adding any safety or reliability.
* It leads to situations like this bug, where you think you’re checking everything and being safe, but in reality you miss the check (or mess up the recovery regime) at the one spot that Mark Dowd happens to look at when he randomly opens up your program for 5 seconds to find his next vulnerability.
Hey,
Thanks for the kind words! I had this thought also: the original exploit I made was browser independant and windows independant, but Flash version specific. I’m pretty sure you could make it Flash version inspecific also. The two things tying the exploit to a given version of flash are:
1. Address you need to overwrite (location of AS3_argmask)
2. Offset of EIP from your given stack location
Issue #1 could possibly cause problems, but hey - exploiting both browsers at once worked out alright by doing multiple overwrites, so you could probably do multiple overwrites to address different versions of Flash also. But, I have never confirmed this, so I can’t be sure.
Issue #2 could be resolved quite easily by getting the DWORD off the stack that you think should be EIP and testing it for various properties in actionscript. Then, repeating the process in 4 byte increments until you find it. (Alternatively, you could test the properties for something else that is near EIP to calculate the right offset.) What properties? I’m not sure exactly - but you can do all the usual bitwise math and stuff in AS3, I’m sure there is some simple formula there that you could come up with.
Just a thought..
@Thomas:
Are you saying that you should not both with checks because you will inevitably miss one and that one will be exploited? If so, why check at all? I mean, if you have guys like Mark attacking your code, you are screwed, so why bother at all right?
I do agree with you about checking the result of malloc though - if you aren’t doing anything funky with the resulting pointer then there should be no reason to check. If you are though, you should be doing bounds checking.
Why do you say Flash doesn’t work with ASLR?
I see flash9f.ocx running in iexplore.exe running at Low IL, on Vista SP1, with ASLR enabled and DEP in permanent mode (I forced IE to use DEP permanent via the ExecuteOptions reg key). Verified using Process Explorer. I played a SWF and used ProcExp to watch the threads in IE using the CPU and Flash9f.ocx was happily consuming my CPU. I wasn’t sure if you were referring to the flash9util9f.exe (which isn’t opted in to ASLR) that seems to run every time the control is activated so I killed that - and the SWF continued to play.
@jamie
I’m being pretty unclear. What I’m advocating for is that allocation *always* be checked. What I’m arguing against is requiring programmers to remember to check. Instead, malloc should abort instead of returning NULL.
There are a vanishingly small number of cases where a typical large program might do something intelligent with a malloc failure. No, we shouldn’t just break those cases. Instead, we should keep a version of malloc with the original K&R semantics, called “unsafe_malloc”, so that those cases continue to work.
The advantage to this scheme is twofold:
* It is hard to introduce vulnerabilities like the one Mark found, because most of the cases where you’d allocate and blindly dereference a pointer are cases where you would not have carefully thought out your recovery regime. Those places will simply crash the program instead of handing control to Mark.
* It pinpoints in your tens of thousands of lines of C code the places where allocation is critical to the program or susceptable to user control. You can audit those cases especially carefully.
Oh - heh - nevermind. I see that flash9f.ocx isn’t compiled with /DYNAMICBASE as Mark says on page 25.
Guess I should have read his paper before commenting. :_)
C:\Windows\SysWOW64\Macromed\Flash>dumpbin /headers Flash9f.ocx
Microsoft (R) COFF/PE Dumper Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Flash9f.ocx
PE signature found
File Type: DLL
FILE HEADER VALUES
14C machine (x86)
6 number of sections
47E8643E time date stamp Mon Mar 24 22:32:30 2008
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
210E characteristics
Executable
Line numbers stripped
Symbols stripped
32 bit word machine
DLL
OPTIONAL HEADER VALUES
10B magic # (PE32)
7.10 linker version
23F000 size of code
16F000 size of initialized data
0 size of uninitialized data
2394C7 entry point (302394C7)
1000 base of code
240000 base of data
30000000 image base (30000000 to 303AEFFF)
1000 section alignment
1000 file alignment
4.00 operating system version
0.00 image version
4.00 subsystem version
0 Win32 version
3AF000 size of image
1000 size of headers
2E25DC checksum
2 subsystem (Windows GUI)
0 DLL characteristics
That said - it’s still not completely fair to say Flash “doesn’t work with ASLR” and assume the worst . . . while it’s true that the DLL itself may not opt-in to ASLR, it IS however running in a process that IS using ASLR and thus there is some measure of randomization occuring (i.e. the thread stacks get random base addresses, the heaps etc.).
thoughts?
That exploit gave me a painful boner.
If it lasts for more than 4 hours, consult a physician.
@nirva I do have that argument with everyone, you are right :). And I will continue to do so. I never said that aborting or throwing an exception on allocation failure isn’t an acceptable solution (i.e. pass appropriate flags to HeapCreate), just that ignoring the result of an allocation and using the returned pointer is a dangerous practice that should be eliminated.
[…] Томас Пташек (Thomas Ptacek) анализирует нечеловеческий эксп…, использующий уязвимость в Flash. […]
@Thomas:
That makes a lot of sense. An error during memory allocation is one of those types of errors that you can’t do too much about - why saddle 99% of the users with the burden of basic error checking which probably results in application termination when it can be done in malloc itself.
Thanks for the article on this exploit - it was very interesting to hear exactly how these things are created
So funny. I guess this is the point where I will finally remove all slaveware from my Gentoo, thank the devs for paludis’ ability to allow/block by license…
Very well written article as well!
Thanks for the writeup; it’s great context / summary for/of the report. Disturbing to see the russian TrackBack above…
Additionally, you are a golden god for that video, and does anyone know where the “perfect” video is?
[…] a detailed step by step look at Dowd’s flash exploit, check out this article. It is long, but is a gold mine for future cyber […]
@Thomas Ptacek
Every programmer can write their own malloc wrapper (possibly a macro or inline function) so there’s no need in changing any C libraries.
That’s awesome. Every programmer can also just not cram 200 bytes into buffers that are only big enough for 100. No need to change the C libraries. Bad programming? Use good programming. It’s so simple! How could we not have seen it!
this article would not exist unless the exploit had been examined by the people responsible for creating a security patch, and i am sure that Dowd has already toppled it.
Mark’s work is awesome. I expect this is the future, just like exploiting smart cards.
You’ll have to be intimately familiar with exactly how each program executes, its semantic interpretation of data (not just meta-information like buffer size), and non-x86 instruction sets (i.e. the AS opcodes here). This is a return to the era of exploiting app logic + skillful pointer dodging.
Best of both worlds, hats off to Dowd.
omg, this is serious man. cudos.
I suppose the bug does not exist on Gnash.
So the free software people might be safe.
Did anyone check?
http://www.gnu.org/software/gnash/
Having a throwing new, or even a throwing malloc might be OK, but a serious side-effect is that you’re now asking people to write exception-safe code. See my post for some more detail on this. Writing exception safe code is an extremely non-trivial undertaking, and if remembering to check an alloc return is too hard, then writing exception safe code is almost certainly too hard.
There’s also some interesting wrinkles to what can go wrong dereferencing null. ptr->array[input] is also an arbitrary memory write.
@David LeBlanc:
You can’t just drop something like that on us and not explain it! How does a couple dereferences and an addition create an arbitrary memory write? Inquiring minds, etc.,.
[…] Matasano Chargen » This New Vulnerability: Dowd’s Inhuman Flash Exploit (tags: actionscript analysis flash hack programming security) […]
@Toni Ruottu gnash has had its share of vulnerabilities in the past and there’s no reason to believe people wouldn’t go looking for more more if it were more widely deployed, e.g.:
http://www.securityfocus.com/bid/23765
As it stands, last time I tried to use it not only did it not play flv pr0n-in-a-browser but it also failed miserably with homestarrunner.com - which are basically the two reasons to even bother with flash anyway.
Yeah, we’re actually taking the “if you’re out of memory, the jig is up” approach in future versions of Firefox (possibly the sequel the Firefox 3, possibly the sequel’s sequel). You can follow https://bugzilla.mozilla.org/show_bug.cgi?id=427099 and its dependents (chiefly https://bugzilla.mozilla.org/show_bug.cgi?id=427109) if you’re interested in the process, which will involve automatic rewriting across the width of our…substantial codebase. Better performance, less code complexity, improved security; it’s not every day you get all of those in one package.
If you have:
ptr->array[input] = foo;
You are putting the foo value into the address of:
ptr + offset(array) + sizeof(array_element) * input
ptr is 0, offset(array) is a small, fixed value, and then sizeof(array_element) * input leads to foo being placed nearly anywhere in addressable memory.
So to flesh this out, say we did:
cbAlloc = sizeof(*ptr) + (input-1) * sizeof(array_element)
Which is a pretty common thing to do. Now the alloc fails, we don’t check it, and you can now put foo just about anywhere you want. If you can put the system under pressure, you might be able to force alloc failure with relatively small values of input.
So assuming that a null pointer is always just a plain crash is not always valid. The approach Mark used is just one way for this to happen - the one that I point out is another.
[…] http://www.matasano.com/log/1032/this-new-vulnerability-dowds-inhuman-flash-exploit/ […]
[…] met, very legit. Even he was thoroughly excited about this, which is clearly evident from his blog entry on the subject. Actually, even if you already know you won’t understand what’s being talked about, […]
impressive!! down south we’ve been speculating about something like this and the exploitation possibilities of an -until now- hypothetical VM bug like this one for some time. But only Mark Dowd (obviously he is the infosec Highlander) could pull this off!
Furthermore I suspect he only decided to NOT make it processor-independent as well purely for nostalgic reasons
@mark: While doing this, did you consider getting rid of the Intel shellcode altogether and relying on a subverted VM to JIT the bytecode for you?
The following excerpt from Flash Player 9 Security - pp. 16 triggered the idea when I read it (the advantage of doing this would be that you can write platform-independent second stage in Action Script itself and, needless to say, the idea may also potentially apply to Java and .NET):
“Byte code verification is done in the client’s computer (by the Verifier) and consists of determining the types that each byte code will consume and produce, by forming a map of the types of the values on the value stack for each byte code. Therefore, byte code programs that use invalid byte codes (given their operand types) can be detected and rejected early. This eliminates some runtime checking that would otherwise be necessary for system integrity. ActionScript 3.0 goes further at this point and produces native machine instructions to perform the actions of the program, having assured itself of the types of the values it will obtain as the program runs. This translation to native instructions depends mainly on knowledge that byte code verification must generate as it proceeds.
Although this process is fairly complex, it is also well defined and it is clear what the interpreter would do under the conditions that the Verifier has proven will occur. Therefore, it is relatively direct for AVM2 to map these to the appropriate machine instructions.”
Very informative article. I have just one question, if even the mem address space layout is fixed for flash, why the “sandbox” of Vista does allow this “unprivileged” injected actions?
Does the flash plugin runs always with admin privileges by default inside the IEFRAME?
Greets, Erwin
The Vista sandbox can’t know about every application running on it. The worst damage inflicted by this flaw is app-layer.
But what happens when IE runs in “protected mode: enabled”? UAC prompt when flash ask for more privileges?
Again, you’re asking for a runtime that runs at a lower level to compensate for mistakes made in higher levels. Sometimes that’s reasonable, but not in this case: the higher level is a population of thousands of different applications.
Thanks Thomas, keep the good work!
[…] Thomas is in love, or at least very, very deep like, of Mark Dowd (here), and (here) and his recent flash vulnerability findings (here) which, Tom states “Combined […]
[…] pointer dereferencing has the researchers who have read the paper fascinated. Thomas Ptacek has an explanation of Dowd’s work, and Nathan McFeters at ZDNet is ’stunned by the technical […]
[…] http://www.matasano.com/log/1032/this-new-vulnerability-dowds-inhuman-flash-exploit/ […]
All together now :
WE’RE NOT WORTHY!
WE’RE NOT WORTHY!
Just amazing.
Super Mario Bros: Frustration wasn’t a Japanese game, it was a hacked ROM.
[…] trivial security enforcing (well; you need to deny your employees certain things like trusting flash everywhere) and central storage and provisioning. Computer broken? Plug in a new one, log on and there all […]
This is a great article, explains the problem well.
If anyone is not aware yet, this has been slashdotted as of april 18 at 4 am. expect more fallout on the reply thread
and I thought the venetian blind shellcode stuff that fx did was the royal hotness… EEK
Great write up, thanks.
Oh dear.
The patch for this is implemented in .124 but the “brains” at Adobe have compiled in SSE instructions into the build since .115, which crashes processors (Pentium 2 and on on). So anyone still capable of running flash with those are still vulnerable.
[…] Very interesting and scary at same time reading about huge bug in Flash Player, with detailed info about how bad guys can use this. […]
OMG! I was giggling uncontrollably by the third “Except not quite.” Although I wasn’t at a coffee shop.
And it is one very, very cool exploit.
I would argue that the result of a malloc() should be checked every time, not just from a security standpoint, but also from a user interaction standpoint. I don’t want any of my code to result in “Segmentation fault” or “Program XXX unexpectedly quit” — I want to gracefully exit and tell the user what happened, NOT just abort. Since I’m a Mac guy, anybody else remember 0xDEADBEEF?
You seem to highlight Flash as a huge security risk for attacks. Agreed. However, when a proprietary engine on my PC has been attacked over the last year it has CONSISTENTLY been attached through the JVM, not Flash.
Sun’s JVM is a catastrophic, insecure turd sitting on almost as many PCs as Flash. If you don’t think it’s an even bigger risk (given what it is and what it does) you’re kidding yourself.
jb
[…] http://www.matasano.com/log/1032/this-new-vulnerability-dowds-inhuman-flash-exploit/ […]
Jonny Bravo : dear troll, Sun’s JVM has been pretty much bullet-proof since more than a decade. Zero buffer-overflow/overrun for Java-written code. Now it’s true that for some obscure reason you must have admin priviledge to install a JVM on a Windows OS (which is completely silly, but I bet MS’s at fault, not Sun, as the JVM installs fine in userland on Un*x systems). So should you break the JVM on a Windows machine, you’d have ‘root’ privileges. Do you care to enlighten us about how you, dear troll, have been consistently attacked through the JVM? The *only* exploit escaping the JVM I know of what by exploiting a buffer-overflow in a (free, third party) C-written lib the JVM depended on.
If you honestly think the quality of Flash’s VM is anywhere near the one produced by Sun (and used by the Real World [TM] at large), then I recommend a visit to your local asylum.
@John — I’m not talking about “Frustration”, the ROM hack. I’m talking about the real Mario 2, the one that didn’t just hack a couple Mario-related sprites onto a totally different side-scroller.
I could be wrong about the YouTube video, though.
@Anonymous — regarding the JVM: you are vividly missing the point.
The problem with Flash is not that the bytecode verifier is broken. So far as we know, it works fine. The problem with Flash is that its C-code native extensions can corrupt the verifier and shut it off.
The exact same problem potentially exists in Java, and Python, and C# (well — less likely in C#). The problem isn’t the language or the language runtime. The problem is that in 2008, none of these things are self-sufficient; they all rely on C-code extensions. The combination of high-level language runtimes and low-level C code memory corruptions moots OS security mechanisms.
That’s the problem. Java has it too.
For the record, though, my computer has not been consistently attacked through the JVM.
@anonymous Nice to see you won’t stake your reputation on claims of Sun’s *perfect* engineering. :-p
Thanks Thomas, very good explanation.
You know what would be even more cool? Writing an excellent blog entry like this explaining the exploit, while at the same time incorporating that very same exploit in a flash animation on this page, infecting any unpatched readers with the exploit as they read about it….
are we saying this “shellcode” runs without crashing the application itself and then even allows the application to finish successfully?
We are saying that indeed. Although, we are merely saying it. Someone else actually fucking did it.
But I FOUND THE PITFALL IMAGES. That was ME. ALL ME.
In the world of Java, a NullPointerException would by thrown. Go Java!
No, Jim. Java gets sloppy seconds from C; if a C native extension in a Java app (say QT4J) misses a malloc check, it can lose before Java kicks in.
[…] e divulgada por meio deste paper por um pesquisador. A partir daí alguns pesquisadores chegaram a conclusao de que esta pesquisa pode originar um novo metodo de exploração de falhas em softwares. A falha […]
Err… so basically you guys are saying that for example Word should just crash and burn inside of malloc() when allocating memory for that 7th document you tried to create while having another 6 unsaved documents still open?
That is SO stupid that I have no words for it.
Dear Team Go Java: I suggest taking a computer science course at a reputable institution, doing some programming outside of your happy fun sandbox, and perhaps, just perhaps, trying to understand at which level the exploit functions.
Hint - It’s at a lower level, you mush brained idiots.
[…] automatically building an exploit based on the patch is nifty. Almost as nifty as that crazy Flash NULL pointer dereference hack. That thing just blew my […]
@Igor, close. Word should crash and burn a few nanoseconds earlier than it otherwise would upon allocating memory for that 7th document.
Malloc bugs tend to crash when tickled non-maliciously, it’s pretty much only the malicious attacks that don’t crash the program. (Or, you know, do, but also run their evil exploit.) So, if malloc fails with no error handling, you’re boned either way. Better to crash under both normal use and attack than to crash under normal use and run exploit code under attack.
“I’m being pretty unclear. What I’m advocating for is that allocation *always* be checked. What I’m arguing against is requiring programmers to remember to check. Instead, malloc should abort instead of returning NULL.
There are a vanishingly small number of cases where a typical large program might do something intelligent with a malloc failure.”
It is a common situation in an embedded system. And most of the times you to handle running out of resources gracefully without aborting an entire process.
[…] This is an awesome successful exploit brought to us as a research paper, but well explained here. […]
Holy crap… That was an amazing and… entertaning read. Speaking of the Mario game… Was it an official release by Nintendo? Part of Lost Levels? Or just a hack like any other?
@AB — while I agree that kernel malloc is a different animal, I don’t know that you’re following my reasoning. I’m not saying that it should be impossible to check error returns from malloc. I’m saying that the default should be to end the program, rather than create possible security flaws.
Embedded systems are a practice focus for us, and I’ll argue with anyone who says that embedded devs are more disciplined about allocation than application devs.
@Ivan — congratulations, you’ve found the one case in 1,000 that justifies “unsafe_malloc”.
Think about this. You’re proposing a scenario in which, failure or not, the very pattern of calls to malloc is sensitive. Your code is insecure with or without a change in the library. You think that code should simply call “malloc”? I’d rename “malloc” to “super_unsafe_side_channel_vector_malloc” for that case even if NULL pointers couldn’t be offset.
@Igor — No, I think you need to re-read the post. I’m not saying Word should crash on malloc. I’m saying that there should be two malloc interfaces: a default that fails safe, and a variant to handle the Word-like case.
This all sounds “so stupid” to you because you’re not working in security. News flash: security sucks. Things would be a lot easier if innocuous programmer errors couldn’t be warped into exploits.
@tom: my code is wrong but i could do:
{
p1=malloc(secret);
p2=malloc(user_supplied);
p3=malloc(secret);
if( !p3 || !p2 || !p1) abort()
}
which I cant with TQBF’s super_duper_extra_safe_malloc() that you’d like me to use.
btw, as far as I recall the debug options of phkmalloc can be used to force an abort() on ENOMEM. In fact i think that’s the default behavior now.
ivan — come on! I’m not saying, “you must use super_duper_extra_safe_malloc”. You’re missing my point in almost every way:
* Where you say “super_duper_extra_safe_malloc”, I say “malloc”
* Where you say “malloc”, I say “unsafe_malloc”
* I’m not arguing that “unsafe_malloc” shouldn’t be available.
Again: the default should be, fail safe.
So, your example doesn’t work with libtqbfmalloc, because you misused it. Just add the token “unsafe_” to each call and you’re fine.
@ivan
First of all, thanks so much for sharing your discovery of an entire new class of cryptographic side channel attacks.
As far as I am aware (unless I missed something), breaking crypto with memory allocation failure is a previously unpublished result.
It’s quite astonishing to learn something so interesting from a short random blog comment.
So I don’t mean this too critically, but I think that your proposed countermeasure doesn’t really work in the case where the allocation patterns are deterministic and repeatable. That is to say, exactly the same situations where you would expect to be able to use this attack.
It’s the same if you fail immediately upon allocation or if you test everything together and then fail. In most scenarios that I can imagine, you can’t even know the difference.
Either way you can easily guess the sum of the two secret lengths with a binary search, and also the exact values if you have an easy (ie: polynomial time) way to verify your guesses.
Depending on constraints for the possible secret length values, and how much control you have over allocations leading up to this situation, you might be able to also guess the secrets directly by punching appropriate sized holes in the heap and then running experiments.
Have you tried your attack against the new constant-time modular exponentiation in OpenSSL? I was instrumenting the allocations over the weekend and it seems very promising.
You know, if it was directed at anyone else, I’d find the sarcasm there bracing. But having known Ivan Arce for going on 15 years now, I’m pretty sure I wouldn’t be alone in being concerned about being made to look dumb for taunting him like that. =)
I admit though, I don’t understand why so many smart people stick up for the K&R malloc semantics. They suck. We have empirical proof of that: spend an afternoon taking a random sample, using only projects people have heard of. You will find three classes of codebase:
(1) Those that have given up on K&R malloc and replaced it with a wrapper that does exactly what I advocate.
(2) Those that don’t know what’s wrong with K&R malloc, pretend to check rigorously, but fail either directly or in a byzantine manner when an attacker exhausts their resources.
(3) Those that do understand what’s dangerous about K&R malloc, and therefore expend great effort to carefully check and recover from all allocation failures.
Even if I unrealistically concede that the codebases are divided evenly among the three classes — and they are not (I’ve provided them in ranked order) — that’s still a failure for the K&R semantics.
I think you’ve misinterpreted my enthusiasm a bit.
I really was sincerely blown away and amazed by the implications of what Ivan posted last week. Maybe it’s old hat to everybody else here but it’s honestly the first time I’ve ever heard the idea.
I spent the weekend thinking about what might be possible with a technique like this. Came up
with silly examples like:
What if there was a hypothetical operating system that was configured by default to set up RLIMIT_DATA to some value other than ‘unlimited’. Let’s call it OpenBSD.
Then suppose that this OS runs some imaginary network service that makes it almost too easy
to allocate (and free) a lot of memory in arbitrarily sized chunks. We’ll name that one OpenSSH.
Now let’s add a feature to our fantasy network service that performs an asymmetrical private
key operation. We can call it ’signing the key exchange with the host RSA key’.
Ok, now suppose that the RSA signing is implemented by say, an exponentiation that rakes over the
private exponent 6 bits at a time and performs a different pattern of big number multiplications (and hence allocations) depending of the value of each particular window of private key bits.
Now to _really_ stack the deck in our favour, we’ll assume that during the modular exponentiation all the allocations are saved up and free()ed together at the end of the operation by releasing the BN_CTX.
Sure, it’s a contrived example, but I’m just saying that it might be kind of interesting to remotely measure precisely where sbrk() is failing in a theoretical scenario like that.
[…] Everyone is abuzz about the vulnerability exposed in Flash Player by Mark Dowd. I can’t explain it any better, and I agree with the popular assessment that Dowd is the iPhone while the rest of us are smoke signals. But, let’s ignore for a minute what might be a whole new class of vulnerabilities and just look at this Flash thing. […]
[…] You can read an excellent technical write-up on Dowd’s hardcore exploit by Thomas Ptacek (of Matasano) blog [here]. […]
@brl: I see with joy that you’ve polished your skills for sarcasm, good for you!
I don’t recall making any claims about new classes of attacks nor of my three lines of code being a solution for anything else than proving the point that not having malloc() abort on failure _may_ be actually useful and desired.
I just blurted a general idea (I guess that is what a blog comment is for) of when automatically exiting on malloc failure may have security implications beyond code execution but then again I do not have any precise concrete real-world examples to show for, the only thing that came to mind as potentially relate when I posted was THC’s paper on execution path timing analysis applied to OpenSSH some years ago.
I can think of other equally random and bogus possibilities to entertain you (like BIND or Apache for example) but I think you are way smarter than me for that kind of thing.
@tom: I don’t stick to K&R semantics because I think they’re “right”, I just think that changing malloc() semantics and encouraging programmers to not do error checking and to rely on the now declared “safe” malloc will not produce more secure programs.
Again, Ivan, if your answer to bad programming is “use good programming”, you and I are simply on different wavelengths. I think the standard libraries need to be hardened against bad programming.
If I was being sarcastic that would mean that when I was commenting on how massively amazed and astonished I was by your post last week, that I was exaggerating or that I meant it ironically or something.
That’s definitely not the case and I’m becoming more and more fascinated by this idea every day.
Remember when Daniel Bleichenbacher tore OpenSSL a new one over PKCS #1 padding?
No no, the other time. Ten years ago. The PKCS1 ‘oracle’ attack to invert RSA.
That problem was ‘fixed’ by kludging implementations to not leak information about the outcome of padding verification.
If something goes wrong, just fill the premaster-secret with random bytes and pretend that nothing strange is happening. This prevents an attacker from knowing if his malicious ciphertext decodes to a PKCS1 conforming message or not.
At least directly through the SSL protocol….
When invalid padding is detected during RSA decryption, the RSA module logs the failure to the internal OpenSSL error handling system. This error is never exposed to the client (for example, in an SSL protocol message), and just to be on the safe side, if the RSA decryption fails for any reason the SSL module calls shenanigans and explicitly clears this internal error log before implementing the random byte hack described above.
Hmm…
It seems that the first time a thread or process logs an error through the error API, a ~400 byte ring buffer structure is allocated with malloc().
Oh, and if that malloc() fails for some reason?
In that case, OpenSSL does something reasonable (?) and returns a reference to a single static instance of the structure. (A special bonus quirk for fans of extreme sports such as thread racing to double free).
So you can’t crash the service by forcing that particular malloc() to fail, but you can later measure if the allocation occurred or not if you understand the allocation failure regime used throughout OpenSSL:
Don’t crash, abort(), or exit() if malloc() fails. Just fail the current operation and all future operations until memory is available again.
I think you could build an oracle for the Bleichenbacher attack out of this behavior. An oracle that precisely detects that the problem with your message is broken padding, (and not the less useful: broken padding OR malformed plaintext).
This is the most powerful leak possible for this attack and with the Klima-Pokorny-Rosa optimizations you would only need a few thousand oracle consultations to sign or decrypt something.
It’s just an idea, and I’m not claiming to have implemented the attack or anything. There would obviously be a lot of hurdles to jump over and details to hammer out in order to build a practical implementation. I’ve just been browsing OpenSSL looking for ways to break things with creative malicious memory exhaustion.
I don’t know how you could even begin fixing bugs like this in a general way. Deciding when to run out of memory in some non-deterministic way?
This stuff is a lot more interesting to me than bickering about whether or not NULL pointer dereference bugs are commonly exploited outside of imaginationland. So sorry if I’m dragging this thread too far off topic.
@brl: hm ok so we are thinking about the same lines then. I was specifically thinking about PKCS1 because I recently looked at it in SILC’s source code and I was specifically thinking about Bleichenbacher’s attack as well but since I couldn’t put my finger on anything concrete where aborting on malloc() would constitute a real issue in just posted a generic comment about that thought . My hunch was that somewhere in the depths of ASN1->MP->PKCS1 operations there is a malloc() with a user-controllable size argument that could provide an oracle if malloc() aborted on failure. Even if malloc didn’t abort there would be an oracle but it would be much harder to measure reliably. However, one thing is to post a random comment on blog and an entirely different thing is to actually find the attack and implement it…and that is only available to “One of God’s own prototypes. Some kind of high powered mutant never even considered for mass production. Too weird to live, and too rare to die.”
[…] Flash Player 9 to mitigate some bad security vulnerabilities (my favorite Flash vulnerability was hilariously described at Matasano Chargen). One of our Flash apps at work suffered collateral damage from the […]
[…] right personality, and you have a “security engineer” who will find things like what is described here (and here and here) as a basis to boldly claim that web browsers are evil. Not something to be […]
[…] His research — which included uncovering a very, very nasty bug in Flash — has created quite a stir in the security community. In this interview Mark tells us there could be more exploitable NULL pointer bugs around the […]
[…] to close it off, here’s a crazy flash exploit. Note that this is worth checking out just for the link to the vid of the super difficult […]