V1me's Blog

Talk is cheap, better to sleep.

0%

CVE-2019-0708 调试记录

环境搭建

准备:

  • Windows 7 Ultimate with Service Pack 1 (x64)
  • Ubuntu 20.04 (with docker)
  • VMWare 16.1.0

环境安装好后,拓扑图如下。(注: 需要在 Windows 7 上手动打开 3389 端口监听远程桌面链接(RDP))

测试被攻击机是否含有漏洞模块。

使用 msf 自带的检测脚本测试,发现被攻击机器可以被攻击。

至此,环境搭建完成。

漏洞定位

根据 CVE-2019-0708 的说明,漏洞文件是 termdd.sys。bindiff 一下发现 patch 打在 IcaBindVirtualChannels 函数中。

漏洞版本逻辑如下:

1
_IcaBindChannel(v3, 5, *(unsigned int *)v2, *(_DWORD *)(v2 + 2));

修复后逻辑如下:

1
2
3
4
v19 = 31;
if (_stricmp(v17 + 268, "MS_T120"))
v19 = *((unsigned __int16*)v6 - 1); // 31
IcaBindChannel(v17, 5, v19, *(unsigned int *)v6);

简而言之,patch 后只能在31通道绑定”MS_T120”通道。因此,原来在任何通道(0~31)都能绑定”MS_T120”大概率就是漏洞点。

调试

在漏洞函数下断点 (Break 1)。

以及在函数 _IcaBindChannel 内,必定有channels_list[32]的操作。所以可以通过在_IcaBindChannels内打断点找到 channels_list 的地址 (Break 2)。Break 2所在的语句将通道结构体基址(rdi)保存在channels_list([rax + rcx*8 + 0xe0])中。

Attach 到 Windows 内核,执行 exp 的send_client_datasend_channel_packets部分。

send_client_data部分抓包如下。

首先断在了 Break 2,寄存器如下。

看到 rsi = 0x1f, rbp = 0x5, rcx = rsi + rbp = 0x24, rdi = 0xfffffa80634f3ab0;

结合后面的调试,rbp = 0x5 是一个”固定偏移量”。也就是说channels_list[32]的基址不是[rax + 0xe0],而是[rax + 0x5*8 + 0xe0], rsi才是真正的 Index。因此,rsi = 0x1f = 31 意味着这是对”MS_T120”通道的绑定操作。”MS_T120”的结构体基址为 0xfffffa80634f3ab0

继续执行,断在了 Break 1,但是 Break 1 没有提供有趣的信息,遂继续。

继续执行,又一次断在了 Break 2。

这次rsi = 0x3, rbp = 0x5, rcx = 0x8, rdi = 0xfffffa80634f3ab0;

也就是说,这次的 index (rsi) 变了,而 rdi 没变。因此,channels_list 中极有可能有两个对”MS_T120”结构的引用。结合漏洞性质是UAF,到了这里基本上漏洞的成因确定了。**”MS_T120”结构体释放的时候,其中一个地址对”MS_T120”结构体的引用解除了,而另一个地址任指向”MS_T120”结构体**,因此如果我们能分配到刚刚”MS_T120”结构体被释放的堆块,就可以进行利用了。下图 channels_list 中, Index 为 3 和 31 的都指向”MS_T120”结构体。

触发漏洞

重新执行exp,包括函数send_client_datasend_channel_packetssend_client_infosend_confirm_activesend_establish_session。发现除了”MS_T120”信道,还创建了几个我们不关心的通道。最后执行send_kill_packet函数,这个函数将 3 号通道关闭,即我们创建的非法的”MS_T120”通道。

关闭通道前的channel_list和”MS_T120”结构:

执行到free函数(下方红框内的 function trace 信息有误,实际上的 trace 链为 IcaDispatch->IcaCloseChannel->IcaDereferenceChannel):

Step over一下。

free之后的”MS_120结构”:

池喷,发送1024个payload包(命中率极低,测试下来不到10%的命中率):

之后系统报SystemError后蓝屏(截图的时候系统崩了,没截上,所以用另一次调试的截图替代….)

剩下的就是写入shellcode并执行。本人Windows基础实在太差,池喷射又及其玄学,而且Windows还管不了内核地址随机化……

所以放弃,直接套用现成的exp……

执行不知道多少遍 exp 后拿到了 Shell ……

欢迎关注我的其它发布渠道