通过DCERPC和ntlmssp获取Windows远程主机信息

admin 2022年6月29日11:48:34评论1,393 views字数 7814阅读26分2秒阅读模式


免责声明



本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。

只供对已授权的目标使用测试,对未授权目标的测试作者不承担责任,均由使用本人自行承担。


通过DCERPC和ntlmssp获取Windows远程主机信息

文章正文



前言

本文通过利用DCERPC协议的ping,并附加NTLMSSP认证信息来获取获取windows远程主机的版本号,主机名,所在域的域名,DNS等信息。

因为通过rpc进行探测的工具,大部分都是依托impacket来实现,而实战中通过挂代理进行内网探测速率和准确度都比较低,所以最好的方法是将脚本放到目标主机上,来进行内网探测信息收集,所以本文关注的点是想办法脱离impacket,在Socket RAW上的实现,这样能够减小工具的体积,并且其他语言也能够轻松复刻整个过程,便于应用到实战中。

成果

首先看一下成果,通过DCERPC协议的ping附带NTLMSSP来获取到目标的版本号,主机名,域名,DNS等信息。

通过DCERPC和ntlmssp获取Windows远程主机信息

协议介绍-RPC

RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TCP/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。

过程

原理

通过看了一篇网络空间测绘核心技术之:协议识别(DCERPC篇)的文章之后,发现可以通过dcerpc的ping包+ntlmssp,epmapper接口,OXIDResolver接口,无需认证的情况下获取目标主机的版本号、主机名、多块网卡、注册到rpc的程序服务等信息。于是想自己实现一下。

对于通过OXIDResolver接口获取多块网卡的信息,已经有大佬实现了,再次不在赘述,重点是借鉴思路。

如下图所示当带上ntlmssp的时候,响应包,就会附带完整的系统版本号,主机名,域名等信息。

请求包:

通过DCERPC和ntlmssp获取Windows远程主机信息

响应包:

通过DCERPC和ntlmssp获取Windows远程主机信息

通过DCERPC和ntlmssp获取Windows远程主机信息

交互过程分析

正常的方式有两种,第一种看官方文档,下载idl接口文件,从头开始写码,另外一种是分析包的结构,寻找规律,尝试构包。

本文是选择后者。

接下来我们尝试抓流量分析包的情况,通过尝试对两台主机进行发包,看下一下是否有规律。

192.168.8.128-> 192.168.31.13

通过DCERPC和ntlmssp获取Windows远程主机信息

192.168.80.134-> 192.168.31.130

通过DCERPC和ntlmssp获取Windows远程主机信息

可以发现一共有4个数据包,前面是TCP握手不用管,通过分析对比后,可以发现两个请求包是一样,响应包也有一定规律。

通过DCERPC和ntlmssp获取Windows远程主机信息

分析包结构

请求包长度内容固定

第一个数据包 72 bytes(主要用于协商版本等等):

通过DCERPC和ntlmssp获取Windows远程主机信息

 "x05x00x0bx03x10x00x00x00x48x00x00x00x01x00x00x00"  "xb8x10xb8x10x00x00x00x00x01x00x00x00x00x00x01x00"  "x08x83xafxe1x1fx5dxc9x11x91xa4x08x00x2bx14xa0xfa"  "x03x00x00x00x33x05x71x71xbaxbex37x49x83x19xb5xdb"  "xefx9cxccx36x01x00x00x00"

第二个数据包:

这个包中如果包含x33x05x71x71xBAxBEx37x49x83x19xB5xDBxEFx9CxCCx36 则是x64,否则则为x86

 "x05x00x0cx03x10x00x00x00x3cx00x00x00x01x00x00x00"  "xb8x10xb8x10x41x1ax00x00x04x00x31x33x35x00x00x00"  "x01x00x00x00x00x00x00x00x33x05x71x71xbaxbex37x49"  "x83x19xb5xdbxefx9cxccx36x01x00x00x00"

第三个数据包:

这个数据包中带着ntlmssp

通过DCERPC和ntlmssp获取Windows远程主机信息

"x05x00x0bx03x10x00x00x00x78x00x28x00x03x00x00x00"  "xb8x10xb8x10x00x00x00x00x01x00x00x00x01x00x01x00"  "xa0x01x00x00x00x00x00x00xc0x00x00x00x00x00x00x46"  "x00x00x00x00x04x5dx88x8axebx1cxc9x11x9fxe8x08x00"  "x2bx10x48x60x02x00x00x00x0ax02x00x00x00x00x00x00"  "x4ex54x4cx4dx53x53x50x00x01x00x00x00x07x82x08xa2"  "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00"  "x06x01xb1x1dx00x00x00x0f"


第四个数据包:

可以看到附带操作系统版本信息,主机名,域名,DNS域名,DNS主机名等信息。

通过DCERPC和ntlmssp获取Windows远程主机信息

"x05x00x0cx03x10x00x00x00x26x01xe2x00x03x00x00x00"  "xb8x10xb8x10x42x1ax00x00x04x00x31x33x35x00x00x00"  "x01x00x00x00x00x00x00x00x04x5dx88x8axebx1cxc9x11"  "x9fxe8x08x00x2bx10x48x60x02x00x00x00x0ax02x00x00"  "x00x00x00x00x4ex54x4cx4dx53x53x50x00x02x00x00x00"  "x06x00x06x00x38x00x00x00x05x82x89xa2x15x71x1ex72"  "x12x1ax14x3dx00x00x00x00x00x00x00x00xa4x00xa4x00"  "x3ex00x00x00x0ax00x61x4ax00x00x00x0fx45x00x53x00"  "x47x00x02x00x06x00x45x00x53x00x47x00x01x00x18x00"  "x41x00x30x00x32x00x33x00x35x00x31x00x38x00x2dx00"  "x4ex00x43x00x30x00x31x00x04x00x18x00x45x00x53x00"  "x47x00x2ex00x33x00x36x00x30x00x45x00x53x00x2ex00"  "x43x00x4ex00x03x00x32x00x41x00x30x00x32x00x33x00"  "x35x00x31x00x38x00x2dx00x4ex00x43x00x30x00x31x00"  "x2ex00x45x00x53x00x47x00x2ex00x33x00x36x00x30x00"  "x45x00x53x00x2ex00x43x00x4ex00x05x00x18x00x45x00"  "x53x00x47x00x2ex00x33x00x36x00x30x00x45x00x53x00"  "x2ex00x43x00x4ex00x07x00x08x00xa8xb3x8fxb4xaax71"  "xd8x01x00x00x00x00"

【腾讯云】年中优惠抢先看,预热专享618元早鸟券一键领取

https://curl.qcloud.com/wG11oMXe

通过DCERPC和ntlmssp获取Windows远程主机信息


数据包结构解析

第四个数据包是不定长的,包括目标操作系统版本信息,主机名,域名,DNS域名,DNS主机名等信息。

通过DCERPC和ntlmssp获取Windows远程主机信息

规律:

从54位开始是dcerpc结构的内容

通过DCERPC和ntlmssp获取Windows远程主机信息

我们需要的内容在Auth Info:NTLMSSP,Connect AuthContextID(0) 或者说NTLM Secure Service Provider 下面。

通过DCERPC和ntlmssp获取Windows远程主机信息

即整体包的偏移122(0x70+0x0a)开始获取所需内容。

通过DCERPC和ntlmssp获取Windows远程主机信息

NTLM Secure Service Provider 的结构

8 bytes:NTLMSSP identifier: NTLMSSP

8 bytes:NTLM Message Type: NTLMSSP_CHALLENGE (0x00000002)

2 bytes:Target Name的Length

2 bytes:Target Name的Maxlen

4 bytes:Target Name的Offset

4 bytes:Negotiate Flags: 0xa2898205, Negotiate 56, Negotiate 128, Negotiate Version, Negotiate Target Info, Negotiate Extended Security, Target Type Domain, Negotiate Always Sign, Negotiate NTLM key, Request Target, Negotiate UNICODE

8 bytes:NTLM Server Challenge: 15711e72121a143d

8 bytes:Reserved: 0000000000000000

2 bytes:Target Info 的Length

2 bytes:Target Info 的Maxlen

4 bytes:Target Info 的Offset

24 bytes:操作系统版本信息

剩下的全是Target Info的数据,属性有:

NetBIOS domain nameNetBIOS computer nameDNS domain nameDNS computer nameDNS tree nameTimestampEnd of list(0x00000000)

每个属性的结构为:

类型2bytes、长度2bytes、值(根据前面的长度)

根据上面的分析,通过socket构包,对回包进行偏移解析,获取所需字段内容,代码如下:

OS_Version_bytes = packet2[int('0xa0', 16) - 54 + 10:int('0xa0', 16) - 54 + 18]Major_Version = int.from_bytes(OS_Version_bytes[0:1], byteorder='little')Minor_Version = int.from_bytes(OS_Version_bytes[1:2], byteorder='little')Build_Number = int.from_bytes(OS_Version_bytes[2:4], byteorder='little')NTLM_Current_Reversion = int.from_bytes(OS_Version_bytes[7:8], byteorder='little')OS_Verison = "Windows Version {0}.{1} Build {2} {3}".format(Major_Version, Minor_Version, Build_Number, digit)Target_Info_Length_bytes = packet2[int('0xa0', 16) - 54 + 2:int('0xa0', 16) - 54 + 4]Target_Info_Length = int.from_bytes(Target_Info_Length_bytes, byteorder='little')Target_Info_bytes = packet2[-Target_Info_Length:-4]  # 最后四个0x00000000

发送第二个包解析代码

def get_osinfo(ip):    global length    osinfo = {        "NetBIOS_domain_name": "",        "DNS_domain_name": "",        "DNS_computer_name": "",        "DNS_tree_name": "",    }    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    try:        sock.settimeout(4)        sock.connect((ip, 135))        buffer_v2 = b"x05x00x0bx03x10x00x00x00x78x00x28x00x03x00x00x00xb8x10xb8x10x00x00x00x00x01x00x00x00x01x00x01x00xa0x01x00x00x00x00x00x00xc0x00x00x00x00x00x00x46x00x00x00x00x04x5dx88x8axebx1cxc9x11x9fxe8x08x00x2bx10x48x60x02x00x00x00x0ax02x00x00x00x00x00x00x4ex54x4cx4dx53x53x50x00x01x00x00x00x07x82x08xa2x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x06x01xb1x1dx00x00x00x0f"           sock.send(buffer_v2)        packet2 = sock.recv(4096)        digit = send_packet(ip)        OS_Version_bytes = packet2[int('0xa0', 16) - 54 + 10:int('0xa0', 16) - 54 + 18]        # print(test(OS_Version_bytes))        Major_Version = int.from_bytes(OS_Version_bytes[0:1], byteorder='little')        Minor_Version = int.from_bytes(OS_Version_bytes[1:2], byteorder='little')        Build_Number = int.from_bytes(OS_Version_bytes[2:4], byteorder='little')        NTLM_Current_Reversion = int.from_bytes(OS_Version_bytes[7:8], byteorder='little')        OS_Verison = "Windows Version {0}.{1} Build {2} {3}".format(Major_Version, Minor_Version, Build_Number, digit)        # print(OS_Verison)
Target_Info_Length_bytes = packet2[int('0xa0', 16) - 54 + 2:int('0xa0', 16) - 54 + 4] Target_Info_Length = int.from_bytes(Target_Info_Length_bytes, byteorder='little') Target_Info_bytes = packet2[-Target_Info_Length:-4] # 最后四个0x00000000 print("[*] " + ip) print("t[->]", "OS_Verison :", OS_Verison) for k in osinfo.keys(): osinfo[k] = attribute_name(Target_Info_bytes) print("t[->]", k, ":", osinfo[k]) # print(attribute_name(Target_Info_bytes)) length = 0 osinfo["OS_Verison"] = OS_Verison result = {ip: osinfo} # print(result) return osinfo except Exception as e: # print(e) return -1 finally: sock.close()

def attribute_name(Target_Info_bytes): global length att_name_length = int.from_bytes(Target_Info_bytes[length + 2:length + 4], byteorder='little') att_name = Target_Info_bytes[length + 4:length + 4 + att_name_length].replace(b"x00", b"").decode( encoding="unicode_escape") length = length + 4 + att_name_length return att_name

上面也说了要通过第一个包判断目标操作系统的架构,代码如下:

 def send_packet(ip):     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     try:         sock.settimeout(4)         sock.connect((ip, 135))         buffer_v1 = b"x05x00x0bx03x10x00x00x00x48x00x00x00x01x00x00x00xb8x10xb8x10x00x00x00x00x01x00x00x00x00x00x01x00x08x83xafxe1x1fx5dxc9x11x91xa4x08x00x2bx14xa0xfax03x00x00x00x33x05x71x71xbaxbex37x49x83x19xb5xdbxefx9cxccx36x01x00x00x00"         sock.send(buffer_v1)         packet1 = sock.recv(1024)         digit = "x86"         if b"x33x05x71x71xBAxBEx37x49x83x19xB5xDBxEFx9CxCCx36" in packet1:             digit = "x64"         return digit     except Exception as e:         # print(e)         return -1     finally:         sock.close()

注意:经过测试发送两个数据包不能在一个socket会话里面,否则第二个包的响应会不正常,要建立两个会话进行发送。

写成脚本

根据上面的分析,写成了多线程的脚本, 多线程实现扫描效果如下:

通过DCERPC和ntlmssp获取Windows远程主机信息


通过DCERPC和ntlmssp获取Windows远程主机信息

域内主机的话会显示域名,主机名,操作系统版本架构等信息,工作组主机则信息都是自己的主机名。

最后脚本放在了github:https://github.com/komomon/Dcerpc_Find_OSInfo

文章首发于:https://www.freebuf.com/articles/system/334948.html




通过DCERPC和ntlmssp获取Windows远程主机信息

技术交流





交流群



关注公众号回复“加群”,添加Z2OBot 小K自动拉你加入Z2O安全攻防交流群分享更多好东西。

通过DCERPC和ntlmssp获取Windows远程主机信息




知识星球



星球不定时更新最新漏洞复现,手把手教你,同时不定时更新POC、内外网渗透测试骚操作。涉及方向包括Web渗透、免杀绕过、内网攻防、代码审计、应急响应、云安全等

通过DCERPC和ntlmssp获取Windows远程主机信息

通过DCERPC和ntlmssp获取Windows远程主机信息

通过DCERPC和ntlmssp获取Windows远程主机信息


通过DCERPC和ntlmssp获取Windows远程主机信息


往期文章:





Postgresql 渗透总结
一篇文章让你拿下用友nc
一篇文章带你学会容器逃逸
PHP代码审计系列(一) 基础:方法、思路、流程
spring cloud function spel表达式注入RCE复现
利用burp精准定位攻击者
从此 Typora 代码块有了颜色
不会写免杀也能轻松过defender上线CS


通过DCERPC和ntlmssp获取Windows远程主机信息

点一下爱心再走吧!

原文始发于微信公众号(Z2O安全攻防):通过DCERPC和ntlmssp获取Windows远程主机信息

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月29日11:48:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   通过DCERPC和ntlmssp获取Windows远程主机信息https://cn-sec.com/archives/1137810.html

发表评论

匿名网友 填写信息