作者:uncle2

文章目录(红字标识为下篇内容)

一、前言:操作系统指纹识别与SMB协议
二、各大知名产品或项目如何做SMB OS探测

  1. Nmap
  2. Zoomeye
  3. Goby
  4. Fofa
  5. Censys
  6. Shodan
  7. Quake
  8. Metasploit
  9. 综述

三、应该如何做SMB OS指纹探测
四、后话

各大知名产品或项目如何做SMB OS探测
5. Censys
https://search.censys.io/
还是以Shodan的结果作比较来看看Censys的SMB探测结果。
Shodan的解析banner如下图:
image-1661840506952
从Shodan的探测结果可以看到,该目标支持SMBv1,且Shodan从目标得到的包含操作系统详细版本的响应。且目标操作系统版本为 Windows Server 2016 Standard Evaluation 14393。
Censys的结果如下:
image-1661840518227
从 services.smb.smbv1_support False 可以推测,Censys在进行SMB OS探测时,应该首先会同目标进行SMB版本协商,当server响应偏好版本为v2时,便使用v2版本进行通信,并把对方标记为不支持v1,这里是存在误报的。因为偏好版本为v2并不能说明不支持v1,而与v2版本不同,v1版本的某种探测请求(Shodan的)可以从server中直接获取操作系统版本的明文字符串。
从 services.transport_fingerprint.os Windows 2008 R2 / 2012 可以看到,在SMB解析结果中Censys错误的标记了操作系统版本,操作系统版本为 Windows Server 2016 Standard Evaluation 14393。回想一下Zoomeye的探测结果,我们可以推测Censys也是通过nmap 的 -sV 选项来进行SMB OS探测的。

通过我们自己的Windows Server 2016进行测试,我们发现Nmap的-sV选项确实会将其错误标识为 Microsoft Windows Server 2008 R2 - 2012 microsoft-ds。
6. Shodan
https://www.shodan.io/
(1) SMBv2
Shodan的banner有经过解析,其中SMBv1的结果在上面的例子中已经给出,再看一下v2版本结果:
image-1661840544330
可以看到,Shodan对v2结果解析出的内容就少了很多,甚至漏掉了很多关键信息,比如 Goby/Fofa 的结果中有包含的关键的 ntlmssp.version。
(2) SMBv1
再来看看另一个v1版本的例子:
image-1661840564075
可以看到,Shodan使用匿名账号进行了认证,若认证通过会读取共享目录。到这里Shodan的整个SMB v1探测逻辑就已经清晰了。分析其解析的banner字段,我们没有确定Shodan是使用哪种SMB客户端或者库实现的,所以推测是其自研的。如下字段值得一提:
OS:对应 #8 微软官方的SMB协议文档

(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/f210069c-7086-4dc2-885e-861d837df688) 中定义的 NativeOS 字段,Nmap中的 smb.native_os 字段。

丨官方解释为 A string that represents the native operating system of the SMB client.
丨通过之前Goby小节的讨论,我们发现当扫描对象用它来识别操作系统并不是很可靠。尤其是当该字段显示的是Windows nt内核版本如Windows 6.1,而非发行版本edision如Windows Server 2016 Datacenter 14393的时候,需要特别注意,这时候需要通过官方定义的NativeLanMan字段的值来确认操作系统版本。
Software:对应 SMB协议文档中的 NativeLanMan 字段,Nmap中的 smb.native_lanman
丨官方解释为 A string that represents the native LAN manager type of the client
丨通过之前Goby小节的讨论,我们用过首先使用该字段值来确定操作系统
实际操作系统 Windows Server 2016
丨Native OS: Windows Server 2016 Datacenter 14393
丨Native LAN Manager: Windows Server 2016 Datacenter 6.3
实际操作系统 Ubuntu
丨Native OS: Windows 6.1
丨Native LAN Manager: Samba 4.3.11-Ubuntu
(3) 读取共享目录
上面提到Shodan在进行SMBv1探测时,会使用匿名账号进行了认证,若认证通过会读取共享目录,这应该是其自研的扫描方式。
我们可以通过Nmap的nse插件 nmap/scripts/smb-enum-shares.nse (https://github.com/nmap/nmap/blob/master/scripts/smb-enum-shares.nse) 来扫描共享目标。
使用方式如下:
image-1661840592260
Nmap会对每个nse进行分类,以标记该脚本的功能、类型及危险程度。该分类可以在nse的源码中查看到。如下为目前用到的2个nse脚本的分类:
smb-enum-shares.nse: categories = {“discovery”,“intrusive”}
smb-os-discovery.nse: categories = {“default”, “discovery”, “safe”}
可以看到 smb-os-discovery.nse 被标记为 safe,而 smb-enum-shares.nse 被标记为 intrusive,说明后者具有入侵性质,可能触发如入侵检测之类的安全系统告警或者在server端留下告警日志。
因此在利用SMBv1 进行OS时探测时,附带扫描共享目录方式较为激进,在实现自己SMB OS扫描的时候,大家需要根据业务场景选择是否进行这种扫描。具体到我们自己的项目为例,我们认为这一步应该放在在漏洞扫描阶段进行,因此在资产探测选择不进行这种扫描。

  1. Quake
    https://quake.360.cn/quake/#/index
    和Fofa一样,Quake许多操作系统指纹的已有规则,如下图是指纹 app:“windows_server_2016” 的检索结果:
    image-1661840617297
    对SMBv1的banner进行了解析,不过好像有点眼熟,没错,跟Shodan的一模一样,且数据日期为 2021-04-13,并非最新。有两种可能:
    Shodan的SMBv1探测方式并非自研,而是使用了某个SMB client或者库,而Quake也使用了同样的方式
    Quake以前的部分SMB数据源自Shodan
    当使用 port:445 搜索,结果如下:
    image-1661840632120
    数据非常新,但解析的banner的字段跟上面的完全不同,应该是后来换了新扫描方式,关于上面两种推断大家心里应该有自己的结论了。此外,Quake也进行了共享目录读取。
    其中的 ServerOS: Windows 6.1 Build 0 应该与 Goby类似,是SMBv2中的 ntlmssp.version。目前看来SMBv2探测,Quake算是做得比较好的一家。
    Quake新的扫描方式,也对SMBv1版本进行了探测,如下图:
    image-1661840646835
    而v1版本的结果跟v2不同,并没有类似于 ServerOS: Windows 6.1 Build 0 的解析结果。
    此外,对结果中某些banner被解析为ServerDefaultDialect: SMB 3.0 或 ServerDefaultDialect: SMB 2.002 的IP的确认,我们发现Quake和Censys一样,使用的是与server协商的server偏好的SMB版本进行探测,而未尝试v1版本的探测,这与Shodan相比,会漏掉不少可以准确获取server操作系统明文字符串的机会。

  2. Metasploit
    https://github.com/rapid7/metasploit-framework/
    MSF的SMB OS识别需要使用module auxiliary/scanner/smb/smb_version
    在测试之初我们注意到SMBv1 OS探测做的最好的是Shodan,但当时其探测方式尚不清楚。在对MSF的SMBv1探测进行研究后我们惊喜地发现,它能与Shodan达到相同的效果。
    MSF进行探测的一些输出如下:
    image-1661840668580
    image-1661840674510
    image-1661840679464
    而在对仅支持SMBv2的目标进行探测时,它会输出接近于Quake的比较全面的解析结果,不过可惜的是唯独少了重要的 ntlmssp.version。
    image-1661840689893
    MSF对支持SMBv1的主机进行探测的数据包如下图:
    image-1661840699365
    其中最值得我们研究的就是它如何进行SMBv1探测的,答案就是使用SMBv1发送 Session Setup AndX Request, NTLMSSP_NEGOTIATE 这种请求。
    从抓包看,MSF也扫描了共享目录。

  3. 综述
    在SMBv2探测中,Goby、Shodan、Quake、Censys、MSF发送的都是 NTLMSSP 请求,主要差异在于对响应banner的解析的详细程度及重要字段的取舍。
    各大厂商/产品差别最大的就是对SMBv1的探测方式上,MSF、Shodan能完善地探测SMBv1,Censys和Zoomeye通过Nmap的-sV选项可以对v1进行探测,但该选项未发送可以获取操作系统版本的请求包。Quake自研的v1探测结果中虽然某些包含操作系统信息,但某些支持SMBv1的目标并未探测出来。
    SMB协议确实很繁杂,一位外国兄弟在文章 #7 SMB version detection in masscan
    (https://blog.erratasec.com/2018/06/smb-version-detection-in-masscan.html) 中就吐槽 “SMB is a nasty protocol”,其官方文档相当冗长,包含如下3个:
    #8 微软官方的SMB协议文档
    (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/f210069c-7086-4dc2-885e-861d837df688)
    #9 微软官方的CIFS协议文档
    (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/d416ff7c-c536-406e-a951-4f04b2fd1d2b)
    #10 微软官方的SMB2协议文档
    (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5606ad47-5ee0-437a-817e-70c366052962)
    这位外国兄弟还指出MSF的公司rapid7也并非从一开始就正确识别了SMBv1
    “This seems to be a problem with Rapid7’s “National Exposure Index” which tracks SMB exposure (amongst other things). It’s missing about 300,000 machines that report NT_STATUS_ACCESS_DENIED from smbclient rather than the numeric version info from NTLMSSP authentication.”
    Rapid7在其2018年的 “National Exposure Index” 报告中漏掉了接近30万条SMB探测结果,就是因为没有采用NTLMSSP的SMBv1请求。
    而从 auxiliary/scanner/smb/smb_version 的 commit记录 看,近几年 Rapid7 也一直在对其进行改进。
    应该如何做SMB OS指纹探测
    在学习了各大产品或项目的SMB OS探测方法后,我们总结了如何较完善地进行SMB OS探测:

  • 对于SMBv1和SMBv2,都需要发送 Session Setup Request, NTLMSSP_NEGOTIATE 请求。
  • 特别是对于SMBv1,若发送 Session Setup AndX Request 而非 NTLMSSP_NEGOTIATE 请求,某些高版本的Windows Server(>2012?)不会响应包含操作系统明文字符串的数据包。
  • 对于SMBv1,会得到包含Server操作系统版本的明文字符串 NativeOS 和 NativeLanMan 的响应。应该首先尝试使用 NativeLanMan 而非 NativeOS 作为操作系统信息,这是为了兼容某些Linux/Unix系统的探测结果。否则可能将Linux误认为是Windows。
  • 对于SMBv2,响应中不包含操作系统版本的明文字符串,而仅能得到 ntlmssp.version,它标识的是NT内核Build版本。
    ntlmssp.version (内核Build版本)不能用来推断server就是Windows系统
    v2响应中的下列字段(Wireshark)通常包含有server的NetBIOS名称,当其值形如 WIN-218LQHR,DESKTOP-L3F,可以推断目标是Windows主机。或者,我们利用其它端口的banner信息确认目标确是Windows时,这时候就可以通过 ntlmssp.version (内核Build版本)来推断其对应的 Windows Edition的具体版本。
    image-1661840781263
  • 在进行探测时,无论服务端是否支持,都应应该首先尝试SMBv1请求,因为v1版本的响应中可以直接得到操作系统版本的明文字符串。若失败,再尝试发送v2版本的请求。
  • 需要注意的是,不应该使用与server协商得到的server的偏好SMB版本
  • 不论SMBv1还是SMBv2,都应该解析响应,并列出关键字段的值

在总结了上述主要关键点及各大产品或项目的经验以后, 我们写了一个简单的SMB探测程序 https://github.com/MoYunSec/osfp-smb

  • 由于我们使用Python,在写 osfp-smb之前我们试图寻找有没有类似功能的项目,但是没有找到完全满足上述各个关键点的项目

  • 类似项目如下,我们有参考过它们的代码

  • ntlm_challenger

  • smbRecon.py

  • 无论是SMBv1还是SMBv2,osfp-smb 只会发送 Negotiate Protocol Request 和 Session Setup AndX Request, NTLMSSP_NEGOTIATE 2个请求,不会像其他工具一样发送第3个 Session Setup AndX Request, NTLMSSP_AUTH, User: .\ 请求

  • 如果你需要在扫描时发送 包含Session Setup AndX Request, NTLMSSP_AUTH, User: .\ 的全部3个请求,可以直接调用 impacket.smb.SMB.login函数 及 impacket.smb3.SMB3.login函数,这会使整个过程变得简单

  • 我们注意到 Fofa/Goby 在扫描某些主机时,输出了 Primary Domain字段,这是个有用的信息,但是impacket.smb.SMB中对其解析存在问题,导致其被忽略而未被解析,在 osfp-smb 我们以较为偷懒的方式修复了这个问题

  • 由于时间原因我们没有实现通过 137/UDP NBNS获取目标的NetBIOS主机名,然后使用其向 139/TCP 发送SMB请求而探测OS信息的功能。Nmap的 smb-os-discovery.nse 有这个功能(仍然有上述探测包内容的问题),MSF好像也是可以的。这可以用于扫描那些未开放 445/TCP 而开放了 137/UDP和139/TCP的主机。如果你有空,我们期待你的pull request。

扫描数据包如下:
SMBv1
image-1661840955425
SMBv2
image-1661840964491
后话
感谢 白帽汇赵武 在 公众号 赵武的自留地 分享的一系列关于资产及操作系统探测的文章,以及上述各种开源项目及工具,它们帮助我们在做资产探测时走了很多捷径,节省了不少时间。这也是我们决定将 osfp-smb 开源的原因。如果有时间的我们还会继续发布其他关于OS探测的系列文章。希望大家继续多多分享交流。

参考链接
#7 SMB version detection in masscan
(https://blog.erratasec.com/2018/06/smb-version-detection-in-masscan.html)
#8 微软官方的SMB协议文档
(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/f210069c-7086-4dc2-885e-861d837df688)
#9 微软官方的CIFS协议文档
(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/d416ff7c-c536-406e-a951-4f04b2fd1d2b)
#10 微软官方的SMB2协议文档
(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5606ad47-5ee0-437a-817e-70c366052962)