As a kid I was fascinated by the Indiana Jones movies and their portrayal of the brave explorer searching for artifacts in ancient tombs and ruins. These days my job as a security researcher involves a certain amount of software archeology. Many software vulnerabilities are a result of old and long forgotten code, often interacting in unexpected ways with new systems.
A great example for this is the WMF file format, a source of multiple
vulnerabilities over the last two years. This format was based on a wrong design decision which has come to haunt Microsoft ever since. In this post I will describe the fundamental design flaws in the WMF format and analyze a new attack that was disclosed publicly today.
WMF is different from typical bitmap graphics file formats. It contains a sequence of processing instructions that are interpreted by the display system and used to draw an image. In this the format is similar to PostScript. Unlike PostScript however, the WMF file format is not based on an abstract graphics language, but instead maps directly into Windows API calls. Each record in the file contains the arguments for a single Windows API function. An advantage of this design is the ability to open a WMF file and record a series of Windows API calls into it. When the file is viewed later, the API calls will be replayed and will draw the image. Unfortunately, this design violates one of the main requirements for secure system - a clear separation of trusted and untrusted data.
The Windows API makes the fundamental assumption that the program issuing API calls is trusted. If the program passes invalid arguments to an API function, it will crash, and the programmer will have to fix it. Unlike the syscall interface to the kernel, the Windows API functions are running at the same privilege level as the program that calls them. This makes it possible to omit a lot of parameter validation.
When we introduce WMF files into this system, the basic assumption breaks. WMF files downloaded from the Internet are untrusted, and so are the parameters that they pass to the Windows API functions. If an untrusted parameter is passed without validation, the WMF file will be able to crash or exploit the program that displays it.
An example of this kind of attack was posted on milw0rm
earlier today. The WMF file created by the exploit calls the CreateBrushIndirect
function and passes it a LOGBRUSH structure from the file without validating any of its contents. According to the MSDN documentation, the lbHatch field in the structure is a constant specifying the hatch style of the brush. However, when the lbStyle field is BS_DIBPATTERNPT, the lbHatch parameter is used as a pointer to a device-independent bitmap structure in memory.
The PoC code on milw0rm sets the lbStyle field to BS_DIBPATTERNPT and passes an invalid pointer value in lbHatch. This value is dereferenced inside GDI32.DLL. Since this address is invalid, the memory access causes an unhandled exception and the program displaying the WMF file crashes. The impact of the vulnerability is limited and does not allow remote code execution, but it is still a good illustration of the fundamental problem with the WMF format.
Solving this problem is not easy, but it can be done. Writing a formal specification for the WMF format and implementing a validating parser would be a good first step. The mapping between each WMF record and Windows API function must be audited for unexpected interactions and issues such as the one described above. Only then can we be reasonably sure that the WMF format is reasonably safe to use for untrusted Internet content.
Labels: 0-day, design, wmf