eternalblue
首页
文章
漏洞
SRC导航
内容精选
输入关键词搜索
APP 登录| 注册
【技术分享】EternalBlue Shellcode详细分析
阅读量 56541 | 稿费 400
分享到: QQ空间 新浪微博 微信 QQ facebook twitter
发布时间:2017-07-07 11:01:25
译文声明
本文是翻译文章,文章原作者,文章来源:安全客
原文地址:
译文仅供参考,具体内容表达以及含义原文为准
×
http://p9.qhimg.com/t017f6d54c32efc9e9f.png
译者:Tmda_da
预估稿费:400RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
0x0 前言
说来很惭愧,EnternalBlue 已经出来很久了,最近才开始分析,漏洞原理和环境搭建网上已经烂大街了,因此这篇文章只分析Shellcode,调试平台如下:
windows 7 sp1 en 32 位
Windbg
Eternalblue
Doublepulsar
Wireshark
断点方法是将Shellcode中的31c0修改为CCCC(int 3)后发送,成功断下来后再通过ew(fdff1f1) c031即可。该Shellcode 大致分为三段: 0x1,hook nt! kiFastCallEntry篇; 0x2, 主要功能篇;0x 3, 后门通信篇,下面来逐一进行介绍。
0x1 Hook ntdll! kiFastCallEntry篇
这部分代码功能比较简单, 但还是值得学习:首先是判断系统环境,作者用法比较巧妙,利用了x86和x64系统通过对二进制指令的解析不同来判断系统环境(64位环境没有调试,直接用IDA查看, 如下图。
http://p1.qhimg.com/t01160988cbaa0ba593.png
1.1 x86环境
http://p5.qhimg.com/t01d1728201f91c71ca.png
1.2 x64位环境
可以发现同样一段二进制代码, 在x86环境下eax=1 , x64环境下 eax = 0。 紧接着通过读取MSR的176号寄存器(放着nt! kiFastCallEntry函数地址)(这里还有简单的混淆),将其保存在Shellcode的末尾位置(Shellcode末尾空置了0x1d byte),然后再将第二段Shellcode的地址存放在MSR 176号寄存器中实现对nt! kiFastCallEntry函数的hook。
http://p6.qhimg.com/t014dae63bbc807bd18.png
1.3 简单混淆
http://p8.qhimg.com/t01e0247afd7f9426bb.png
1.4 hook nt!kiFastCallEntry
http://p0.qhimg.com/t011f52741504f8909e.png
1.5 hook前的情况
http://p5.qhimg.com/t01ebda1fed6bf2d670.png
1.6 hook后的情况
为什么要hook kiFastCallEntry?
在Ring3应用程序需要调用ring0函数的时候, 会通过ntdll!kiFastSystemCall 函数,该函数的内容如下:
mov edx, esp
sysenter
ret
Ring3层最终通过 sysenter 调用内核函数 nt!KiFastCallEntry实现空间转换。因此只要存在用户空间需要调用内核函数,都会调用这个函数。
0x2 主要功能篇
首先是获取到上一段Shellcode功能中保存末尾的kiFastCallEntry实际地址,然后写入MSR的176号寄存器中,恢复kiFastCallEntry。
http://p4.qhimg.com/t016ce976557213c172.png
2.1 unhook KiFastCallEntry
接下来获取ntoskrnl.exe 的基地址,fs:[0x38] 指向_KIDTENTRY表结构的开始地址,也指向0号中断,将0号中断的ExtendedOffset 和Offset组合成地址,就是0号中断处理函数地址。而这个函数位于ntoskrnl.exe中,因此该空间在ntoskrnl.exe进程空间中,在这个地址对齐(&0x00F000)处理后只需要每次减0x1000,然后比较前两位的PE(MZ)文件标识,最后一定能找到ntoskrnl.exe的基地址地址。
http://p1.qhimg.com/t01a23d59ce8b1eadfd.png
2.2. 寻找ntoskrnl.exe基地址
http://p1.qhimg.com/t01850bf4c41bc2442d.png
2.3 0号中断结构信息
找到ntoskrnl.exe的基地址后,利用应用层常用的查找函数地址方式查找ntoskrnl.exe导出表中的函数地址(此代码中的所有函数名和文件名都采用了hash处理),分别是
1, ExAllocatePool
2, ExFreePool
3, ZwQuerySystemInformationEx
http://p7.qhimg.com/t01802d41965e91eecb.png
2.4 根据hash 获取函数地址
函数寻找完成后,便是将后门程序hook到SrvTransaction2DispatchTable表中的函数SrvTransactionNotImplemented地址上,至于为什么要挑选这个函数我认为主要有以下三个原因:
1, 不增加无关网络协议连接,直接利用SMB协议进行数据传输(可以达到隐藏流量的目的,估计这也是为什么到公布了利用工具后才发现漏洞的原因)。
2, 通过查看SrvTransaction2DispatchTable表结构,我们有两个函数在这个表中出现了两次以上SrvSmbFsct1(3次)和SrvTransactionNotImplemented (2次),因此这两个函数更有利于hook。
3, 如果hook到SMB协议的常用处理函数, 那么这个函数的调用会比较频繁,那么处理过程就相对要复杂很多。而SrvTransactionNotImplemented的调用时在发送非正常Trans2 Request请求时才会调用,在正常情况下执行到这个函数的概率很小。
作者知道SrvTransaction2DispatchTable位于Srv.sys中的.data节中,所以作者采用了如下3个步骤实现寻找SrvTransaction2DispatchTable地址:
1,通过两次调用ZwQuerySystemInformationEx函数来获取所有内核模块的空间结构信息(_SYSTEM_MODULE_INFORMATION_ENTRY)表(第一次调用ZwQuerySystemInformationEx来获取 内核模块信息大小, 然后利用ExAllocatePool创建内存空间,在第二次调用ZwQuerySystemInformationEx来获取模块信息)。
http://p3.qhimg.com/t01f35dd7e52001db28.png
2.5 获取内核模块信息结构体
2,通过依次对比_SYSTEM_MODULE_INFORMATION_ENTRY中的ImabeName 字符串来查找 srv.sys(此模块是SMB协议的主要模块)
http://p0.qhimg.com/t01462449e624c1e611.png
2.6 查找srv.sys地址空间
3, 找到srv.sys的基地址后通过PE文件结构信息,最终后定位到.data节。
http://p8.qhimg.com/t0130b9fcc09a25616e.png
2.7 定位.data节信息
4,找到.data节后,最后进行内存搜索,根据SrvTransaction2DispatchTable的结构特征(见图2.9):
① 根据观察发现 SrvTransaction2DispatchTable[9], SrvTransaction2DispatchTable[11], SrvTransaction2DispatchTable[12]的值都相同, 都指向srv!SrvSmbFsct1;
②SrvTransaction2DispatchTable 中的函数指针跟SrvTransaction2DispatchTable在同一个地址领空, 因此最高8位的地址应该相同;
③SrvTransaction2DispatchTable[18h] = 0;
根据这三个特征来顺序搜索.data节空间,可以定位到SrvTransaction2DispatchTable的基地址。
http://p8.qhimg.com/t0146b9d5d3852e0118.png
2.8查找SrvTransaction2DispatchTable地址
http://p7.qhimg.com/t011a95ca86c07acd85.png
2.9 SrvTransaction2DispatchTable结构信息
找到SrvTransaction2DispatchTable后开始为hook 后门程序做准备,先重新分配一块0x400大小内存空间bdBuffer,首先将前0x48字节中存放一些地址信息,因此顺序为:
http://p8.qhimg.com/t01b21138ebe12fd502.png
(此处的ebp+4我猜测是作者的一点小失误,应该是 ebp-14h对应函数地址ZwQuerySystemInformationEx,不过对后边后门程序基本没有影响也就无法验证)。
并且将上述几个地址和空间结束地址进行异或后的值存放在bdBuffer+0x24地址处,作为后门程序首次使用时的异或key的引子(后门程序所使用的异或key是通过这个值变换而来)。接下来便将后门程序拷贝到bdBuffer+0x48处,然后将 bdBuffer + 0x48赋值给SrvTransaction2DispatchTable[14]中, 实现hook后退出。
http://p8.qhimg.com/t01ac9553678696a21b.png
2.10 保存函数地址,拷贝后门程序
http://p4.qhimg.com/t015412a8e4301382cd.png
2.11 Hook SrvTransactionNotImplemented前后对比
0x3 后门通信篇
这个模块需要配合Doublepulsar程序,因此就一起分析了下,本文主要分析EternalBlue中的Shellcode,所以就对Doublepulsar的分析此处就不写了,主要配合Wireshark进行分析。
首先是获取空间起始地址获取给ebp,然后获取到已经够造好的SmbBuffer中。
http://p9.qhimg.com/t01aab14274ebd09e59.png
3.1 获取相关信息
在函数85bbd239中,获取最终返回的SMB 返回数据包地址赋值到ebp+0x38。至于这个过程如何得到的,我也没有仔细跟,应该跟SMB协议结构有关系(先将就着用吧)。
http://p7.qhimg.com/t019c5ee61814508348.png
3.2 获取SMB 返回数据包地址
接着是计算解码密钥,计算过程在85bbd1a8中,比较简单 key = (A*2) ^ bswap(A), 然后将结果赋值到ebp+0x28中,具体过程如下:
http://p5.qhimg.com/t01fa8292360d5ced6a.png
3.3 根据解码引子计算解码key
函数85bbd1e9是获取SMB发送数据数据段的相关结构,对SMB数据结构在内存中的表现形式不太了解,我也还没太搞明白。
获取完这些后,接着判断命令类型,计算过程使根据发送的数据包的TimeOut,中的逐字节相加得到:
http://p1.qhimg.com/t010cfa98dccb479969.png
3.4 计算命令类型
http://p3.qhimg.com/t01fea411ac50b2fd7d.png
3.5 抓取的Trans2 Request数据包
判断命令类型,主要有三个命令,0x23 -> 检查后门是否存在, 0x77 –> 卸载后门, 0xC8 执行Shellcode。
http://p2.qhimg.com/t012f00e9fdbe5fb98a.png
3.6 命令类型判断
0x3.1 检查后门是否存在 0x23
当接收到的命令是0x23后,做的事情,将ebp+0x24中存放的密钥引子写入到返回数据包的Signature前4个字节中,将系统位数信息存放在Signature的第5个字节中。如下所示:
http://p0.qhimg.com/t01752f8706ec916c4e.png
3.7 后门检测处理过程
然后将返回数据包的Multiplex ID加0x10后 跳转到真正的SrvTransactionNotImplemented地址继续执行。
执行结果如下(两次结果不一样,是因为不是同一个过程里边抓到的数据包,调试过程中,分析太久SMB就自动退出链接):
http://p4.qhimg.com/t017e699bd787ee19d2.png
3.8 检测后门反馈数据包
0x3.2 卸载后门 0x77
卸载后门的过程也相对较为简单,清空并释放掉以前分配的空间,然后unhook SrvTransactionNotImplemented函数后,设置返回数据包的Multiplex ID +=0x10恢复SrvTransactionNotImplemented的相关条件后退出,由系统在调用一次正常的SrvTransactionNotImplemented即可。
http://p0.qhimg.com/t014cb7e3a2e0757687.png
3.9 卸载后门过程
0x3.3 执行命令 0xc8
此过程主要包括组装数据(Doublepulsar的攻击数据根据大小拆分成一个或多个Trans2 Request数据包)和执行两个功能,主要流程如下:
Step 1, 解密数据包的SESSION_SETUP Parameters参数,获取当前数据的总长度total_len,当前数据包长度current_len和 当前数据包在整个数据包的位置current_pos;
http://p5.qhimg.com/t01a0e7d17fffdb0bb2.png
3.10 计算数据包信息
http://p4.qhimg.com/t01a19da634da565622.png
3.11 数据包信息存放位置
Step 2, total_len 和存放总长度存放位置(ebp+0x30)的值进行比较,如果不相等则说明这是第一个数据包或者是错误数据包都 需要重新开始转到Step 3, 否则转到Step4;
Step 3, 如果内存空间存放处 ebp + 0x2C 不为这将其空间清零后释放,然后在分配一块长度为(total_len + 4)的空间,地址为buffer_addr,如果内存分配失败则跳转到Step 10, 然后将ebp+0x30 的值设置为total_len +4, ebp+0x2c 的值设置为buffer_addr;
http://p9.qhimg.com/t01915acfb68d6548a3.png
3.12 分配存放数据包空间
Step 4, 如果current_pos + current_len >total_len,则表示数据包出错, 跳转到Step 9;
Step 5, 将接收到的数据packet_data 拷贝到 buffer_addr + current_pos处, 然后对这段拷贝的数据解码;
http://p5.qhimg.com/t0182ea73a65ac6ca56.png
3.13 拷贝数据并解码
Step 6, 如果解码完成后的位置pos < buffer_addr+ total_len 则表示数据包没有接收完成,转到Step 8, 否则转到Step 7; Step 7 , 直接执行(call)buffer_addr, 执行完成后, 清除并释放掉buffer_addr,并重新计算密钥引子和解密密钥; http://p6.qhimg.com/t01ea030caa0aae5fcd.png 3.14 执行解码后的数据,重新生成解码引子和解码key Step 8 , 将发送的SMB Reponse 中Multiplex ID + 0x10 (执行成功) ,转到Step 11; Step 9, 将发送的SMB Reponse 中Multiplex ID + 0x20 (非后门需要的数据包),转到Step 11; Step 10, 将发送的SMB Reponse 中Multiplex ID + 0x30 (内存分配失败),转到Step 11; Step 11, 跳到真正的SrvTransactionNotImplemented中执行。 0x4 写在最后 这是小菜第一次内核调试,查了很多资料,学了很多内核相关知识,也学到了EternalBlue作者的一些奇淫技巧。但是还是有很多不清楚的地方,希望各位大牛不吝赐教 0x5 参考文献 【1】NSA Eternalblue SMB 漏洞分析 http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/ 【2】NSA Eternalblue SMB 漏洞分析 http://www.myhack58.com/Article/html/3/62/2017/85358_4.htm 本文翻译自 安全客, 原文链接 。如若转载请注明出处。 安全知识 Tmda_da 分享到: QQ空间 新浪微博 微信 QQ facebook twitter |推荐阅读 U2F安全协议分析 2018-11-24 10:00:48 二十年重回首——CIH病毒源码分析 2018-11-23 15:20:19 Cookie Maker:隐藏在Google Docs中的恶意网络 2018-11-23 14:30:40 情报分析与研判之图片信息挖掘(1) 2018-11-23 10:00:17 |发表评论 发表你的评论吧 昵称 管理员 换一个 |评论列表 还没有评论呢,快去抢个沙发吧~ Tmda_da 这个人太懒了,签名都懒得写一个 文章 1 粉丝 0 TA的文章 【技术分享】EternalBlue Shellcode详细分析 2017-07-07 11:01:25 输入关键字搜索内容 相关文章 360 | 数字货币钱包APP安全威胁概况 以太坊智能合约安全入门了解一下(下) 对恶意勒索软件Samsam多个变种的深入分析 360 | 数字货币钱包安全白皮书 Json Web Token历险记 揪出底层的幽灵:深挖寄生灵Ⅱ 简单五步教你如何绕过安全狗 热门推荐 安全客Logo 安全客 安全客 关于我们 加入我们 联系我们 用户协议 商务合作 合作内容 联系方式 友情链接 内容须知 投稿须知 转载须知 合作单位 安全客 安全客 Copyright © 360网络攻防实验室 All Rights Reserved 京ICP备08010314号-66 Loading...0daybank
文章评论