分析研究报告

漏洞介绍:

适用环境:

     全补丁 xp,  2003系统

 

漏洞发现时间:2013-3-4

漏洞起因:

         ImagePath 项读取的长度未做检查和限定,导致后面的复制有问题

影响系统:xp, 2003

 

危害
本地拒绝服务

 

攻击所需条件: 填充注册表ImagePath 修改成REG_MULTI_SZ, 填充数据 的长度

Len(DWORD 类型) 满足:Len > = 65536

 

一.漏洞poc的构造(poc.exe)

创建一个服务:xxxx2, 删除原有的ImagePath 键值,新建 REG_MULTI_SZ类型的ImagePath,填充 Len = 65536 ,内容为:
pBuffer[65536] = {‘\\’,0,’A’.....后面全部是A};

 

二.漏洞分析(xp sp3  英文版)

 

05 f8af9bd8 8057e40e nt!KiTrap0E+0xd0

06 f8af9c80 80580f31 nt!IopBuildFullDriverPath+0xf6

07 f8af9d54 80581487 nt!IopLoadDriver+0x227

08 f8af9d7c 8053876d nt!IopLoadUnloadDriver+0x45

09 f8af9dac 805cff64 nt!ExpWorkerThread+0xef

0a f8af9ddc 805460de nt!PspSystemThreadStartup+0x34

0b 00000000 00000000 nt!KiThreadStartup+0x16

 

 

蓝屏时候的堆栈,一步步跟踪后,重点从IopBuildFullDriverPath开始下断点,看实际的系统操作,最终会调用(从调用堆栈就可以看出)

 

PAGE:805A5B8B                 lea     eax, [ebp+Destination]

PAGE:805A5B8E                 push    eax             ; nDestLen

PAGE:805A5B8F                 push    [ebp+BugCheckParameter1] ; KeyHandle

PAGE:805A5B92                 lea     eax, [ebp+pusDriverName]

PAGE:805A5B95                 push    eax             ; pusDriverName

PAGE:805A5B96     call    _IopBuildFullDriverPath@12 ; IopBuildFullDriverPath(x,x,x)

 

重点函数体在此:

 

此函数声明:

int __stdcall IopBuildFullDriverPath(PUNICODE_STRING pusDriverName, HANDLE KeyHandle, int nDestLen)

 

 

 

进入此函数内部:

直接调用IopGetRegistryValue  获取ImagePath 的KEY_VALUE_FULL_INFORMATION ,通过第三个参数返回结构体信息:

此结构体如下:

typedef struct _KEY_VALUE_FULL_INFORMATION

{

ULONG TitleIndex;

ULONG Type;

ULONG DataOffset;     

ULONG DataLength;

ULONG NameLength;

 WCHAR Name[1];

} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;

 

PAGE:004CF132                 mov     edi, edi

PAGE:004CF134                 push    ebp

PAGE:004CF135                 mov     ebp, esp

PAGE:004CF137                 sub     esp, 10h

PAGE:004CF13A                 push    ebx

PAGE:004CF13B                 mov     ebx, [ebp+arg_8]

PAGE:004CF13E                 push    esi

PAGE:004CF13F                 push    edi

PAGE:004CF140                 lea     eax, [ebp+pOutKeyFullInFormation]

PAGE:004CF143                 push    eax             ; int

PAGE:004CF144                 xor     esi, esi

PAGE:004CF146                 push    offset word_4CF242 ; ImagePath:

PAGE:004CF14B                 push    [ebp+ulLenWithoutNull] ; KeyHandle

PAGE:004CF14E                 mov     [ebx+2], si

PAGE:004CF152                 mov     [ebx], si

PAGE:004CF155                 mov     [ebx+4], esi

PAGE:004CF158                 mov     [ebp+arg_8], esi

PAGE:004CF15B                 mov     [ebp+var_8], esi

PAGE:004CF15E                 mov     [ebp+pOutKeyFullInFormation], esi

 

PAGE:004CF161             call    IopGetRegistryValue@12 ; IopGetRegistryValue(x,x,x)

PAGE:004CF166                 test    eax, eax

PAGE:004CF168                 jl      loc_4DE606

PAGE:004CF16E                 mov     ecx, [ebp+pOutKeyFullInFormation] ; ecx = pOutInformation  ;结构体输出 基地址0x81fbe00

PAGE:004CF171     mov  eax, [ecx+_KEY_VALUE_FULL_INFORMATION.DataLength] ; eax = 0x10000 ,填充的Name 数组就是这么大

PAGE:004CF174                 cmp     eax, esi

PAGE:004CF176                 jz      loc_4DE606

PAGE:004CF17C     mov     esi, [ecx+_KEY_VALUE_FULL_INFORMATION.DataOffset]

PAGE:004CF17F                 add     esi, ecx        ; esi = 0x81d16028

PAGE:004CF181                add     eax, 0FFFFFFFEh ; eax = eax - 2结果等于0xfffe

PAGE:004CF184                 cmp     word ptr [esi], 5Ch ; pValue[0] = L’\\’

PAGE:004CF188                mov     [ebp+ulLenWithoutNull], eax ; 这是Name字段的长度 不加后面的空(宽字符原因)大小为0xfffe

PAGE:004CF18B                 mov     [ebp+pValue], esi;指向Name起始地址

PAGE:004CF18E                 jz      short go1    ;第一个字符为 L’\\’ 直接跳走

 

--- 

/***

执行查询ImagePath 的KEY_VALUE_FULL_INFORMATION 

内存分布:

kd> db 81fbe000  

81fbe000  00 00 00 00 07 00 00 00-28 00 00 00 00 00 01 00  ........(.......

81fbe010  12 00 00 00 49 00 6d 00-61 00 67 00 65 00 50 00  ....I.m.a.g.e.P.

81fbe020  61 00 74 00 68 00 29 10-5c 00 41 41 41 41 41 41  a.t.h.).\.AAAAAA

81fbe030  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

81fbe040  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

81fbe050  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

81fbe060  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

81fbe070  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

 

前面是 结构体各个字段的信息,后面是 我们在ImagePath 里面填充的字符 “\ AAAAA....”

 

Ebx 下面是一个局部结构体变量 ,逆向后其结构为:

00000000 _MEM_INFOR      struc ; (sizeof=0x8)

00000000 wDataLen        dw ?    //字符长度,不带null

00000002 wLen            dw ?    // 整个mem 大小

00000004 pDstMem         dd ?    // 指针 ,指向开辟的空间

00000008 _MEM_INFOR      ends

***/

 

PAGE:004CF19E go1:  

PAGE:004CF19E                 mov     ecx, [ebp+ulLenWithoutNull] ;ecx 为Name字段的长度 - 2 

PAGE:004CF1A1                 mov     eax, [ebp+var_8] ; eax = 0

PAGE:004CF1A4                 mov     edi, [ebp+arg_8] ; edi = 0

PAGE:004CF1A7                 add     eax, ecx        ;eax = ecx

PAGE:004CF1A9                 lea     eax, [edi+eax+2] ; eax= eax +2,恢复整体长度 ,就是Name的totalLen = 0x10000

PAGE:004CF1AD                 mov     [ebx+_MEM_INFOR.wLen], ax ; Loword(eax)  eax 为整体的长度,此时MemInfor.wLen  等于 原始Name长度的低位值,这里poc 调试LOWORD(eax) = 0

PAGE:004CF1B1                 movzx   eax, ax

PAGE:004CF1B4                 push    20206F49h       ; Tag

PAGE:004CF1B9                 push    eax             ; NumberOfBytes ;size为0

PAGE:004CF1BA                 push    1               ; PoolType

PAGE:004CF1BC                 call    _ExAllocatePoolWithTag@12 ; ExAllocatePoolWithTag(x,x,x)   ;开辟的长度 为外部输入Name长度的低4位值,这里就明显没有根据了,可能没有他认为我们不可能输入这么长的字符数,这里取低位以后长度大小为 0

 

PAGE:004CF1C1                 test    eax, eax

PAGE:004CF1C3                 mov     [ebx+_MEM_INFOR.pDstMem], eax;存放指针

0xe1a79708

PAGE:004CF1C6                 jz      loc_519E9C

PAGE:004CF1CC                 mov     cx, [ebx+_MEM_INFOR.wLen] ;为 0

PAGE:004CF1D0                 sub     cx, 2   ;0 -2 = 0xfffe

PAGE:004CF1D4                 test    edi, edi ;edi 一直为零

PAGE:004CF1D6                 mov     [ebx+_MEM_INFOR.wDataLen], cx ; 实际能放的字符长度0xfffe ,这里已经错了

PAGE:004CF1D9                 jz      short go2       ; 肯定跳转  edi = 0

 

/******

此时 pMemInforDst 的情况为:

kd> dd ebx

f8af9cf8  0000fffe e1a79708

wDataLen        dw     0xfffe  //允许存放的空间大小

wLen            dw     0x0   //开辟的长度 为0

pDstMem         dd     0xe1a79708

 

*******/

PAGE:004CF1F3 go2:                                    ; CODE XREF: IopBuildFullDriverPath(x,x,x)+A7j

PAGE:004CF1F3                 mov     ecx, [ebp+ulLenWithoutNull]

PAGE:004CF1F6                 test    ecx, ecx

PAGE:004CF1F8                 jz      short loc_4CF20E

PAGE:004CF1FA                 mov     edi, [ebx+_MEM_INFOR.pDstMem]

PAGE:004CF1FD                 add     edi, [ebp+arg_8] ; arg8 = 0

PAGE:004CF200                 mov     eax, ecx

PAGE:004CF202                 shr     ecx, 2          ; ecx = ecx /4 这里就使用有问题了,它使用的是esi的size = 0x10000,而此时复制的目的DstMem 的size = 0(他是取得低四位数值)

PAGE:004CF205              rep movsd              

 ;esi : pNameValue  edi:pDstMem ,(ecx = 0x3ffff> (DstMem = 0) 开辟空间的大小 ,内存复制大小使用出错,导致蓝屏

 

至此 ,分析完毕

 

 

 

 

 

 

 

posted on 2013-07-30 16:59  5t4rk  阅读(362)  评论(0编辑  收藏  举报