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.
That's quite a long time to have a flaw in your OS. Maybe they should focus more on security rather than a fancy new AeroGlass interface.
My journal: Clicky. Read it because it
More importantly: when is the patch for 3.1 and MS Bob coming out?
An interesting quote from the first link:
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.
Which makes me wonder, why on earth did they remove that security measure in later versions of Windows?
The Tao of math: The numbers you can count are not the real numbers.
I think maybe Windows' landscape has changed but security wasn't so passe' to other software makers. I wonder how much arbitrary code could have been executed by UNIX or even Netware in those days? And I leave open the possibility that it could have. In the long run, this was left uncheck and maybe forgotten for what, 12-15 years now? And more importantly, was brought right into the server code from the desktop code.
I think therein lies the fundamental problem with Windows and why SA's warned for years about Microsoft's assbackwards approach to security. Windows is at it's heart a desktop OS and as such has a reverse understanding of security.
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.
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).
/library/en-us/gdi/metafile_1yec.asp)
/library/en-us/gdi/metafile_8j1u.asp) and is the all important header with the following definition:
/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):
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=
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=
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=
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
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.