Uninformed: Informative Information for the Uninformed

Vol 9» 2008.Jan


While the ANI vulnerability was certainly unique, it was not the first time the animated cursor code was found to have a security issue. Microsoft patched an issue that was almost exactly the same as MS07-017 with MS05-002 roughly two years prior[7]. In both cases, the underlying security issue was related to a failure to properly validate input that was derived from the contents of an animated cursor file. Alexander Sotirov provided much of the initial research on the ANI vulnerability and also gave an excellent write-up to its effect[22]. This paper will only attempt to highlight the flaw.

The vulnerability itself was found in user32!LoadAniIcon which is responsible for processing a number of different chunks that may be contained within an animated cursor file. Each chunk is a TLV (Type-Length-Value) as described by the following structure4:

struct ANIChunk
    char  tag[4];        // ASCII tag
    DWORD size;          // length of data in bytes
    char  data[size];    // variable sized data

Keeping this structure in mind, the flaw itself can be seen in the abbreviated pseudo-code below as modified slightly from Sotirov's original write-up:

01: int LoadAniIcon(struct MappedFile* file, ...) {
02:   struct ANIChunk  chunk;
03:   struct ANIHeader header;  // 36 byte structure
04:   while (1) {
05:     // read the first 8 bytes of the chunk
06:     ReadTag(file, &chunk);
07:     switch (chunk.tag) {
08:       case 'anih':
09:         // read chunk.size bytes into header
10:         ReadChunk(file, &chunk, &header);

On line 6, the chunk header is read into the local variable chunk using ReadTag which populates the chunk's tag and size fields. If the chunk's tag is equal to 'anih', the data associated with the chunk is read into the header local variable using ReadChunk on line 10. The problem is that ReadChunk uses the size field of the chunk as the amount of data to read from the file. Since header is a fixed-size (36 byte) data structure and the chunk's size can be variable, a trivial stack-based buffer overflow may occur if more than 36 bytes are specified as the chunk size. In terms of the vulnerability, that's all there is to it, but the implications from an exploitation perspective are where things start to get interesting.

When attempting to exploit this vulnerability it may at first appear that all attempts to do so would be futile. Given Vista's security push, an attacker would be justified in thinking that surely the LoadAniIcon function is protected by a GS cookie. This point is especially justified considering the majority of all binaries shipped with Windows Vista have been compiled with GS enabled[27]. However, there are indeed circumstances where the compiler will choose to not enable GS for a specific function. As chance would have it, the compiler chose not to enable GS for the LoadAniIcon function because of the simple fact that it does not contain any characteristics that would suggest that a stack-based buffer overflow might be possible (such as the use of stack-allocated arrays). This means that an attacker is able to make use of exploitation techniques that are associated with traditional stack-based buffer overflows. While this drastically increases the chances of being able to produce a reliable exploit, there are still other mitigations that are of potential concern.

Another mitigation that might be concerning in most circumstances is hardware-enforced DEP (NX). This would generally prevent an attacker from being able to run arbitrary code within regions that are not marked as executable (such as the stack and the heap). However, as fate would have it, Internet Explorer is configured to not run with DEP enabled. This immediately removes this concern from the equation for exploits that attempt to trigger the ANI vulnerability through Internet Explorer. With DEP out of the picture, ASLR becomes a weakened but still potentially significant hurdle.

While it may appear that ASLR would be challenging to defeat in most circumstances, this particular vulnerability provides an example of two different ways in which ASLR can be bypassed. The simplest approach, as taken by Sotirov, involves making use of the fact that Internet Explorer is not compiled with support for ASLR and therefore can be found at a fixed address within the address space. This allows an attacker to make use of opcodes contained within iexplore.exe's memory mapping. A second approach, as taken by the author, involves using a partial overwrite to ignore the effects of ASLR completely. The details relating to how a partial overwrite works were explained in §2.4.2. In either case, an attacker is able to reliably defeat Vista's ASLR.

To compound the problem, the particulars of the context in which this vulnerability occur make it easier to exploit even without the presence of mitigations. This improved reliability comes from the fact that the LoadAniIcon function is wrapped in an exception handling context that simply swallows exceptions that are encountered. This makes it possible for an exploit to fail without actually crashing the process, thus allowing the attacker to try multiple times without having to worry about making a mistake that crashes the process. When all is said and done, the simplicity of the vulnerability and the ease with which mitigations could be bypassed are what lead to the ANI vulnerability being quite unique. Given the fact that this vulnerability can be so easily exploited, it is prudent to describe how it could have been detected as being a high risk function.