1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
local datetime = require "datetime"
local os = require "os"
local shortport = require "shortport"
local stdnse = require "stdnse"
local smbauth = require "smbauth"
local string = require "string"
local rdp = require "rdp"
description = [[
This script enumerates information from remote RDP services with CredSSP
(NLA) authentication enabled.
Sending an incomplete CredSSP (NTLM) authentication request with null credentials
will cause the remote service to respond with a NTLMSSP message disclosing
information to include NetBIOS, DNS, and OS build version.
]]
---
-- @usage
-- nmap -p 3389 --script rdp-ntlm-info <target>
--
-- @output
-- 3389/tcp open ms-wbt-server syn-ack ttl 128 Microsoft Terminal Services
-- | rdp-ntlm-info:
-- | Target_Name: W2016
-- | NetBIOS_Domain_Name: W2016
-- | NetBIOS_Computer_Name: W16GA-SRV01
-- | DNS_Domain_Name: W2016.lab
-- | DNS_Computer_Name: W16GA-SRV01.W2016.lab
-- | DNS_Tree_Name: W2016.lab
-- | Product_Version: 10.0.14393
-- |_ System_Time: 2019-06-13T10:38:35+00:00
--
--@xmloutput
-- <elem key="Target_Name">W2016</elem>
-- <elem key="NetBIOS_Domain_Name">W2016</elem>
-- <elem key="NetBIOS_Computer_Name">W16GA-SRV01</elem>
-- <elem key="DNS_Domain_Name">W2016.lab</elem>
-- <elem key="DNS_Computer_Name">W16GA-SRV01.W2016.lab</elem>
-- <elem key="DNS_Tree_Name">W2016.lab</elem>
-- <elem key="Product_Version">10.0.14393</elem>
-- <elem key="System_Time">2019-06-13T10:38:35+00:00</elem>
author = "Tom Sellers"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
portrule = shortport.port_or_service(3389, "ms-wbt-server")
action = function(host, port)
local comm = rdp.Comm:new(host, port)
if ( not(comm:connect()) ) then
return nil
end
local requested_protocol = rdp.PROTOCOL_SSL | rdp.PROTOCOL_HYBRID | rdp.PROTOCOL_HYBRID_EX
local cr = rdp.Request.ConnectionRequest:new(requested_protocol)
local status, _ = comm:exch(cr)
if ( not(status) ) then
comm:close()
return
end
-- This script could include code to detect which security protocols the
-- target claims that it accepts however that's less than useful because
-- 1. Windows XP doesn't provide that layer of the packet
-- 2. Even when configured for RDP Security only, Windows Server 2008
-- will still let you connect over TLS and start the CredSSP nego.
local _, response, recvtime
status, _ = comm.socket:reconnect_ssl()
if status then
stdnse.debug1("Sending NTLM NEGOTIATE..")
-- NTLMSSP Negotiate request mimicking a Windows 10 client
local NTLM_NEGOTIATE_BLOB = stdnse.fromhex(
"30 37 A0 03 02 01 60 A1 30 30 2E 30 2C A0 2A 04 28" ..
"4e 54 4c 4d 53 53 50 00" .. -- Identifier - NTLMSSP
"01 00 00 00" .. -- Type: NTLMSSP Negotiate - 01
"B7 82 08 E2 " .. -- Flags (NEGOTIATE_SIGN_ALWAYS | NEGOTIATE_NTLM | NEGOTIATE_SIGN | REQUEST_TARGET | NEGOTIATE_UNICODE)
"00 00 " .. -- DomainNameLen
"00 00" .. -- DomainNameMaxLen
"00 00 00 00" .. -- DomainNameBufferOffset
"00 00 " .. -- WorkstationLen
"00 00" .. -- WorkstationMaxLen
"00 00 00 00" .. -- WorkstationBufferOffset
"0A" .. -- ProductMajorVersion = 10
"00 " .. -- ProductMinorVersion = 0
"63 45 " .. -- ProductBuild = 0x4563 = 17763
"00 00 00" .. -- Reserved
"0F" -- NTLMRevision = 5 = NTLMSSP_REVISION_W2K3
)
-- Not using comm:exch here since that performs some processing on the
-- packet that isn't appropriate in this case.
status, response = comm:send(NTLM_NEGOTIATE_BLOB)
if ( not(status) ) then
return false, response
end
status, response = comm:recv()
if status then
recvtime = os.time()
end
else
comm:close()
stdnse.debug1("Unable to establish a TLS connection which is required to negotiation CredSSP.")
return
end
if response == nil then
return
end
-- Continue only if NTLMSSP response is returned
local start = response:find("NTLMSSP")
if not start then
return nil
end
response = response:sub(start)
local ntlm_decoded = smbauth.get_host_info_from_security_blob(response)
local output = stdnse.output_table()
-- Target Name will always be returned under any implementation
output.Target_Name = ntlm_decoded.target_realm
-- Display information returned & ignore responses with null values
if ntlm_decoded.netbios_domain_name and #ntlm_decoded.netbios_domain_name > 0 then
output.NetBIOS_Domain_Name = ntlm_decoded.netbios_domain_name
end
if ntlm_decoded.netbios_computer_name and #ntlm_decoded.netbios_computer_name > 0 then
output.NetBIOS_Computer_Name = ntlm_decoded.netbios_computer_name
end
if ntlm_decoded.dns_domain_name and #ntlm_decoded.dns_domain_name > 0 then
output.DNS_Domain_Name = ntlm_decoded.dns_domain_name
end
if ntlm_decoded.fqdn and #ntlm_decoded.fqdn > 0 then
output.DNS_Computer_Name = ntlm_decoded.fqdn
end
if ntlm_decoded.dns_forest_name and #ntlm_decoded.dns_forest_name > 0 then
output.DNS_Tree_Name = ntlm_decoded.dns_forest_name
end
if ntlm_decoded.os_major_version then
local product_ver = string.format("%d.%d.%d",
ntlm_decoded.os_major_version, ntlm_decoded.os_minor_version, ntlm_decoded.os_build)
output.Product_Version = product_ver
end
if ntlm_decoded.timestamp and ntlm_decoded.timestamp > 0 then
-- 64-bit number of 100ns clicks since 1/1/1601
local unixstamp = ntlm_decoded.timestamp // 10000000 - 11644473600
datetime.record_skew(host, unixstamp, recvtime)
local sys_time = datetime.format_timestamp( unixstamp, 0)
output.System_Time = sys_time
end
return output
end
|