NSA Eternalblue SMB 漏洞分析

环境

EXPLOIT:
Eternalblue-2.2.0.exe

TARGET:
win7 sp1 32bits
srv.sys 6.1.7601.17514
srvnet.sys 6.1.7601.17514

PATCH:
MS17-010

漏洞原理

srv.sys在处理SrvOs2FeaListSizeToNt的时候逻辑不正确导致越界拷贝。我们首先看下漏洞的触发点:

发生越界的地方见上面第二个memmove。调试的时候可以这样下断点:

这么设断点的原因是最后一次越界的拷贝的长度是0xa8,断下来后可以发现:

我们可以从上面的调试记录看到明显的越写拷贝操作。可以看到被覆盖的是SMB1的buffer是有srvnet.sys分配的。这里exploit精心布局好的,是通过pool喷射的将两个pool连接在一起的。覆盖后面的这个pool有啥用后面会提到。
有同学会说”这只是现象,漏洞真正的成因在哪里呢?”。往下看:

首先SrvOs2FeaListToNt首先调用SrvOs2FeaListSizeToNt计算pNtFea的大小。这里注意了SrvOs2FeaListSizeToNt函数会修改原始的pOs2Fea中的Length大小,本来Length是一个DWORD, 代码还强制转换成了WORD,不能不让人联想一些事。然后以计算出来的Length来分配pNtFea.最后调用SrvOs2FeaToNt来实现转换。SrvOs2FeaToNt后面的判断就有问题了。这里还不止一个问题。

1. 转换完成后,增加pOs2FeaBody然后比较。正确的逻辑难道不应该是先判断再转换吗?
2. 由于SrvOs2FeaListSizeToNt中改变了pOs2Fea的length的值,这里使用变大后的值做比较,肯定会越界。

为了方便同学们调试,我把代码扣出来了。大家可以在环3围观下这段代码。

看到我加了个__debugbreak的地方,断在那里就说明溢出了
dumo.bin的内容为处理最后触发漏洞的数据包。最后我会给大家带上。
大家也可以自己抓demp.bin的内容,方法如下:

漏洞利用

我们先来看pool数据覆盖的情况。

覆盖前

覆盖后

在将下面SrvNet分配的对象覆盖前面的a1字节后。由于被覆盖的pool里面存在用于接收数据的buffer的指针。像上面描述的0x8d1aa034(0xffd0f020)这个地方的指针(我发懒了没有去确定到底是哪一个)。srvnet在接收包的时候就会在固定0xffdff000这个地址存入客户端发送来的数据。
0xffdff0000这个地址是什么?wrk中有定义,如下:

这块内存是系统预留的,里面保存了系统的一些信息,像时钟,版本,配置之类。注意这个地址在win10下是不可以执行的。所以这个利用方法在win10下是不可用的。

覆盖完之后是这样。

0xffdff1f1处为shellcode.最后在接收完成后,最终调到srvnet!SrvNetWskReceiveComplete.在这个函数中会调用最终的shellcode。可以这么下断点:

最终调用到shellcode的调用栈为:

关于补丁

修补前:

修复后:

修补的方法就是将修补*(WORD*)v6 ==> *(DWORD*)v6; 还有就是*(_DWORD *)(v3 + 0x50) >= 1 变成了 *(_DWORD *)(v3 + 0x50) >= 2u 笔者在调试的时候发现触发漏洞的正好是1。

由于作者水平有限,有什么错误欢迎大家指出
联系作者:pgboy1988

dump.bin