Inside the WMF Backdoor

Steve Gibson (of SpinRite fame) proposed a theory in his weekly Thursday-night podcast last week that if true, would be the biggest scandal to ever hit Microsoft - that the Windows Metafile (WMF) vulnerability that drew so much media attention last month is actually a backdoor programmed intentionally by Microsoft for unknown reasons. Slashdot picked up the story the next day and I received a flood of emails asking me to look into it. I finished my analysis, which Steve aided by sending me the source code to his WMF-vulnerability tester program (KnockKnock), over the weekend. In my opinion the backdoor is one caused by a security flaw and not one made for subterfuge. I sent my findings to both Steve and to Microsoft Monday morning, but because the issue continues to draw media attention I’ve decided to publicly document my investigation.

Understanding the WMF vulnerability requires a brief background in WMF files. A WMF file is a script for executing graphics commands, called graphics device interface (GDI) functions. Each command is stored as a record in the WMF file and examples of GDI functions include ones to draw lines, fill rectangles, and copy bitmaps. Image files like bitmaps, GIFs, or JPEGs, on the other hand, store the representation of pre-rendered images. Because an application can direct a WMF file’s execution at different devices, like screens and printers, with different graphics resolutions and color depths, their advantage over pre-rendered formats is that they scale to the capabilities of the target device. For this reason, many clipart images, including those used by Microsoft Office, are stored in WMF files.

WMF files originated with early 16-bit versions of Windows that implemented single-threaded cooperative multitasking. In that programming environment a process can’t perform two tasks, such as printing a document and displaying a print-cancel dialog, concurrently. Instead, they have to manually interleave the tasks, periodically polling to see if the user has asked to cancel the printing. The programming model for printing in Windows therefore has the concept of an abort procedure that an application can set before calling the printing API. If such a procedure is registered Windows periodically calls it to give an application a chance to signal that it wants the print job cancelled. Otherwise there would be no way to abort a long-running print job.

The WMF vulnerability stems from the fact that WMF supports the SetAbortProc API, which is the GDI call to set an abort procedure, that Windows expects abort procedure code to be stored directly in the SetAbortProc WMF record, and that Windows will invoke the procedure under certain conditions immediately after processing the record. Thus, if an attacker can get your computer to execute their WMF file through Internet Explorer or Outlook, for example, they can make your system execute arbitrary Windows commands, including downloading malicious applications and launching them.

Steve Gibson’s intentional backdoor theory is based on four suspicious observations he made regarding the vulnerability and the behavior of his tests with WMF files that contain a SetAbortProc record:

  1. There is no need for WMF files to include support for the SetAbortProc API.
  2. Even if an abort procedure is set by a WMF file, Windows shouldn’t execute it unless some abort condition is triggered, which should never occur when executing a WMF file.
  3. He could only get his WMF file’s abort procedure to execute when he specified certain invalid values for the size of the record containing the SetAbortProc command.
  4. Windows executes code embedded within the SetAbortProc record rather than expect the record to reference a procedure within the application executing the WMF file.

Steve’s belief that WMF files should not support the SetAbortProc API comes from the documentation for how Windows calls an abort procedure registered via SetAbortProc:

It [the abort proc] is called when a print job is to be cancelled during spooling.

The statement implies that Windows detects that a user or printer wants to cancel a print job and informs an application by executing the registered abort procedure. Steve echoes this understanding in a posting on his website’s news group:

[the abort proc] is the address of an application-provided "callback" -- a subroutine provided by the application that is expressly designed to asynchronously accept the news and notification of a printing job being aborted for whatever reason.

Steve reasoned that WMF files execute to screens, not printers, and so it makes no sense to abort their execution. Further, his tests showed that Windows calls the abort procedure registered by a WMF file immediately, when there’s no apparent cause for cancellation.

WMF files can be directed at a printer, however, and not only that, but the abort procedure documentation is misleading. Its correct description is in the Microsoft documentation that describes the basic steps for writing code that prints to a printer:

After the application registers the AbortProc abort procedure, GDI calls the function periodically during the printing process to determine whether to cancel the job.

Thus, the abort procedure really works both ways, providing Windows a way to notify an application of printing errors and the application a way to notify Windows that it wants to cancel printing. With this interpretation Windows’ execution of the abort procedure immediately after one is registered makes sense: Windows is calling the procedure to ask it if the playback of the rest of the procedure should be aborted.

Even still, the question remains as to why WMF files implement the SetAbortProc GDI function at all. My belief is that Microsoft developers decided to implement as much as the GDI function-set as possible. Including SetAbortProc makes sense for the same reason that abort procedures for printing make sense: WMF files can consist of many records containing complex GDI commands that can take along time to execute, especially when sent to a printer and on old hardware like the kind on which the cooperatively multitasked Windows 3.1 operating system ran. The abort procedure gives applications the ability to monitor the progress of a playback and to unilaterally abort it if a user makes UI choices that make a complete playback unnecessary. In addition, if a WMF file is sent to a printer and there’s a printer error Windows must have a way to know that an application wants to cancel WMF playback, which is another reason to invoke the abort procedure from within the PlayMetaFile loop. This Microsoft article from 1992 confirms the behavior as designed.

I’ve addressed the first two of Steve’s observations, but what about his claim that the abort procedure only executes when the SetAbortProc record contains certain invalid record sizes? I’ve analyzed the control flow of the PlayMetaFile function that executes WMF file records and found that, if an abort procedure is registered, it calls it after executing each record except the last record of the file. That behavior makes sense since there’s no need to ask an application if playback should be aborted when the playback is already completed.

Steve’s example WMF file contains only one record, the one that specifies SetAbortProc, so under normal circumstances PlayMetaFile will never call his abort procedure. The record sizes that he found trigger its execution cause PlayMetaFile to incorrectly increment its pointer into the WMF file such that it believes that there are more records to process, whereas the values he used that don’t trigger the execution land it on data values that indicate there are no more records. So his assertion that only certain magic values open the backdoor is wrong.

The remaining question is why PlayMetaFile expects the abort procedure to be in-lined in the metafile. It’s that fact that allows a hacker to transport malicious code within a WMF file. The actual reason is lost with the original developer of the API, but my guess is that he or she was being as flexible as possible. When a WMF file is generated in memory and played back by the application in the same run, like it would to create a graphics macro and use it mulitple times, it generally makes no difference if the procedure is copied or not.

For the code in on-disk WMF files to work any references it makes to data or code, such as Windows functions, must be to hard-coded addresses. This means that WMF file code won’t work if Windows system DLLs change in size or load into different locations in memory and therefore WMF vulnerability exploits only work on specific patch-levels of Windows. While this might make an argument against a design that includes the abort code in the WMF file things were different when the format was architected. In the Windows 3.1 “large” memory model code is inherently location-independent and Windows was never patched, so both Windows and an application could simply copy an application function into the WMF file and assume it would work when played back by the same application in a later run session. In any case, its not clear that the developers envisioned applications creating on-disk metafiles with abort procedures. Also, as Microsoft’s Stephen Toulouse pointed out in Microsoft’s rebuttal to Steve’s claims, the security landscape in the early 1990’s was very different than today and all code, including that stored in a WMF file, was inherently trusted.

The vulnerability is subtle enough that the WINE project, whose intent is to implement the Windows API for non-Windows environments, copied it verbatim in their implementation of PlayMetaFile. A secret backdoor would probably have been noticed by the WINE group, and given a choice of believing there was malicious intent or poor design behind this implementation, I’ll pick poor design. After all, there are plenty of such examples all throughout the Windows API, especially in the part of the API that has its roots in Windows 3.1. The bottom line is that I'm convinced that this behavior, while intentional, is not a secret backdoor.

Originally by Mark Russinovich on 1/18/2006 11:05:00 PM
Migrated from original

# re: Inside the WMF Backdoor

Mark, Given your current good reputation, I am sure that this single blog post will put people at ease must better than 20-100 statements from Microsoft :)

1/19/2006 12:00:00 AM by Troy Phillips

# re: Inside the WMF Backdoor

Thanks for this excellent analysis! Steve Gibson certainly does not deserver to be taken seriously by anyone, but unfortunately he is :-(

Do you have ANY wild idea why Microsoft might have kept the AbortProc in WMF files during security reviews?

Could there be any reason like an application using WMF-files to cache rendered content (including all commands, including SetAbortProc) and then replaying them without accessing the disc or internet or so?

While WMF can be seen as a format to store cliparts and vector grahics on disc, could it also be seen as a way to record a macro and playback it without ever touching the outside world?

It would be interesting if the findings would allow such a guess and that Microsoft once decided against removing it because of backward compatibility?

1/19/2006 4:15:00 AM by Anonymous

# re: Inside the WMF Backdoor

Of course it's not a backdoor - if it were a backdoor from so long ago it would have been found a decade ago and exploited by now. It's just an error in judgement. I'm sure Vista will have many of these as well and all in the name of DRM.

1/19/2006 4:20:00 AM by Sime

# re: Inside the WMF Backdoor

I'd made my mind up already: if it's conspiracy vs. "cock up" - it's invariable always the latter.

1/19/2006 6:15:00 AM by Anonymous

# re: Inside the WMF Backdoor

That's a very nice explanation. I came to the same conclusion when looking at the code (my detailed explanation is blogged here:

I don't believe that Steve is right, this is not a backdoor. I'm also not clear that Microsoft ever intended there to be in WMF file code. I think this is a side effect of the way they hooked up the metafile Escape function to the GDI Escape. By simply assuming that the metafile parameters could be passed to Escape verbatim they created this vulnerability (especially since the third parameter is an arbitrary pointer; in this case which points into the metafile).


1/19/2006 6:20:00 AM by John Graham-Cumming

# re: Inside the WMF Backdoor

I'd made my mind up already: if it's conspiracy vs. "cock up" - it's invariable always the latter.

That's called "Hanlon's Razor":

Never attribute to malice that which can be adequately explained by stupidity.

1/19/2006 7:14:00 AM by Anonymous

# re: Inside the WMF Backdoor

Steve Gibson is well known for kicking up a fuss about anything that gets him media attention. Raw packets and all that...

1/19/2006 9:06:00 AM by Ed

# re: Inside the WMF Backdoor

Or, as Napoleon said, "Never ascribe to malice that which is adequately explained by incompetence."

1/19/2006 9:29:00 AM by Anonymous

# re: Inside the WMF Backdoor

There was one other point that Steve Gibson made that would be good to hear a rebuttal on.

Wasn't the WMF code recently overhauled, supposedly gone over with a fine toothcomb. I'm no coder, but that the actual function was 'in-line' inside the metafile, and therefore presumably, open to being misappropriated; given the amount of sites out there that have wmf content running unsolicited, you'd think someone would have said, wait a minute, this could be exploited.

In fact, now I see another comment asking the same question.

You think it was just a case of, well, it might be open to exploitation, but it hasn't yet been exploited yet, so let's just leave it in, it'll take too much effort to rip it out?

I wonder how long it would have sat in the code if source code was available. But that's a seperate issue.

1/19/2006 9:42:00 AM by ruy_lopez

# re: Inside the WMF Backdoor

Q: Is this a back door?
A: Yes - that's why it's such a serious vulnerability.
Q: Was it intentionally put into Windows code.
A: Yes.
Q: Was it intended to be misused/abused?
A: Almost undoubtedly not.

Based on the Gibson's transcript (
it looks like Steve was right on - it is a backdoor intentionally placed
in Windows code; I guess his sin is calling a spade, a spade. I don't see
where he ever claimed that MS intentionally did this to subvert security
for their own purposes which appears to be the claim of the Gibson

On the other hand,
Q: When was this backdoor coded?
A: About 1992.
Q: How old was VMS at that time?
A: 15 years.
Q: Who directed the development of Windows NT?
A: Dave Cutler.
Q: What's Cutler's background.
A: Directed VMS at DEC.
Q: On who's watch was this security lapse ported into the
Windows NT stream.
A: Presumably Cutler's.

While anything's possible, it's hard to imagine how a security lapse
of this magnitude (trusting user-written code) could have made its
way into VMS code.

The point is that Stephen Toulouse's "the security landscape in the early
1990’s was very different than today" is, well, self-serving. Only in MS's
myoptic view is this the case.

1/19/2006 10:14:00 AM by tc

# re: Inside the WMF Backdoor

I believe that the wmf exploit was left im by microsoft mainly because of the amount of checking there would of been earlier, i can also confirm its still affecting windows. try looking at ***usaporn-dot-org*** for one its a well known dropper, i hope the name is nothing to do with the usa and that the person is actually a russian thats registered the name,

damn more conspiracy

either way

a it shouldnt of been there and accessable by anything other than a printer user.

b found during the last 12 months

c fully fixed by microsoft.

the worst thing ever to happen was to provide an operating system with a computer , bios based would of been better

1/19/2006 2:46:00 PM by Anonymous

# re: Inside the WMF Backdoor

ruy: This same vulnerability sat in the Wine source, so having the source available didn't seem to make a difference.

1/19/2006 4:10:00 PM by Anonymous

# re: Inside the WMF Backdoor

You gotta love the people who (obviously can't) and quickly jump to defend MSFT. Let's see now we went through VS, MVS, VMS, OS2, etc... and "we" still can't build an OS? If this explanation is sound, which I have no reason to question, then somebodies at MS need to be shown the door. Come on, they have Security groups and QA groups, and the development groups who SHOULD have caught this.

Now that I think about it, even Mark has to guess at what some coder was thinking when she wrote this, and maybe she did it intentionally. You'll never know will you? Maybe somebody's been watching all of us for years, and it ends up in some massive NSA database.

1/19/2006 4:14:00 PM by Habbab

# re: Inside the WMF Backdoor

Yes, Microsoft Q&A should have caught this. But, well, they didn't.

In 1992, this vulnerability would simply not have caused the fuss it does today. Of course it would still have been a vulnerability, and had it been pointed out it would have been fixed -- but people would not be up in arms about it.

Calling Microsoft incompetent over an old bug that never got fixed is easy, but it's slightly overblown. Let's not forget that this was a feature -- it served a need. It did so in a ham-fisted way that we can easily denounce as foolish with the benefit of hindsight, but let's be honest, sub-optimal solutions ("just make it work") are not exactly uncommon in software development.

Much worse mistakes than this have been made, by people and companies with much better reputations in this department than Microsoft.

1/19/2006 6:01:00 PM by Anonymous

# re: Inside the WMF Backdoor

People are being a bit harsh on Steve here...

1. AbortProc has definitely been in Windows for a long time, without doubt.

2. Was it deliberately put there? Yes - it's usage is so clear that it's not there accidentally. It's not like this is a buffer overflow - someone HAD to have coded it this way.

3. Was it maliciously put there? Hard to say - possibly or possibly not. There are clearly legitimate uses for this "feature" of meta-files.

4. Was Microsoft careless? Yes! While there are naturally perfectly good reasons for having such code, Microsoft has not/did not take due care to ensure that this code could only be used for its intended purpose. I do a lot of coding in various languages, and I always make sure that my code can only be used for what it's supposed to - be copious error trapping, and scrutiny to inputs to functions. This code was rushed.

5. Should we go beserk at Microsoft? No! At the time this code was originally developed, I doubt anyone even conceived this as a potential attack vector - nevertheless, whoever coded this was sloppy.

6. Why sloppy? If the "malicious" side of this problem can be triggered using an impossible value of an input parameter - in this case, 1 - whoever coded this should have trapped for that input - and thrown up an error that the input is wrong - not drop into arbitrary code.

1/19/2006 6:15:00 PM by Michael Wyres

# re: Inside the WMF Backdoor

No body knows what Microsoft's, Mark's or Steve's intentions are but themselves. Let not talk about intentions.

Undoubtedly Mark is a professional in anaylsis of extremely technical stuff. While Steve often alert people of potential unsafe computing. I don't know their intentions, but I *think* they are having goodwill in computing.

So let's not attack these people who spend their time investigating potential risk to alert/inform users/administrators (better cause a fuss to get attention for other investigations and get a fix than being exploited by malicious attacks, right?) This WMF vulnerability is a good example already. We've got Steve at first and then Mark to follow up. May be someone to follow up later.

Lets do something constructive in the computing industry instead.

1/19/2006 7:38:00 PM by Felix the okayman

# re: Inside the WMF Backdoor

Given the time frame where this "BUG" appeared in NT ( it apparently does not affect Win9x or Win3x ), the comment of Congressman Weldon in the September 28, 1999 Internet Caucus Panel Discussion might be relevant:

Rep. Curt Weldon: But the point is that when John Hamre briefed me, and gave me the three key points of this change, there are a lot of unanswered questions. He assured me that in discussions that he had had with people like Bill Gates and Gerstner from IBM that there would be, kind of a, I don't know whether it's a, unstated ability to get access to systems if we needed it. Now, I want to know if that is part of the policy, or is that just something that we are being assured of, that needs to be spoke. Because, if there is some kind of a tacit understanding, I would like to know what it is.

1/19/2006 9:29:00 PM by David

# re: Inside the WMF Backdoor


While I applaud your efforts to explain the *details* of this vulnerability (and nicely done too) and why it may have been allowed to exist, there's one point Gibson brought up you didn't cover: Why, if as you claim that this was seen as a 'feature' in days so long ago (Win 3.x) that code inside a .wmf file could rely upon 'hard-coded addresses when patches didn't exist,' did Microsoft make sure embedded-code-execution couldn't happen under Windows 9x (in fact adding extra code to keep it from ever doing so!) yet still allow it (or more correctly added it to? ) their Windows NT series? Therefore, it seems at least one person in the 'NT development' dept. (who could have checked how Windows 9x handled .WMF files) chose to allow for arbitrary code execution instead. It's not a coding error: The 'mistake' was for Microsoft during many code reviews to allow it to continue that way in Win 2000, XP and beyond until an exploit finally made use of it!

(Michael: Gibson recently admitted that he made an error in assuming there was only 1 specific way to trigger the exploits as Mark pointed out to us.)

Though Gibson may be overly flamboyant in ways that market his product, hasn't he helped many more Net users by calling attention to 'security flaws,' telling us how to protect our systems, by being the person he is? Woldn't there have been many more people on the Internet with 'unprotected boxes' full of worms/trojans if he never spoke up?

1/19/2006 9:38:00 PM by The Starman

# re: Inside the WMF Backdoor

Great point about Dave Cutler. I'd really be willing to give Microsoft the benefit of the doubt, but when they come out with statements like the security landscape has changed, that's a bit ignorant, and you really start to wonder about the rest of their statements.

Maybe from Microsoft's standpoint, the landscape has changed - they weren't focused on security then, they are more focused now.

Cutler worked on VMS at DEC, he was probably familiar with the Morris Worm, otherwise known as the "Great Worm". That was 1988. In the movie WarGames ('84?), Mathew Broderick uses a backdoor to hack into a military system. So script kiddies "landscape has changed" if you haven't seen the movie, dust off your VHS player and rent it.\_wor

Couple other points:

This is a technicality, but my understanding of the WINE vulnerability is that it is a similar issue, but not the same, i.e. the replicated the full functionality of Windows in order to be compatible, but the mechanism of the "bug/feature" is somewhat different. Obviously the code is different. But yeah, if the WINE folks ported this over without thinking about it, (even if it is different) I buy that argument much better than Microsoft's "well it's all in assembly code who reads that stuff anymore" waffling. Don't tell that to folks like Ilfak Guilfanov or Steve Gibson - assembly code wizards.

Finally, and this is the whole Microsoft confusion that started Gibson on the track of figuring out what exactly was broken (I'm sure they are kicking themselves now), what is the deal with Win9x? Microsoft claims the vulnerability is there, but there's this extra step, and thus it's not a "critical vulnerability"? Huh? Talk about waffling. As Gibson points out, if this wasn't intentional, why in the world did they take it out in the later OSes? Cuz seriously, if you write code like this, or if you're at all familiar with buffer overruns and the like, a smart programmer (as detailed in Steve Macquire's excellent book about coding at Microsoft 'Writing Solid Code', would've added a check for the context or something like that)

As to whether this is a backdoor or not, put yourself in the shoes of a lowly MSFT programmer, smart hacker type, but under deadline pressure to get the next great feature out the door. Might this feature somehow help you with testing your code? I recall a web programmer adding a nifty feature to a web page - type in some sql in the url, and it would hit the table. Great for testing. Somehow this got to production, and they basically shut their site down for three days, or ran it in a restricted mode, while they fixed this.

Finally I think the folks who criticize Gibson about his end of the world scenarios are bit misled and naive. (He was right about raw sockets, think SP2).

This stuff is a big deal. Read up on China's Titan Rain hackers. The landscape hasn't changed (NT/Unix/Linux), security is still an issue, exploits are similar, but the stakes, the impact, is vastly different.

1/19/2006 10:57:00 PM by Anonymous

# re: Inside the WMF Backdoor

"On the other hand,
Q: When was this backdoor coded?
A: About 1992.
Q: How old was VMS at that time?
A: 15 years.
Q: Who directed the development of Windows NT?
A: Dave Cutler.
Q: What's Cutler's background.
A: Directed VMS at DEC.
Q: On who's watch was this security lapse ported into the
Windows NT stream.
A: Presumably Cutler's."

My understanding was that this vulnerability goes back to Windows 3.0, which was released in 1990. Part of the problem in this excerpt it that is seems to equate NT 3.1 with Windows 3.x, which is not the case. Also, pointing the finger at Cutler seems a bit misleading, since it seems unreasonable to believe that he was responsible for the design of the WMF format.

Given the nature of the factors required for the exploitation of this, I really don't see why Steve jumps to the conclusion that it's in there on purpose as some sort of backdoor. Part of the problem is that, if Microsoft reviewed this issue during the security code review (as he claims), it's a bit far-fetched to think that they would not address it, knowing that if found out, it could be a huge, huge blow to the company.

1/19/2006 11:45:00 PM by Anonymous

# re: Inside the WMF Backdoor

I am perfectly willing to believe in Microsoft’s incompetence but it that really an acceptable excuse?
Even if the intention was not malicious why did they unblock this functionality after Windows 3.x, enabling it to automatically run code at a time when they should have already been well aware of the security dangers of the landscape?
Why wasn’t this corrected during the recent security code review MS claims to have completed? Were they so incompetent they didn’t realise this could be dangerous or did they just not check properly?

All of us must accept censure when our work is erroneous or flawed especially if we are arrogant enough to believe that opening our work to independent scrutiny is unnecessary.
Why should Microsoft be given a free pass?

1/20/2006 12:44:00 AM by Don't blame me - I'm just imcompetent

# re: Inside the WMF Backdoor

Obviously the WINE release would have the same issue, despite source code being available, as it is a compatibility layer implementation of the Windows API. But can you compare windows meta files' prevalence, when used with the WINE environment under Linux, to their prominence within the MS Windows package, and the fact that most Windows users are running in Admin mode?

I just don't see open source coders spending much time looking at a port of a propritary API with a view to fixing bugs, so that they can then, what? Presumably get in touch with MS and say, here we fixed this problem of yours for free.

The open source dicta, that with enough eyes on the code, all bugs are trivial, can only really operate when the 'eyes' feel they have a shared interest in the end product. How many feel that way about Windows? When I used to use Windows it felt more like they owned my puter, than I owned a part of Windows.

1/20/2006 7:25:00 AM by ruy_lopez

# re: Inside the WMF Backdoor

The "deal with Win9X" is pretty simple.

The vulnerability is there, however there are no default viewers for WMF files. The result is that rather than a drive-by-download attack the user would have to save the .wmf to disk, launch an application that can view wmf files, open the file in that application. MS argument is that this makes it non-critical on those platfor