In part one of this blog, I gave an overview of the exploitation flow for the recent DirectShow vulnerability. With no patch for this vulnerability available as of yet, the fact that we are seeing this exploit used more commonly in the wild is worrying. In this article I will discuss the exploit, how it works, and mitigation strategies to protect against it.
To get straight to the mitigation strategies jump to the bottom of the page. This vulnerability does not exist in Vista or Windows Server 2008.
To trigger this vulnerability, attackers are currently enticing users to visit a malicious page. Attackers have become quite adept at doing this by embedding iframe tags in legitimate pages, among other techniques. This is the most likely attack vector. We have seen iframe tags pointing to this exploit inside phishing pages already and we do expect to see iframe tags added to more pages.
The vulnerability exists in the code within Microsoft DirectX and can be triggered by a specially crafted QuickTime media file. The attackers Web page will try to play the malicious QuickTime file, not using the QuickTime player, but using Windows Media Player instead. This will trigger the vulnerability and allow the attacker to execute code on the visitor’s computer.
The vulnerable code exists in quartz.dll and is a null-byte overwrite. It allows the attacker to overwrite just one byte of memory with a null byte. An additional constraint is that the address of the byte to be overwritten must be within 255 bytes of the address of the vulnerable line of code.
The conditions of the vulnerability make it non-trivial to craft an exploit. Most exploits we have seen in the recent past use heap spraying. The attacker places their malicious code in a very large range of memory and then tries to jump into that memory region using the exploit. However, in this case the attacker cannot always do that since he can only control one byte, which will become zero. The memory range where the heap is allocated might not be reachable just by overwriting one byte. (This depends where the DLL is loaded in memory. See below.)
In the exploits that we have observed in the wild, the attacker chose to overwrite one byte of the return address of the vulnerable function—the second byte. So if the return address of the vulnerable code is 0x74817677 the attacker will change the return address to 0x74007677. When execution reaches the end of the vulnerable function, it will jump to the attacker’s address.
Now the attacker needs to have code that he controls at address 0x74007677. In order to achieve this, the attacker loads a DLL of his or her own into memory. The DLL has a preferred loading address that will place it at a specified address close to quartz.dll (0x74000000 in this example). The DLLs have a large NOP slide inside them that lead to the shell code to be executed. When the newly overwritten return address is followed (0x74007677) it will jump into the memory of the DLL (loaded at 74000000) and the attacker will gain control.
In this figure we can see quartz.dll is loaded at address 0x74810000 and the attacker’s DLL—12.dll—is loaded at 0x74000000 and then continues up to 0x74014000 (which is +1000). In this screenshot the attacker has achieved the conditions necessary for successful exploitation.
There is a problem though—quartz.dll is not always loaded at 0x74810000. It can be loaded at a variety of different addresses depending on what is already in memory at that time. If there is already something loaded at address 0x74810000 then quartz.dll will be loaded at another location. This location will be chosen according to what memory region is free at the loading time. There is no way for the attacker to know the exact address at which quartz.dll will be loaded. To account for this the attacker loads several other DLLs into memory each with a different preferred loading address. In this way he or she is spraying memory with DLLs—DLL spraying instead of heap spraying—hoping that one of the DLLs will be close to where quartz.dll is eventually loaded.
Here we see the attacker has loaded many DLLs into memory (7.dll, 8.dll, 9.dll, 1.dll, 2.dll, 3.dll, 4.dll, and 5.dll) in the hopes that if quartz.dll is not loaded at its preferred location, it will be loaded close to one of these other DLLs. In fact during testing we observed quartz.dll being loaded close to 0x0c000000, which also lead to successful exploitation.
Loading a DLL at the preferred address of quartz.dll forces the DLL to be loaded elsewhere. In the screenshot above I have loaded my own dll at address 78410000, forcing quartz.dll to be loaded in memory at a different location. Quartz.dll actually gets loaded at 63f0000 (see the below screenshot). The malicious DLLs have already placed themselves close by, note the address of 11, 14, 6, 7, 8, etc. In this example, the overwritten return address in quartz.dll would look something like 0x0600XXXX, which lies within the memory range of 6.dll.
In the pages we have seen, the attacker was using between seven and fifteen DLLs in order to improve his chances of success.
There was also heap spraying code in several of the exploit pages that we have seen. However, this heap spraying code appears to be redundant, since the attacker can place a DLL at an exact offset of his choosing. In fact, just yesterday one exploit page that we have been monitoring removed the heap spraying code completely. Others continue to contain the code. Why is this?
Due to the fact that the attacker needs to load so many DLLs into memory, the page may load quite slowly. Each DLL is around 78Kb and 78 * 15 = 1.17 Mb. However, this amount of traffic can be handled quite quickly by most modern connections, so it may not be much of an obstacle to the attackers. Yet the number of DLLs needed in memory may be reduced by heap spraying. The DLL technique shown above could be used for the high addresses, where heap spraying would not work. If quartz.dll gets loaded at a lower address, then heap spraying could be used. In fact, we have already seen a corrupt attack that appears to be using this technique. The heap spray code appears to have been included as an insurance policy in case the other methods do not work. As stated previously, this attack is very precise and as such heap spray is not needed, but is still being included in many exploit pages. Using both techniques, DLLs 10 through 15 in the table above could be loaded to handle the cases where quartz.dll is loaded at a high address, and for the lower addresses, heap spraying could be used. We are still investigating the use of the exploit; however, from our research so far it is appearing more often and we are investigating the use of it within Web exploit kits. This will likely lead to wide-spread use in a short time.
Although this is not precisely what was discussed in the paper “Bypassing Browser Memory Protections” by Mark Dowd and Alex Sotirov, they discussed bypassing memory protection mechanisms such as ASLR, DEP, etc. The techniques used here are similar to what is discussed in that paper. This is the first time we have seen this technique used in the wild and it may even be a contender to replace heap spraying, which is the current staple for Web-based exploitation.
Symantec has added detections for the malicious QuickTime files, the malicious DLLs, the network traffic associated with the exploit, and the exploit pages themselves. Please update the definitions in your Symantec products to the latest versions.
Here is some additional information about the vulnerability that can be used to protect yourself. This vulnerability does not exist in Vista or Windows Server 2008. For Windows 2000 Service Pack 4, Windows XP, and Windows Server 2003, Microsoft has released this advisory, as well as this work-around.