最近调了instruder发的0day漏洞:http://www.exploit-db.com/exploits/18140/
把调试分析的情况写在这里。水平有限,让大家见笑了, 欢迎批评指正。
dump文件的分析结果如下:
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - "0x%08lx"
FAULTING_IP:
win32k!ReadLayoutFile+88
bf89ed23 0fb75006 movzx edx,word ptr [eax+6]
TRAP_FRAME: b28068a0 -- (.trap 0xffffffffb28068a0)
ErrCode = 00000000
eax=003e0000 ebx=00000000 ecx=003d0000 edx=804ff619 esi=00000000 edi=00000000
eip=bf89ed23 esp=b2806914 ebp=b2806944 iopl=0 nv up ei pl nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010206
win32k!ReadLayoutFile+0x88:
bf89ed23 0fb75006 movzx edx,word ptr [eax+6] ds:0023:003e0006=????
Resetting default scope
CUSTOMER_CRASH_COUNT: 1
DEFAULT_BUCKET_ID: DRIVER_FAULT
BUGCHECK_STR: 0x8E
PROCESS_NAME: 0Day.exe
LAST_CONTROL_TRANSFER: from bf89ec61 to bf89ed23
STACK_TEXT:
b2806944 bf89ec61 e12a4298 000007cc 00000160 win32k!ReadLayoutFile+0x88
b2806964 bf885192 000007cc 00000160 00000000 win32k!LoadKeyboardLayoutFile+0x6a
b28069f0 bf884c80 81ccf038 000007cc 08040804 win32k!xxxLoadKeyboardLayoutEx+0x1be
b2806d40 8053e638 000007cc 00000160 00409c40 win32k!NtUserLoadKeyboardLayoutEx+0x158
b2806d40 7c92e4f4 000007cc 00000160 00409c40 nt!KiFastCallEntry+0xf8
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012ffc0 00000000 00000000 00000000 00000000 0x7c92e4f4
分析后猜测,winXP没有对传入的文件句柄做任何检测,导致按照PE文件格式逐步解析畸形的键盘布局文件时出错。
漏洞发生在win32k!ReadLayoutFile函数中。下面主要是分析该函数流程:
.text:BF89EC9E ; int __stdcall ReadLayoutFile(int, HANDLE FileHandle, size_t, int)
.text:BF89EC9E _ReadLayoutFile@16 proc near ; CODE XREF: LoadKeyboardLayoutFile(x,x,x,x,x,x,x)+4Dp
.text:BF89EC9E
.text:BF89EC9E ObjectAttributes= OBJECT_ATTRIBUTES ptr -28h
.text:BF89EC9E ViewSize = dword ptr -10h
.text:BF89EC9E Handle = dword ptr -0Ch
.text:BF89EC9E var_8 = dword ptr -8
.text:BF89EC9E BaseAddress = dword ptr -4
.text:BF89EC9E arg_0 = dword ptr 8
.text:BF89EC9E FileHandle = dword ptr 0Ch
.text:BF89EC9E arg_8 = dword ptr 10h
.text:BF89EC9E arg_C = dword ptr 14h
.text:BF89EC9E
.text:BF89EC9E ; FUNCTION CHUNK AT .text:BF89E265 SIZE 00000071 BYTES
......
.text:BF89ECE1 mov [ebp+ObjectAttributes.SecurityDescriptor], esi
.text:BF89ECE4 mov [ebp+ObjectAttributes.SecurityQualityOfService], esi
.text:BF89ECE7 mov [ebp+BaseAddress], esi
.text:BF89ECEA call ds:__imp__ZwCreateSection@28 ; ZwCreateSection(x,x,x,x,x,x,x)
.text:BF89ECF0 test eax, eax
.text:BF89ECF2 jl loc_BF89E265
......
.text:BF89ED07 push eax ; BaseAddress
.text:BF89ED08 push 0FFFFFFFFh ; ProcessHandle
.text:BF89ED0A push [ebp+Handle] ; SectionHandle
.text:BF89ED0D call ds:__imp__ZwMapViewOfSection@40 ; ZwMapViewOfSection(x,x,x,x,x,x,x,x,x,x)
.text:BF89ED13 test eax, eax ; 执行对键盘文件的内存映射
.text:BF89ED15 jl loc_BF89EEB3
.text:BF89ED1B mov ecx, [ebp+BaseAddress] ; ecx保存执行文件映射后的内存基址
.text:BF89ED1E mov eax, [ecx+3Ch] ; 0x3c是IMAGE_DOS_HEADER_STRUCT的e_lfanew成员,该成员保存指向PE文件的偏移。
.text:BF89ED21 add eax, ecx ; 加上文件映射内存基址,eax指向IMAGE_FILE_HEADER结构
.text:BF89ED23 movzx edx, word ptr [eax+6] ; IMAGE_FILE_HEADER结构0x6偏移保存NumberOfSections成员
.text:BF89ED23 ; edx保存NumberOfSections成员的值
.text:BF89ED27 cmp edx, esi ; 比较是否NumberOfSections成员等于0
.text:BF89ED29 movzx ecx, word ptr [eax+14h] ; IMAGE_FILE_HEADER结构0x14偏移保存SizeOfOptionalHeader成员,
.text:BF89ED29 ; 用于表示IMAGE_OPTIONAL_HEADER32结构大小
.text:BF89ED2D lea eax, [ecx+eax+18h] ; ecx+eax+18h指向IMAGE_NT_HEADER结构的OptionalHeader成员,
.text:BF89ED2D ; 也就是指向IMAGE_OPTIONAL_HEADER32结构, eax得到相应的地址指针
.text:BF89ED31 push edi
.text:BF89ED32 mov [ebp+var_8], edx
.text:BF89ED35 mov [ebp+FileHandle], eax ; filehandle从此保存OptionalHeader的地址
.text:BF89ED38 jbe short loc_BF89ED50 ; 执行无符号比较
.text:BF89ED3A
.text:BF89ED3A loc_BF89ED3A: ; CODE XREF: ReadLayoutFile(x,x,x,x)-A23j
.text:BF89ED3A push 6
.text:BF89ED3C mov edi, offset a_data ; ".data" ;这里将会跳转做比较,对程序流程影响不大
.text:BF89ED41 mov esi, eax
.text:BF89ED43 pop ecx
.text:BF89ED44 xor edx, edx
.text:BF89ED46 repe cmpsb
.text:BF89ED48 jnz loc_BF89E26C
.text:BF89ED4E
.text:BF89ED4E loc_BF89ED4E: ; CODE XREF: ReadLayoutFile(x,x,x,x)-A29j
.text:BF89ED4E xor esi, esi
.text:BF89ED50
.text:BF89ED50 loc_BF89ED50: ; CODE XREF: ReadLayoutFile(x,x,x,x)+9Aj
.text:BF89ED50 cmp [ebp+var_8], esi ; [ebp+var_8]保存NumberOfSections成员的值
.text:BF89ED53 jz loc_BF89EEB2 ; 如果NumberOfSections的值等于0则程序结束
.text:BF89ED59 mov edi, [ebp+arg_8] ; arg8应该是文件大小 ????
.text:BF89ED5C sub edi, [eax+0Ch] ; eax指向IMAGE_OPTIONAL_HEADER32结构,eax+0xc指向SizeofUninitializedData
.text:BF89ED5C ; 所有未初始化数据区块总大小
.text:BF89ED5F mov eax, [eax+8] ; eax指向IMAGE_OPTIONAL_HEADER32结构,eax+0x8指向SizeofinitializedData
.text:BF89ED5F ; 所有初始化数据区块总大小
.text:BF89ED62 push esi ; int
.text:BF89ED63 push 746B7355h ; Tag
.text:BF89ED68 push eax ; NumberOfBytes
.text:BF89ED69 mov [ebp+arg_8], eax
.text:BF89ED6C call _HeavyAllocPool@12 ; HeavyAllocPool(x,x,x)
.text:BF89ED71 cmp eax, esi
.text:BF89ED73 mov [ebp+var_8], eax ; 保存分配的地址 <------------问题就在这里
.text:BF89ED76 jz loc_BF89EEB2
.text:BF89ED7C mov ebx, [ebp+arg_0]
.text:BF89ED7F mov ecx, [ebp+FileHandle]
.text:BF89ED82 push [ebp+arg_8] ; size_t 可控,从文件的0x140处的值
.text:BF89ED85 mov [ebx+0Ch], eax
.text:BF89ED88 mov ecx, [ecx+14h] ; ecx可控,从文件0x156处读出
.text:BF89ED8B add ecx, [ebp+BaseAddress]
.text:BF89ED8E push ecx ; void * ecx可控,从文件中读出
.text:BF89ED8F push eax ; void *
.text:BF89ED90 call _memmove
从上面的程序流程可以看出,ReadLayoutFile函数调用ZwCreateSection和ZwMapViewOfSection将传入键盘布局文件映射到内存中,然后执行PE
文件格式解析。ecx+3Ch将得到e_lfanew成员,eaxeax指向IMAGE_FILE_HEADER结构地址。
.text:BF89ED1E mov eax, [ecx+3Ch] ; 0x3c是IMAGE_DOS_HEADER_STRUCT的e_lfanew成员,该成员保存指向PE文件的偏移。
.text:BF89ED21 add eax, ecx ; 加上文件映射内存基址,eax指向IMAGE_FILE_HEADER结构
从POC代码可以看到正是对e_lfanew成员的fuzz导致了eax指向了一个无效地址,产生内存访问错的指令
.text:BF89ED23 movzx edx, word ptr [eax+6] ; IMAGE_FILE_HEADER结构0x6偏移保存NumberOfSections成员
通过适当修改POC文件,可以使程序流程执行到BF89ED62,将调用_HeavyAllocPool分配一块空间,然后执行_memmove。
从代码流程分析看,拷贝数据的源、长度分别来自键盘布局文件的0x140处的值,0x156处的值。数据源、数据长度可控,但是目的不可控 (:
从后续程序流程看,也未找到可以利用之处
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!