summaryrefslogtreecommitdiffstats
path: root/scripts/ms-sql-ntlm-info.nse
blob: 6ff3db5a6ec1d01e4a30d067fed47d934323147d (plain)
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
local os = require "os"
local datetime = require "datetime"
local mssql = require "mssql"
local stdnse = require "stdnse"
local smbauth = require "smbauth"
local string = require "string"


description = [[
This script enumerates information from remote Microsoft SQL services with NTLM
authentication enabled.

Sending a MS-TDS NTLM authentication request with an invalid domain and 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 1433 --script ms-sql-ntlm-info <target>
--
-- @output
-- 1433/tcp   open     ms-sql-s
-- | ms-sql-ntlm-info:
-- |   Target_Name: ACTIVESQL
-- |   NetBIOS_Domain_Name: ACTIVESQL
-- |   NetBIOS_Computer_Name: DB-TEST2
-- |   DNS_Domain_Name: somedomain.com
-- |   DNS_Computer_Name: db-test2.somedomain.com
-- |   DNS_Tree_Name: somedomain.com
-- |_  Product_Version: 6.1.7601
--
--@xmloutput
-- <elem key="Target_Name">ACTIVESQL</elem>
-- <elem key="NetBIOS_Domain_Name">ACTIVESQL</elem>
-- <elem key="NetBIOS_Computer_Name">DB-TEST2</elem>
-- <elem key="DNS_Domain_Name">somedomain.com</elem>
-- <elem key="DNS_Computer_Name">db-test2.somedomain.com</elem>
-- <elem key="DNS_Tree_Name">somedomain.com</elem>
-- <elem key="Product_Version">6.1.7601</elem>


author = "Justin Cacak"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}

dependencies = {"broadcast-ms-sql-discover"}

local do_action = function(host, port)

  local output = stdnse.output_table()

  local tdsstream = mssql.TDSStream:new()
  local status, result = tdsstream:Connect(host, port)
  if not status then
    return nil
  end

  local lp = mssql.LoginPacket:new()
  lp:SetUsername("")
  lp:SetPassword("")
  lp:SetDatabase("")
  lp:SetServer(stdnse.get_hostname(host))
  -- Setting domain forces NTLM authentication
  lp:SetDomain(".")

  status, result = tdsstream:Send( lp:ToString() )
  if not status then
    tdsstream:Disconnect()
    return nil
  end

  local status, response, errorDetail = tdsstream:Receive()
  local recvtime = os.time()
  tdsstream:Disconnect()

  local ttype, pos = string.unpack("B", response)
  if ttype ~= mssql.TokenType.NTLMSSP_CHALLENGE then
    return nil
  end

  local data, pos = string.unpack("<s2", response, pos)
  if not string.match(data, "^NTLMSSP") then
    return nil
  end

  -- Leverage smbauth.get_host_info_from_security_blob() for decoding
  local ntlm_decoded = smbauth.get_host_info_from_security_blob(data)

  if ntlm_decoded.timestamp then
    -- 64-bit number of 100ns clicks since 1/1/1601
    local unixstamp = ntlm_decoded.timestamp // 10000000 - 11644473600
    datetime.record_skew(host, unixstamp, recvtime)
  end

  -- 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
    output.Product_Version = string.format("%d.%d.%d",
      ntlm_decoded.os_major_version, ntlm_decoded.os_minor_version, ntlm_decoded.os_build)
  end

  return output

end

local function process_instance(instance)
  return do_action(instance.host, instance.port)
end

action, portrule = mssql.Helper.InitScript(process_instance)