Slashdot Mirror


Microsoft Responds to WMF Vulnerability

beuges writes "In an entry on the Microsoft Security Response Center Blog, Stephen Toulouse explains exactly how the WMF flaw could be triggered. BetaNews has an overview of the company's response." From the BetaNews article: "This code exists on every version of Windows since version 3.0, security firms have said. When this functionality was introduced, Toulouse said the security landscape differed from what it is now and metafile records were completely trusted by the operating system. Gibson claimed that the flaw could be exploited only by using a byte size of 1 in the metafile record, which Toulouse says is incorrect. He surmised that Gibson's tests had the offending function as the last entry in the metafile, which caused only incorrect sizes to trigger the flaw." We've previous reported on the backdoor claim.

18 of 221 comments (clear)

  1. Security a top priority since 2002 by sl4shd0rk · · Score: 3, Informative

    It's nice to know they are taking such a proactive stance on the issue of security. http://news.com.com/2100-1001-816880.html

    --
    Join the Slashcott! Feb 10 thru Feb 17!
  2. Re:Every version since 3.0? by mwvdlee · · Score: 3, Informative
    The WMF flaw was patched ahead of schedule


    "ahead of schedule" meaning "after a number of exploits have been released but before our original delayed release date"?
    --
    Slashdot social media options: AIM, ICQ, Yahoo, Jabber and Mobile Text. Why no MySpace?
  3. Re:Why does Windows have so much legacy? by IamTheRealMike · · Score: 5, Informative
    Windows 3.0?! Ok, if it was a problem back then, why didn't it get fixed when the security environment changed?

    There are a large number of 16 bit (ie Win3.0/3.1) apps out there that are still in industrial use. They tend to be obscure things - applications for subtitling TV transmissions, interfacing to medical kit etc. Although it may be hard for you to believe there are no apps out there more than 10 years old in fact there are, and often the computers these apps run on are upgraded to new versions of Windows as time goes by (because it'd be a huge pain to have like 8 versions of Windows in use in a single organisation).

    Fixing this flaw does in fact break backwards compatibility, and that means somewhere some random app we've never heard is is broken right about now - of this I am almost certain. That has a cost, and nobody wants to break peoples apps and cause network admins headaches without good reason.

    Apple realized that it's legacy code was no good years ago and succesfully ditched it in favor of something more modern, why can't windows do the same?

    Apple did no such thing - they maintained a compatibility mode in the OS and more importantly kept the Carbon APIs around mostly complete so legacy code could be ported over very easily. And of course, Apple had hardly any mission-critical apps running on their platform anyway so the pain and cost was much less than it would be for Microsoft.

    In fact, Windows does run Windows 3.1 apps in a VM type process these days, it's called a WoW (Windows on Windows) VM, but the integration is so tight most users never even realise it. Except for looking a bit dated the apps continue to run correctly and appear on the same desktop etc. In other words, Microsoft already did what you asked for!

    Now it didn't mitigate this vulnerability, because the Microsoft developers who wrote the Windows Image/Fax viewer wanted to support every file format they could, and when supporting WMF was so easy why not do it? They unfortunately didn't get the memo about this being a potential attack vector: this is a failure of corporate communications, and perhaps over-zealous developers, not a failure of operating system design.

    As an interesting historical aside, Raymond Chen has said that back in the early days of the Windows 95 project there were in fact two competing approaches to 3.1 compatibility: a VMware type approach where the 16 bit environment ran inside a window box that was in turn running a copy of Windows 3.1 .... and the approach they actually ended up using which was based on API thunks. The thunk approach was more complex but had much better integration, much lower resource usage (not running two operating systems on top of each other) and in usability tests came out on top every time. Everybody who tried the tight integration approach preferred it, and MS management felt they couldn't ask users to put up with a very jarring experience - potentially forever, in the case of apps that'd never be ported to Win32.

  4. What WINE does by JohnGrahamCumming · · Score: 5, Informative

    I think that their implementation contains exactly the same bug as Windows (as others have pointed out) and that if you take a look at the code you can easily see why (and it's not a backdoor).

    First the file dlls/gdi/metafile.c contains a function called PlayMetaFileRecord with the following signature:

    BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )

    Which is simply WINE's implementation of the same Win32 API (which is documented here: http://msdn.microsoft.com/library/default.asp?url= /library/en-us/gdi/metafile_1yec.asp)

    The third parameter (mr) is a METARECORD pointer (a METARECORD is just an entry in the metafile and is detailed here: http://msdn.microsoft.com/library/default.asp?url= /library/en-us/gdi/metafile_8j1u.asp) and is the all important header with the following definition:

    typedef struct tagMETARECORD { DWORD rdSize; WORD rdFunction; WORD rdParm[1]; } METARECORD, *PMETARECORD;

    With the rdSize being the size of the record in words, the rdFunction being the function and the rdParm the data (which in the case of an exploit would be executable code). PlayMetaFileRecord handles META_ESCAPE like this:

    case META_ESCAPE:
    Escape( hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
    break;

    You'll note that parameter 3 is a pointer into the metafile parameter block, i.e. if executed parameter 3 would execute code in the metafile. Now Escape has implemented like this (dlls/gdi/driver.c):

    INT WINAPI Escape( HDC hdc, INT escape, INT in_count, LPCSTR in_data, LPVOID out_data )

    and the SETABORTPROC is handled with the following code:

    case SETABORTPROC:
    return SetAbortProc( hdc, (ABORTPROC)in_data );

    So if you have an ESCAPE/SETABORTPROC record in a metafile then under WINE the AbortProc is set to point into the metafile (since in_data is corresponds to &mr->rdParm[2]).

    So it's quite clear from the WINE implementation that this is a way to set a pointer into the metafile for execution. All it would take is that the metafile's AbortProc is called and arbitrary code could be executed.

    In WINE at least this looks nothing like an intentional backdoor. It looks more like a bug caused by the fact that Escape is rather powerful and can set a pointer to code.

    Now it's possible in WINE (I believe) to force the AbortProc to execute with another ESCAPE record that has NEWFRAME as the function. Again looking at the Escape code you'll see that NEWFRAME has handled like this:

    case NEWFRAME:
    return EndPage( hdc );

    EndPage is a standard GDI function (see here for documentation: http://msdn.microsoft.com/library/default.asp?url= /library/en-us/gdi/prntspol_0d6b.asp). If you take a look at the implementation in WINE you see the following code (dlls/gdi/printdrv.c):

    INT WINAPI EndPage(HDC hdc)
    {
    ABORTPROC abort_proc;
    INT ret = 0;
    DC *dc = DC_GetDCPtr( hdc );
    if(!dc) return SP_ERROR;

    if (dc->funcs->pEndPage) ret = dc->funcs->pEndPage( dc->physDev );
    abort_proc = dc->pAbortProc;
    GDI_ReleaseObj( hdc );
    if (abort_proc && !abort_proc( hdc, 0 ))
    {
    EndDoc( hdc );
    ret = 0;
    }
    return ret;
    }

    Note that this function always called the Abo

  5. FTFA by defile · · Score: 1, Informative
    • The vulnerable code has been there since 3.0, but it wasn't exploitable until very recently.
    • Gibson's claim that it was an intentional vulnerability is bogus (it was bogus before, but just in case you needed confirmation, here it is from Microsoft)

    Thanks.

  6. Re:Every version since 3.0? by dirty · · Score: 2, Informative

    I believe the lineage is actually BSD -> NeXTStep -> Mac OS X. Apple simply bought NeXT because their previous attempt at a new OS (Copland) had failed. With NeXT they got NeXTStep which was the foundation for OS X (that's why all of the Cocoa classes start with NS). Even with all of this it took two full versions before OS X became useable, 10.0 and 10.1 were dog slow from what I understand. A complete rewrite of any major product from scratch is an extremely daunting task.

    --

    -matt
  7. Re:Every version since 3.0? by Shano · · Score: 5, Informative

    I believe it was a part that WINE reimplemented, and it's certainly documented. I don't follow WINE that closely, though, so I can't say for sure.

    The WMF spec allows a file to define a callback function that is executed in case of an error (it resembles ON ERROR GOTO more than modern exception handling). This was presumably useful for some reason, although I'm not aware it was ever used. The exploit defines a malicious callback function, then deliberately creates an error condition.

    Any correct implementation of the spec should have the same vulnerability, whether it's done by Microsoft, WINE, or anyone else.

  8. Stop, and think for a moment by anzev · · Score: 4, Informative

    Ok, i've been reading about this for much too long. It seems that there are two main issues here, how the flaw went unnoticed and why Microsoft didn't reimplement the whole legacy thing.

    Did anybody even RTFA? I've seen a lot of people already writing that Microsoft should have re-implemented the Legacy code, yadayadayada, write a new OS from scratch, introduce a new virtual machine just for OS compatibility. However, you all missed something very important. WMF is a well-defined standard (not saying a good one, but a well-defined one!) which means that Microsoft (or Wine for that matter) HAS TO IMPLEMENT IT WITH CERTAIN CONSIDERATIONS. One of them, is the SetAbortProc procedure that's been causing so much trouble. If Microsoft would failed to implement one part of this standard we would be getting comments like "M$ is 3vil, they don't respect standards...". I bet they're sorry that the security flaw got missed. I think it shows on their stock also! But non the less, it's fixed now.

    Come to think of it, I think that, in a world where there were no exploits (PC-wise) the whole callback function scenario was pretty cool. You'd just say that if something fails, notify the user with this procedure in my code, and since you already no it failed (no return false statement :-) ), you can also do some other tasks.

    One more sidenote, Microsoft HAS REIMPLEMENTED the code. This is proven by the following statement in the article:

    With WMF we want to be very clear: the Windows 9x platform is not vulnerable to any "Critical" attack vector. The reason Windows 9x is not vulnerable to a "Critical" attack vector is because an additional step exists in the Win9x platform: When not printing to a printer, applications will simply never process the SetAbortProc record. Although the vulnerable code does exist in the Win9x platform, all "Critical" attack vectors are blocked by this additional step.

    I have no idea why they've let this slip though in the XP.

  9. Re:"Landscape has changed" by multipartmixed · · Score: 4, Informative

    > I wonder how much arbitrary code could have been executed by UNIX
    > or even Netware in those days?

    Plenty. At one point, it was possible to hack a Sun box running sendmail using nothing more than telnet.

    Yeah, baby, a root shell prompt without even logging. Now THAT was scary.

    --

    Do daemons dream of electric sleep()?
  10. Kind of makes you wonder, though. by martinultima · · Score: 1, Informative

    If Micro$oft can document the exact procedure for triggering the bug so well, then that indicates that they have a very good idea how it works. If they have a very good idea how it works, then that implies that they should have been able to fix it sometime long before now. Therefore, if Micro$oft can document the exact procedure for triggering the bug so well, then they should have been able to fix it sometime long before now. QED.

    Maybe it's just the fact that I'm a Linux user who's naturally suspicious of anything Micro$oft does, but something does seem kind of fishy here.

    --
    Creative misinterpretation is your friend.
  11. Re:Odd thing to introduce... by DrPizza · · Score: 2, Informative

    I haven't seen any evidence thus far that a change was introduced in 2000/XP. So far, everything suggests that it's always been in the NT 3.1 line.

    What "saved" windows 9x is that it was a completely different code-base from NT (derived from Win3.x); it was likely altered independently by the 9x product team. But because of the separate code-bases there was no cross-pollination of this change to the NT line. Presumably the recent patch implements an equivalent fix (so that SetAbortProc is only handled when actually printing). Or perhaps it removes the functionality altogether, as even when printing, the behaviour seems risky.

    It may well be that this "defer until the next record is read" behaviour exists in 9x (even if when actually printing) and Win3.x too.

    Rather, the issue that arose in XP and 2003 is that they bundled a COM control that could handle WMF files, and which assumed them to be trustworthy.

    IE was deliberately neutered because in IE it's obvious that any WMF file /isn't/ trustworthy. But in the Fax Viewer thingy, such an assumption can't be made. The WMF files it views could come from anywhere; some sources friendly, others hostile. So it is not altogether surprising that it did not have an equivalent change made to it.

  12. Re:Inverse security evolution by m50d · · Score: 2, Informative

    They didn't remove it, it was just never added to the new program (windows printer and fax viewer) when it was written. If this was there as a fix in win9x then this shows why it's important to update specifications with security fixes, but it could just as easily be different application writers taking different approaches and one of them incidentally fixing the flaw.

    --
    I am trolling
  13. 'ported' isn't really the word by dioscaido · · Score: 5, Informative

    Something that people don't seem to realize is that when a new OS is created for a particular windows family (95/98/ME or NT4/2000/XP/2003/Vista), functions aren't 'ported'. Instead the same codebase is worked on until you arrive at the next version. So once that function was ported over from the 95 family to the NT4 family, it probably remained untouched, with this vulnerability. So it's not necessarily correct to say 'why did they keep porting this function across OS?!'.

    The reality is the windows codebase has a ton of legacy in it. One positive step taken for Vista is that *all* code, including legacy (actually, most importantly, legacy), was SAL annotated so that static analysis of the full codebase could be performed for a large variety of coding mistakes that lead to vulnerabilities. Related to that, all memory/string functions that don't take bounds have been removed from the codebase, which allows SAL to statically analyze for buffer overruns. There's been a few times when thanks to updates to the SAL agent I've had bugs assigned to my code that catch obscure issues. You can read more about the technique at: http://research.microsoft.com/slam/ At the same time, WIM is doing a second security sweep of all windows components. This is in no way complete, given that things like this WMF vulnerability still got through, but still it is a start, and is a process that is evolving every day.

    I'd like to point out that in Vista WMF is mitigated by the fact that unless you are logged in as the straight Administrator account, the arbitrary code executed from the WMF exploit will only have limited user access to the system (no access to write to the windows directory, program files directory, and system registry for example) even if the account is part of the Administrators group. Honestly this is probably the #1 reason to move to Vista -- it finally has a coherent LUA story and by default I can run all my apps with low priviledges.

  14. Re:Odd thing to introduce... by lseltzer · · Score: 3, Informative
  15. Re:Every version since 3.0? by Thundersnatch · · Score: 2, Informative

    At some point Microsoft will release a completely new OS. It will probably look something very much like Singularity. Reliability and security, rather than speed or features, will be the focus.

  16. Re:Incorrect sizes? by Anonymous Coward · · Score: 1, Informative
    Then how come only size 1 worked, not other incorrect sizes?

    Ilfak's tester used a size of 17. The metasploit module used a size of 4.

    In fact, I'm pretty sure Gibson is mistaken with his own tester. I tried changing the size (using a debugger) to 3, and that successfully triggered the exploit. So did sizes 4, 5, 6 and 7. I really don't know what he's going on about.

    size==0 doesn't work because there is a check in GDI32.DLL:
    77F4A5CB: mov eax, [edi] ; get length
    77F4A5CD: lea ecx, [eax+eax] ; bytes to words
    77F4A5D0: cmp ecx, eax ; check for overflow
    77F4A5D2: jb short loc_77F4A60F
    77F4A5D4: test eax, eax ; check for zero
    77F4A5D6: jz short loc_77F4A60F
    At loc_77F4A60F is code to place -1 in EAX (-1 is an error in this case), so the function returns an error and GDI32.DLL doesn't even process the record.

    size==2 doesn't work because there is a check to see if the metafile function for the current record is non-zero:
    77F4A602: mov ax, [esi+4] ; function of next record
    77F4A606: neg ax
    77F4A609: sbb eax, eax
    77F4A60B: and eax, esi ; eax will be zero if [esi+4] is zero
    77F4A60D: jmp short loc_77F4A612 ; end of function
    The above code is quite clever. "sbb eax, eax" will place 0 in eax if the carry bit is not set, but will place -1 in eax if the carry bit is set. neg sets the carry bit if its operand is non-zero. So this function fails (zero is an error in this case) if the "rdFunction" field of the metafile record is zero.

    Gibson's WMF looks like this:
    01 00 09 00 00 01 18 00-00 00 01 00 0C 00 00 00
    00 00 01 00 00 00 26 06-09 00 00 00 68 B0 03 00
    00 B8 00 00 00 00 FF D0-C3 00 03 00 00 00 00 00
    The "01 00 00 00" is the little-endian 32-bit size (which is in 16-bit words). You can see here how using a size of 2 causes the next record to start with "26 06 09 00 00 00", which is a record with size==0x00090626 and rdFunction==0. Indeed, replacing "01 00 00 00 26 06 09 00 00 00" with "02 00 00 00 26 06 09 00 00 01" allows the exploit to be triggered, and that is an example of a successful exploit where size==2.

    So the only real erroneous value for size is 0, which makes sense, since a size of 0 would cause the WMF parser to enter an infinite loop as it processes the same record ad infinitum.
  17. So where does Microsoft refute Gibson?? by dtjohnson · · Score: 3, Informative

    Read more closely. Where does Microsoft actually say that Gibson is wrong? Gibson claimed that Windows XP would read a .wmf file and begin executing a portion of the data file contents as executable code if a metafile record was encountered with a length of one byte. Since the minimum length of a valid metafile record is 6 bytes, Gibson suggests that the behavior was intentional rather than an accident. Microsoft doesn't actually SAY in their response that any of what Gibson claims is wrong:

    Gibson: Except that, when I was pursuing this and finally got it to work, what Windows did when it encountered this Escape function, followed by the SETABORTPROC metafile record, was it jumped immediately to the next byte of code and began to execute it. That is, it was no longer interpreting my metafile records record by record, which is the way metafiles are supposed to be processed.

    Microsoft: If you are seeing that you can only trigger it with an incorrect value, it's probably because your SetAbortProc record is the last record in the metafile.

    Gibson: It turns out that the only way to get Windows to misbehave in this bizarre fashion is to set the length to one, which is an impossible value. I tried setting it to zero. It didn't trigger the exploit. I tried setting it to two, no effect. Three, no effect. Nothing, not even the correct length. Only one.

    Microsoft: The vulnerability can be triggered with correct or incorrect size values.

    Even though the Microsoft guy claims he is going to "get rather technical here" he never specifies what he considers an 'incorrect' or 'correct' size value to be. More importantly, he never refutes the claim that a record with a length of one byte would always cause Windows to spawn a new thread and begin executing 'data' as code.

  18. Re:Why does Windows have so much legacy? by Locutus · · Score: 2, Informative

    Part of the design for how Windows95 ran Windows3.x code probably had to do with how the competition ran that code. For instance, IBM was selling a million copies a month of 32bit OS/2 when Windows95 was finally released and OS/2 was a major threat during the formative years of Chicago. Running those old apps in a VM like OS/2 did, resulted in two different look/feels and really made the old Windows3.x stuff seem old and outdated to the user. Microsoft needed users to THINK they had a new system even when running the old code. When Windows95 finally shipped, OS/2 had a good number of native applications running on it along with all the Windows3.x applications which ran on it too. Heck, Microsoft even went so far as to tell the press/public it was a new 32bit operation system when the techies were showing them it wasn't...Dos/Windows95 was a hack to beat OS/2 when 32bit WindowsNT v3.1 turned out to be overbloated as a destkop OS. The fact that it has the flaws of Windows3.x should not be a surprise. And looking back at how poorly Microsofts tools on WinowsNT v3.1, 3.50, 3.51, and 4.0 applications used multi-threading, it shows that they did very little redesign above the system kernel and did more porting of the application/tools and most likely much more. Again, not a surprise that flaws show up all the way down the lineage when the "feature" existed back that far. How would you have liked to be a developer at Microsoft when they failed to beat OS/2 with NT and then started hacking on DOS/Windows for 3 years to only come out with the hack that was DOS/Windows95? Intel and Microsoft fractured some on this when Intels 32bit PentiumPro CPU ran slower on DOS/Windows95 than it's older Pentium( 150MHz vs 150MHz )....

    BTW, how many times has Microsoft told the press that they were rewriting and redesigning their new operating system? We're getting close to needing another hand to count them. It is why Microsoft is really much more of a Marketing Company and than a technology company. They rely less on techical solutions to their "problems" and more on smoke and mirror kinds of solutions IMO. And had they done things right, they wouldn't need to rely so much on fake "Get the Facts" programs either. But THAT Microsoft never existed so there's not much hope of it ever happening. So Microsoft Windows still sucks and history shows that it will for another decade or more no matter what lies, half-truths, fabrications come out of their executives mouths. IMO.

    LoB

    --
    "Anyone who stands out in the middle of a road looks like roadkill to me." --Linus