首页
社区
课程
招聘
[原创]CVE-2017-7269:IIS6.0远程代码执行漏洞逆向分析记录
2017-4-11 15:50 9082

[原创]CVE-2017-7269:IIS6.0远程代码执行漏洞逆向分析记录

2017-4-11 15:50
9082

0x0 写在前面

该漏洞可针对IIS 6.0的WebDAV服务发起攻击,通过缓冲区溢出造成远程代码执行。漏洞提交者已在GitHub上公布Poc代码以及漏洞描述,我们可以方便得到Poc以及漏洞信息进行调试

作为一个初学者,看完别人的分析文章需要做的是上手调试,于是形成了这篇调试笔记。行文略显烦琐,错误含糊之处希望各位指(pao)出(hong)

本文的分析思路是跟踪执行脚本时大规模拷贝的数据,弄清数据的含义以及拷贝之后的流程走向,因为没有对相关函数进行反汇编阅读,理解上难免狭隘肤浅

0x1 调试环境

  • [操作系统]: Windows Server 2003 R2 Enterprise Edition SP2

  • [调试器]: WinDbg 6.11.0001.402 X86

  • [Python]: Python 2.7

0x2 搭建调试环境

0x2.1 安装IIS 6.0

在Add or Remove Programs中选择 Add/Remove Windows Components

对Application Server选项的描述中提到了IIS

点击Details全部选中(只选择IIS应该也可以),然后点击Next

在安装组件的过程中需要插入安装光盘

安装完成之后打开IIS服务管理器

鼠标右键将WebDAV设置为Allow

打开服务,查看WebClient,需要将其开启

目前处于停止状态且无法开启,将该服务设为自启动,然后重启

此时服务正常开启

0x2.2 运行样本文件

将python路径设为环境变量,使用控制台窗口运行样本

查看任务管理器,多出了隐藏窗口的calc.exe进程

使用Process Explorer查看进程依赖关系

可以看到calc.exe的父进程是w3wp.exe

查看calc.exe进程详细信息

0x3 调试样本

由于w3wp.exe并不是开机启动的进程,而样本只是简单启动计算器,干脆先执行一次脚本,然后使用Windbg附加调试

既然会创建新进程,那就对几个关键API下断等它来

0:022> bu CreateProcessA
0:022> bu CreateProcessW
0:022> bu WinExec
0:022> bl
 0 e 77e424a9     0001 (0001)  0:**** kernel32!CreateProcessA
 1 e 77e42474     0001 (0001)  0:**** kernel32!CreateProcessW
 2 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec

执行起来,中断到kernel32!WinExec函数中

0:025> g
Breakpoint 2 hit
eax=77ea411e ebx=7ffe0300 ecx=68031614 edx=876f8b31 esi=68031460 edi=680124e3
eip=77ea411e esp=680313f8 ebp=68031581 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
kernel32!WinExec:
77ea411e 8bff            mov     edi,edi

查看调用栈

0:006> k
ChildEBP RetAddr  
68031581 00000000 kernel32!WinExec

没有调用关系可以参考,好了,老招数,对esp下断

0:022> bu WinExec
0:022> ba w4 680313f8 "kb; r; gc"
0:022> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 680313f8 w 4 0001 (0001)  0:**** rsaenh!g_pfnFree+0x13c "kb; r; gc"

凭感觉收获真是太多了

0:022> g
ChildEBP RetAddr  Args to Child              
0114f798 67119469 680312c0 0114f800 00000000 httpext!ScStoragePathFromUrl+0x360
0114f7ac 6712544a 020f2878 680312c0 0114f800 httpext!CMethUtil::ScStoragePathFromUrl+0x18
0114fc34 6712561e 020f01e8 01ecee36 0114fc78 httpext!HrCheckIfHeader+0x124
0114fc44 6711f659 020f01e8 01ecee36 00000001 httpext!HrCheckStateHeaders+0x10
0114fc78 6711f7c5 020f0238 0114fcd4 671404e2 httpext!CPropFindRequest::Execute+0xf0
0114fc90 671296f2 020f0238 00000004 011d5b88 httpext!DAVPropFind+0x47
0114fce0 67117bc6 01ecffa0 020f01e8 011d5b88 httpext!CDAVExt::DwMain+0x12e
0114fe04 5a322991 011d5b88 011d48c8 011d5518 httpext!DwDavFSExtensionProc+0x3f
0114fe24 5a3968ff 011d5af8 67117b87 0114fe50 w3isapi!ProcessIsapiRequest+0x214
...(lines have been omitted)...
eax=000005fc ebx=000002fd ecx=00000137 edx=680312c0 esi=020f29b8 edi=68031404
eip=67126fdb esp=0114f330 ebp=0114f798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
...(lines have been omitted)...
ChildEBP RetAddr  Args to Child              
68031581 00000000 0c528b30 8b14528b b70f2872 rsaenh!g_pfnFree+0x356
eax=68031633 ebx=7ffe0300 ecx=00000000 edx=6803163e esi=68031460 edi=680124e3
eip=68031612 esp=680313f8 ebp=68031581 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
rsaenh!g_pfnFree+0x356:
68031612 ffd5            call    ebp {rsaenh!g_pfnFree+0x2c5 (68031581)}
ChildEBP RetAddr  Args to Child              
68031581 00000000 0c528b30 8b14528b b70f2872 rsaenh!g_pfnFree+0x33e
eax=77ea411e ebx=7ffe0300 ecx=68031614 edx=876f8b31 esi=68031460 edi=680124e3
eip=680315fa esp=680313f8 ebp=68031581 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
rsaenh!g_pfnFree+0x33e:
680315fa ffe0            jmp     eax {kernel32!WinExec (77ea411e)}
...(lines have been omitted)...

重新加载样本,对如下rep movsd指令的地址下断

httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

设置断点

0:022> bu 67126fdb
0:022> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 67126fdb     0001 (0001)  0:**** httpext!ScStoragePathFromUrl+0x360

抢先剧透,这个漏洞的产生的确来自这里,这里的数据拷贝会来三次

通常俺喜欢从上层函数开始往下看

0:006> k
ChildEBP RetAddr  
00fef798 67119469 httpext!ScStoragePathFromUrl+0x360
00fef7ac 67125484 httpext!CMethUtil::ScStoragePathFromUrl+0x18
00fefc34 6712561e httpext!HrCheckIfHeader+0x15e
00fefc44 6711f659 httpext!HrCheckStateHeaders+0x10
00fefc78 6711f7c5 httpext!CPropFindRequest::Execute+0xf0

0:006> ub 67119469
httpext!CMethUtil::ScStoragePathFromUrl+0x2:
67119453 55              push    ebp
67119454 8bec            mov     ebp,esp
67119456 8b4910          mov     ecx,dword ptr [ecx+10h]
67119459 8b5508          mov     edx,dword ptr [ebp+8]
6711945c 6a00            push    0
6711945e ff7510          push    dword ptr [ebp+10h]
67119461 ff750c          push    dword ptr [ebp+0Ch]
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

好了重新加载样本,新增断点,对地址0x67119464下断

0:022> bu 680313f8
0:022> bu 67119464
0:022> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 67119464     0001 (0001)  0:**** httpext!CMethUtil::ScStoragePathFromUrl+0x13

运行样本,中断在httpext!ScStoragePathFromUrl函数调用前

0:022> g
Breakpoint 1 hit
eax=0118f800 ebx=020f01e8 ecx=01ecfa80 edx=020f08f0 esi=00000000 edi=77bd8ef2
eip=67119464 esp=0118f7a0 ebp=0118f7ac iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
httpext!CMethUtil::ScStoragePathFromUrl+0x13:
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

当前函数是这样的

httpext!CMethUtil::ScStoragePathFromUrl:
67119451 8bff            mov     edi,edi
67119453 55              push    ebp
67119454 8bec            mov     ebp,esp
67119456 8b4910          mov     ecx,dword ptr [ecx+10h]
67119459 8b5508          mov     edx,dword ptr [ebp+8]
6711945c 6a00            push    0
6711945e ff7510          push    dword ptr [ebp+10h]
67119461 ff750c          push    dword ptr [ebp+0Ch]
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)
67119469 5d              pop     ebp
6711946a c20c00          ret     0Ch

跟进httpext!ScStoragePathFromUrl,单步几句

httpext!ScStoragePathFromUrl:
67126c7b b8150d1467      mov     eax,offset httpext!swscanf+0x14b5 (67140d15)
67126c80 e803100000      call    httpext!_EH_prolog (67127c88)
67126c85 81ec50040000    sub     esp,450h
67126c8b a1c0701467      mov     eax,dword ptr [httpext!__security_cookie (671470c0)]
67126c90 8945f0          mov     dword ptr [ebp-10h],eax

此时内存布局为

G一下,到拷贝数据的位置

0:006> g
Breakpoint 2 hit
eax=00000130 ebx=00000097 ecx=0000004c edx=00fef804 esi=020f0910 edi=00fef828
eip=67126fdb esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

先不急,观察一下上下文,附近有四句rep movsd指令

67126faf f3a5            rep movs dword ptr es:[edi],dword ptr [esi] //the first instruction of "rep movsd"
67126fb1 8bca            mov     ecx,edx
67126fb3 8b95d4fdffff    mov     edx,dword ptr [ebp-22Ch]
67126fb9 83e103          and     ecx,3
67126fbc f3a4            rep movs byte ptr es:[edi],byte ptr [esi] //the second
67126fbe 8bb5bcfbffff    mov     esi,dword ptr [ebp-444h]
67126fc4 2bda            sub     ebx,edx
67126fc6 8d3456          lea     esi,[esi+edx*2]
67126fc9 8b95b0fbffff    mov     edx,dword ptr [ebp-450h]
67126fcf 8d3c10          lea     edi,[eax+edx]
67126fd2 8d4c1b02        lea     ecx,[ebx+ebx+2]
67126fd6 8bc1            mov     eax,ecx
67126fd8 c1e902          shr     ecx,2
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi] //the third
67126fdd 8bc8            mov     ecx,eax
67126fdf 83e103          and     ecx,3
67126fe2 f3a4            rep movs byte ptr es:[edi],byte ptr [esi] //the fourth

目前在第三处rep movsd,重新加载样本,看看前两次都干嘛了

新增断点0x67126faf

0:006> bu 67126faf
0:006> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 67119464     0001 (0001)  0:**** httpext!CMethUtil::ScStoragePathFromUrl+0x13
 2 e 67126fdb     0001 (0001)  0:**** httpext!ScStoragePathFromUrl+0x360
 3 e 67126faf     0001 (0001)  0:**** httpext!ScStoragePathFromUrl+0x334

G一下,断到第一句rep movsd指令处

0:006> g
Breakpoint 3 hit
eax=00000024 ebx=00000097 ecx=00000009 edx=00000024 esi=00fef35c edi=00fef804
eip=67126faf esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
httpext!ScStoragePathFromUrl+0x334:
67126faf f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

此时的目的地址edi的值就是上层函数传进来的第一个参数

查看拷贝的内容

0:006> du esi L2 * ecx
00fef35c  "c:\inetpub\wwwroot"

执行过去

0:006> bd *
0:006> p
eax=00000024 ebx=00000097 ecx=00000000 edx=00000024 esi=00fef380 edi=00fef828
eip=67126fb1 esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206

来到第二次rep movsd,拷贝次数为0,并不关心

0:006> t
eax=00000024 ebx=00000097 ecx=00000000 edx=00000000 esi=00fef380 edi=00fef828
eip=67126fbc esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!ScStoragePathFromUrl+0x341:
67126fbc f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

好了,来到关键的第三次rep movsd

0:006> t
Breakpoint 2 hit
eax=00000130 ebx=00000097 ecx=0000004c edx=00fef804 esi=020f0910 edi=00fef828
eip=67126fdb esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

查看拷贝的数据

0:006> du esi L2 * ecx
020f0910  "/aaaaaaa潨硣睡焳椶䝲稹䭷佰畓穏䡨噣浔桅㥓偬啧杣.䘰硅楒吱"
...(lines have been omitted)...
020f0a10  "Ꮐ栃䠴攱潃湦瑁䍬Ꮐ栃千橁灒.塦䉌灋捆关祁穐䩬>"

拷贝前,对比一下目的地址的原始数据和源地址的数据

0:006> db edi L4 * ecx
00fef828  60 06 ec 01 50 06 ec 01-00 00 00 00 00 00 00 00  `...P...........
00fef838  00 00 00 00 00 00 00 00-00 00 00 00 01 00 00 00  ................
...(lines have been omitted)...
00fef908  12 04 00 00 04 f8 fe 00-5b 20 11 67 13 00 00 00  ........[ .g....
00fef918  c0 f9 fe 00 e7 87 12 67-00 00 00 00 f0 00 00 00  .......g........
00fef928  13 00 00 00 00 00 00 00-24 f2 ec 01 fc 87 12 67  ........$......g
00fef938  d0 f9 fe 00 69 66 2d 75-6e 6d 6f 64 69 66 69 65  ....if-unmodifie
00fef948  64 2d 73 69 6e 63 65 00-00 00 00 00 78 01 ec 01  d-since.....x...

0:006> db esi L4 * ecx
020f0910  2f 00 61 00 61 00 61 00-61 00 61 00 61 00 61 00  /.a.a.a.a.a.a.a.
020f0920  68 6f 63 78 61 77 33 71-36 69 72 47 39 7a 77 4b  hocxaw3q6irG9zwK
...(lines have been omitted)...
020f09f0  02 02 02 02 c0 12 03 68-44 6c 56 52 37 4b 6d 6c  .......hDlVR7Kml
020f0a00  58 4f 5a 58 50 79 6a 49-4f 58 52 4a 50 41 4d 66  XOZXPyjIOXRJPAMf
020f0a10  c0 13 03 68 34 48 31 65-43 6f 66 6e 41 74 6c 43  ...h4H1eCofnAtlC
020f0a20  c0 13 03 68 43 53 41 6a-52 70 30 33 66 58 4c 42  ...hCSAjRp03fXLB
020f0a30  4b 70 46 63 73 51 41 79-50 7a 6c 4a 3e 00 00 00  KpFcsQAyPzlJ>...

忍不住又要剧透了,这次拷贝的关键在于覆写地址0x00fef90c处的数据,数据0x00FEF804修改为0x680312C0,这不是一个巧合

单步过去,然后G起来

0:006> bd *
0:006> p
eax=00000130 ebx=00000097 ecx=00000000 edx=00fef804 esi=020f0a40 edi=00fef958
eip=67126fdd esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x362:
67126fdd 8bc8            mov     ecx,eax
0:006> be *
0:006> g
Breakpoint 1 hit
eax=00fef800 ebx=020f01e8 ecx=01ecfa80 edx=020f2878 esi=00000000 edi=77bd8ef2
eip=67119464 esp=00fef7a0 ebp=00fef7ac iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!CMethUtil::ScStoragePathFromUrl+0x13:
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

中断到上层函数,看看这次的参数

0:006> dds esp L3
00fef7a0  680312c0 rsaenh!g_pfnFree+0x4
00fef7a4  00fef800
00fef7a8  00000000

经过前面的调试,已经知道地址0x680312c0肯定会作为目标地址被拷贝数据,那么就,围观一下这段内存空间

0:006> !address 680312c0
    68000000 : 68031000 - 00001000
                    Type     01000000 MEM_IMAGE
                    Protect  00000040 PAGE_EXECUTE_READWRITE
                    State    00001000 MEM_COMMIT
                    Usage    RegionUsageImage
                    FullPath C:\WINDOWS\system32\rsaenh.dll

这就是初初调试时感到美妙的地方,0x680312c0这个值是哪里冒出来的?这可是别人的模块

查看上下文环境

6711945e ff7510          push    dword ptr [ebp+10h]
67119461 ff750c          push    dword ptr [ebp+0Ch]
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

0:006> dd ebp+0Ch L1
00fef7b8  680312c0

那么地址0x00fef7b8的数据0x680312c0又从哪里来的呢?

重新运行样本,对地址0x00fef7b8下个写断点

0:006> ba w4 00fef7b8

留意地址0x00fef7b8处数据的值,执行到这里时出现我们寻找的值

0:006> g
Breakpoint 3 hit
eax=020f003c ebx=020f01e8 ecx=00000000 edx=00000026 esi=020f0710 edi=680312c0
eip=671254e0 esp=00fef7b8 ebp=00fefc34 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!HrCheckIfHeader+0x1ba:
671254e0 56              push    esi
0:006> dd 00fef7b8 L1
00fef7b8  680312c0

查看上下文环境

671254b1 8bbdd8fcffff    mov     edi,dword ptr [ebp-328h]
671254b7 8d8ddcfcffff    lea     ecx,[ebp-324h]
671254bd c645fc01        mov     byte ptr [ebp-4],1
671254c1 e8000affff      call    httpext!CStackBuffer<unsigned short,260>::release (67115ec6)
671254c6 83a5c4fbffff00  and     dword ptr [ebp-43Ch],0
671254cd 6a02            push    2
671254cf e9a8000000      jmp     httpext!HrCheckIfHeader+0x256 (6712557c)
671254d4 668b06          mov     ax,word ptr [esi]
671254d7 663d3c00        cmp     ax,3Ch
671254db 750c            jne     httpext!HrCheckIfHeader+0x1c3 (671254e9)
671254dd 6a00            push    0
671254df 57              push    edi
671254e0 56              push    esi

edi的值来自[ebp-328h]

0:006> dd ebp-328h L1
00fef90c  680312c0

这就是前面剧透的,拷贝数据时,地址0x00fef90c处的数据由0x00FEF804修改为0x680312C0

取消该写断点,G一下,中断到上层函数,地址0x00fef90c处的数据没有变化

0:006> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 67119464     0001 (0001)  0:**** httpext!CMethUtil::ScStoragePathFromUrl+0x13
 2 e 67126fdb     0001 (0001)  0:**** httpext!ScStoragePathFromUrl+0x360
 3 e 00fef7b8 w 4 0001 (0001)  0:**** 
0:006> bc 3
0:006> g
Breakpoint 1 hit
eax=00fef800 ebx=020f01e8 ecx=01ecfa80 edx=020f2878 esi=00000000 edi=77bd8ef2
eip=67119464 esp=00fef7a0 ebp=00fef7ac iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!CMethUtil::ScStoragePathFromUrl+0x13:
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)
0:006> dd 0x00fef90c L1
00fef90c  680312c0
0:006> dd 00fef7b8 L1
00fef7b8  680312c0

如上所述,当前参数如下

0:006> dds esp L3
00fef7a0  680312c0 rsaenh!g_pfnFree+0x4
00fef7a4  00fef800
00fef7a8  00000000

以上整个过程中,弄清了第一次大规模拷贝数据的意义:控制第二次大规模拷贝数据的目的地址

现在分析第二次大规模拷贝,G一下,直接断在第三次rep movsd处

0:006> bl
 0 e 77ea411e     0001 (0001)  0:**** kernel32!WinExec
 1 e 67119464     0001 (0001)  0:**** httpext!CMethUtil::ScStoragePathFromUrl+0x13
 2 e 67126fdb     0001 (0001)  0:**** httpext!ScStoragePathFromUrl+0x360

0:006> g
Breakpoint 2 hit
eax=000005fc ebx=000002fd ecx=0000017f edx=680312c0 esi=020f2898 edi=680312e4
eip=67126fdb esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

是的,目的寄存器edi的值在内存中属于rsaenh.dll模块

查看拷贝的源数据

0:006> du esi L2 * ecx
020f2898  "/bbbbbbb祈慵佃潧歯䡅㙆杵䐳㡱坥婢吵噡楒橓兗㡎奈捕䥱䍤摲㑨"
...(lines have been omitted)...
020f2e58  "L3W9P5POO0F2SMXJNJMJS8KJNKPA>"

拷贝之后的内存数据

0:006> db 680312e4 L4 * 17f
680312e4  2f 00 62 00 62 00 62 00-62 00 62 00 62 00 62 00  /.b.b.b.b.b.b.b.
...(lines have been omitted)...
680313b4  41 59 50 71 36 30 77 57-57 44 61 53 c0 13 03 68  AYPq60wWWDaS...h
680313c4  4f 6e 00 68 4f 6e 00 68-47 42 6a 76 c0 13 03 68  On.hOn.hGBjv...h
680313d4  57 42 74 4f 47 59 34 52-66 4b 42 4b 64 74 6f 78  WBtOGY4RfKBKdtox
680313e4  82 60 01 68 35 51 7a 72-7a 74 47 4d 59 44 57 57  .`.h5QzrztGMYDWW
...(lines have been omitted)...
680318d4  4e 00 4b 00 50 00 41 00-3e 00 00 00              N.K.P.A.>...

现在分析第三次大规模数据拷贝,来到上层函数

0:006> bd *
0:006> p
eax=000005fc ebx=000002fd ecx=00000000 edx=680312c0 esi=020f2e94 edi=680318e0
eip=67126fdd esp=00fef330 ebp=00fef798 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x362:
67126fdd 8bc8            mov     ecx,eax
0:006> be *
0:006> g
Breakpoint 1 hit
eax=00fef9a4 ebx=00fefbe8 ecx=01ecfa80 edx=020f0710 esi=00fefc28 edi=00000104
eip=67119464 esp=00fef944 ebp=00fef950 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
httpext!CMethUtil::ScStoragePathFromUrl+0x13:
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

查看参数

0:006> dds esp L3
00fef944  00fefab4
00fef948  00fef9a4
00fef94c  00000000

G一下,断在第三次rep movsd处

0:006> g
Breakpoint 2 hit
eax=00000130 ebx=00000097 ecx=0000004c edx=00fefab4 esi=020f0730 edi=00fefad8
eip=67126fdb esp=00fef4d4 ebp=00fef93c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

查看源数据,和第一次大规模拷贝的数据相同

0:006> du esi L2 * ecx
020f0730  "/aaaaaaa潨硣睡焳椶䝲稹䭷佰畓穏䡨噣浔桅㥓偬啧杣.䘰硅楒吱"
...(lines have been omitted)...
020f0830  "Ꮐ栃䠴攱潃湦瑁䍬Ꮐ栃千橁灒.塦䉌灋捆关祁穐䩬>"

拷贝之后的内存数据

0:006> db 00fefad8 L4 * 4c
00fefad8  2f 00 61 00 61 00 61 00-61 00 61 00 61 00 61 00  /.a.a.a.a.a.a.a.
00fefae8  68 6f 63 78 61 77 33 71-36 69 72 47 39 7a 77 4b  hocxaw3q6irG9zwK
...(lines have been omitted)...
00fefbe8  c0 13 03 68 43 53 41 6a-52 70 30 33 66 58 4c 42  ...hCSAjRp03fXLB
00fefbf8  4b 70 46 63 73 51 41 79-50 7a 6c 4a 3e 00 00 00  KpFcsQAyPzlJ>...

这次大规模拷贝的数据,连上第一次rep movsd,是从地址0x00fefab4开始的

G一下,再次来到上层函数

0:006> g
Breakpoint 1 hit
eax=00fef9a4 ebx=00fefbe8 ecx=680313c0 edx=020f2878 esi=00fefc28 edi=00000104
eip=67119464 esp=00fef944 ebp=00fef950 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
httpext!CMethUtil::ScStoragePathFromUrl+0x13:
67119464 e812d80000      call    httpext!ScStoragePathFromUrl (67126c7b)

查看参数

0:006> dds esp L3
00fef944  00fefab4
00fef948  00fef9a4
00fef94c  00000000

此次的参数跟上一次参数是相同的,上一次已经向地址0x00fefab4拷贝了数据,经过调试,现在没有大规模数据拷贝了,跟进httpext!ScStoragePathFromUrl函数

单步来到地址0x67126cc4处,继续单步步入

67126cc4 e80cc90000      call    httpext!ScStripAndCheckHttpPrefix (671335d5)

httpext!ScStoragePathFromUrl函数中,关键代码如下

httpext!ScStripAndCheckHttpPrefix:
671335d5 8bff            mov     edi,edi
671335d7 55              push    ebp
671335d8 8bec            mov     ebp,esp
671335da 83ec0c          sub     esp,0Ch
671335dd 8365f800        and     dword ptr [ebp-8],0
671335e1 53              push    ebx
671335e2 56              push    esi
671335e3 8b32            mov     esi,dword ptr [edx]
671335e5 57              push    edi
671335e6 8bf9            mov     edi,ecx
671335e8 8b07            mov     eax,dword ptr [edi]  ds:0023:680313c0=680313c0
671335ea 8d4dfc          lea     ecx,[ebp-4]
671335ed 51              push    ecx
671335ee 8bcf            mov     ecx,edi
671335f0 8955f4          mov     dword ptr [ebp-0Ch],edx
671335f3 ff5024          call    dword ptr [eax+24h]

单步到地址0x671335e8处

0:006> t
eax=00fef9a4 ebx=00fefbe8 ecx=680313c0 edx=00fef4f8 esi=020f2878 edi=680313c0
eip=671335e8 esp=00fef4b8 ebp=00fef4d0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x13:
671335e8 8b07            mov     eax,dword ptr [edi]  ds:0023:680313c0=680313c0

很明显ecx是this指针,ecx给到edi,edi取内容给eax,那么eax此时是虚表指针

继续单步

0:006> t
eax=680313c0 ebx=00fefbe8 ecx=680313c0 edx=00fef4f8 esi=020f2878 edi=680313c0
eip=671335f3 esp=00fef4b4 ebp=00fef4d0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3 ff5024          call    dword ptr [eax+24h]  ds:0023:680313e4=68016082

调用虚函数,进入第二次大规模布置数据的内存中

继续单步步入,首先是换栈操作

68016082 8be1            mov     esp,ecx
68016084 8b08            mov     ecx,dword ptr [eax]
68016086 8b4004          mov     eax,dword ptr [eax+4]
68016089 50              push    eax
6801608a c3              ret

经过ROP链和解密shellcode后,执行到

680315fa ffe0            jmp     eax {kernel32!WinExec (77ea411e)}

查看命令行参数

0:006> db poi(esp + 4) L9
68031633  63 61 6c 63 2e 65 78 65-00                       calc.exe.

运行起来,如图所示,产生calc.exe进程(为了方便调试,前文已经提过,加载w3wp.exe之前运行一次样本已经存在一个calc.exe进程)

该结束了,可是好像只用到了前两次大规模的数据,那么第三次拷贝的意义在哪里呢?

其实第三次拷贝数据之后,调用CMethUtil::ScStoragePathFromUrl之前,来到CParseLockTokenHeader::HrGetLockIdForPath函数

以下几句代码就是ecx的值的来源

6712571a 8b9dc4fdffff    mov     ebx,dword ptr [ebp-23Ch]
67125720 8b0b            mov     ecx,dword ptr [ebx]
67125722 c1e803          shr     eax,3
67125725 8985d4fdffff    mov     dword ptr [ebp-22Ch],eax
6712572b 8d85d4fdffff    lea     eax,[ebp-22Ch]
67125731 50              push    eax
67125732 ff75ec          push    dword ptr [ebp-14h]
67125735 ffb5e0feffff    push    dword ptr [ebp-120h]
6712573b e8113dffff      call    httpext!CMethUtil::ScStoragePathFromUrl (67119451)

单步围观

0:006> p
eax=00000412 ebx=00000000 ecx=00fef9a4 edx=000002fe esi=00fefc28 edi=00000104
eip=6712571a esp=00fef964 ebp=00fefbd0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!CParseLockTokenHeader::HrGetLockIdForPath+0xf3:
6712571a 8b9dc4fdffff    mov     ebx,dword ptr [ebp-23Ch] ss:0023:00fef994=00fefbe8
0:006> p
eax=00000412 ebx=00fefbe8 ecx=00fef9a4 edx=000002fe esi=00fefc28 edi=00000104
eip=67125720 esp=00fef964 ebp=00fefbd0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
httpext!CParseLockTokenHeader::HrGetLockIdForPath+0xf9:
67125720 8b0b            mov     ecx,dword ptr [ebx]  ds:0023:00fefbe8=680313c0

看见了,内存地址0x00fefbe8在第三次大规模数据拷贝的地址范围,其内容为后续调用用到的this指针

0x4 总结 & 致谢

该漏洞的成因是没有对输入数据进行有效的长度检查造成溢出。样本通过三次精妙的数据拷贝稳定利用该漏洞。第一次拷贝的目的是控制第二次拷贝的数据位置,将第二次拷贝的数据布置到一个可读可写可执行的模块空间中,第二次拷贝向该可控空间中写入ROP链和Shellcode,第三次拷贝的目的是修改this指针、虚表指针以及虚表的值,使得样本执行成功劫持虚函数

第一次发帖,虽然行文烦琐,仍然在此感谢武汉科锐的钱老师带我走进逆向大门一窥二进制的精彩世界。钱老师认真的治学态度、丰富的逆向经验以及对待生活的热情给人许多启发和帮助、受益匪浅

0x5 参考资料

[1] https://github.com/edwardz246003/IIS_exploit

[2] https://ht-sec.org/cve-2017-7269-vulnerabilities/

     更正作者一处笔误:

     原文中: "PoC 绕过栈返回地址保护的方法就是修改 IEcb 对象结构地址到 0x680312C0"

     应该是:0x680313C0

[3] http://bbs.pediy.com/thread-216809.htm

     更正作者一处笔误:

     原文将内存地址0x680312c0描述为堆地址,不是特别恰当,如上文调试中显示,这个地址属于rsaenh模块


[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  CCkicker   +1.00 2017/05/08
最新回复 (4)
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
狂奔的鸡骨架 2017-4-11 17:16
2
0
俺觉得你好厉害
雪    币: 141
活跃值: (844)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaozuzhi 2017-4-11 17:41
3
0
俺也觉得你好厉害
雪    币: 1217
活跃值: (566)
能力值: (RANK:30 )
在线值:
发帖
回帖
粉丝
webappsec 2017-4-12 17:07
4
0
俺也觉得你好厉害
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
雪扬 2017-4-13 22:57
5
0
这书真的是没白读啊,好强大,好优秀,必须点赞。
游客
登录 | 注册 方可回帖
返回