After a few days of fuzzing, I noticed that I covered a large part of the format (at least the part I found interesting) so I then began reverse engineering the format more thoroughly. I started by mapping out the tag-types and reviewing functions that parse them.
After I spent a few hours just poking around and getting a stable list of function names and addresses, I noticed something strange; it seems there is an undocumented tag (0x03).
I began examining the tag and noticed it has the following structure:
// The rest is unknown so far
Note: The reversing process has taken place under a Windows XP SP2 machine with Adobe Flash 10.0.42.34 installed while it was rebased to the address 0x02531000.
I quickly launched my flash fuzzer and added the new tag structure to the tag list so I would be able to trace the function execution and understand it faster. I generated a valid SWF file, placed a breakpoint on the function that parses the unknown tag “ParseUnknownTag0x03” at 025F4A30, and launched the debugger.
.text:025F4A30 mov eax, [esp+unknown0]
.text:025F4A34 push ebp
.text:025F4A35 push esi
.text:025F4A36 and eax, 7Fh
.text:025F4A39 mov ebp, ecx
.text:025F4A3B mov esi, [ebp+eax*4+2C4h]
.text:025F4A42 push edi
.text:025F4A43 lea edi, [ebp+eax*4+2C4h]
.text:025F4A4A test esi, esi
.text:025F4A4C jz return
While debugging this function, I noticed that EAX is being assigned the “unknown0” variable that I mapped. EAX then gets limited to 0x7F and is used as an index to an unknown array. This array is all zeros besides one element that contains a pointer to an unknown struct / class. The element is 0x7F and is as high as we can go. Even if we enter 0xFFFF as our “unknown0” value, we will still get up-to 0x7F and no more.
A quick translation of the code fragment would be:
objectPointerOnTable = &this->swfObject[unknown0 & 0x7F];
if (object == NULL)
I stopped debugging and modified my flash fuzzer to generate the exact same file but with the value “unknown0” set to 0x7F. This time the object was not a NULL so the function execution continued until I reached the following code fragment (as a part of a loop):
.text:025F4A65 cmp [esi+0D0h], cx
I took a quick look at “[esi+0D0h]” and saw it contained the value 0xFFFE.
If the values do not match, the loop continues then quickly breaks and the function returns. I then modified “unknown0” to 0xFFFE and restarted the debugging process. And then I noticed that if these values do match, a call to “HeapFree” is made. I then continued execution, took a look at Internet Explorer and… boom, access violation.
Looking at these values, I quickly concluded that it is a use-after-free. The structure being accessed was replaced by an irrelevant string.
I found several ways to control the data within the structure but no code-execution. The down-side to this vulnerability is that, as you can see, the crash occurs during a read operation.
I spent awhile trying to find an arbitrary write or a virtual function table call and found an arbitrary write but was unable to automate it for situations other than in the lab. (The trigger required specific events to occur).
And this is why I left the vulnerability untouched until it got patched.
Both methods of research (reverse engineering and fuzzing) are extremely useful.
Most people just choose one of the two and miss the vulnerabilities that are easy to find using the alternative method. When conducting research you should probably keep an open-mind and try both reversing and fuzzing. And even if you choose to conduct just fuzzing you should still debug every “tag” and make sure you are covering as much as you can.
About the Author
Tal Zeltzer (zelik) is a security researcher from Israel, focusing on reverse engineering both software and hardware. He spends most of his free time developing private security tools and exploits for fun.