1local smb = require "smb"
2local smb2 = require "smb2"
3local stdnse = require "stdnse"
4local table = require "table"
5local nmap = require "nmap"
6
7description = [[
8Determines the message signing configuration in SMBv2 servers
9 for all supported dialects.
10
11The script sends a SMB2_COM_NEGOTIATE request for each SMB2/SMB3 dialect
12 and parses the security mode field to determine the message signing
13 configuration of the SMB server.
14
15References:
16* https://msdn.microsoft.com/en-us/library/cc246561.aspx
17]]
18
19---
20-- @usage nmap -p 445 --script smb2-security-mode <target>
21-- @usage nmap -p 139 --script smb2-security-mode <target>
22--
23-- @output
24-- | smb2-security-mode:
25-- |   3.11:
26-- |_    Message signing enabled but not required
27--
28-- @xmloutput
29-- <table key="3.11">
30-- <elem>Message signing enabled but not required</elem>
31-- </table>
32---
33
34author = "Paulino Calderon"
35license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
36categories = {"safe", "discovery", "default"}
37
38hostrule = function(host)
39  return smb.get_port(host) ~= nil
40end
41
42action = function(host,port)
43  local status, smbstate, overrides
44  local output = stdnse.output_table()
45  overrides = overrides or {}
46
47  local smb2_dialects = {0x0202, 0x0210, 0x0300, 0x0302, 0x0311}
48
49  for i, dialect in pairs(smb2_dialects) do
50    -- we need a clean connection for each negotiate request
51    status, smbstate = smb.start(host)
52    if(status == false) then
53      return false, smbstate
54    end
55    overrides['Dialects'] = {dialect}
56    status, dialect = smb2.negotiate_v2(smbstate, overrides)
57    if status then
58      local message_signing = {}
59
60      -- Signing configuration. SMBv2 servers support two flags:
61      -- * Message signing enabled
62      -- * Message signing required
63      local signing_enabled, signing_required
64      if smbstate['security_mode'] & 0x01 == 0x01 then
65        signing_enabled = true
66      end
67      if smbstate['security_mode'] & 0x02 == 0x02 then
68        signing_required = true
69      end
70
71      if signing_enabled and signing_required then
72        table.insert(message_signing, "Message signing enabled and required")
73      elseif signing_enabled and not(signing_required) then
74        table.insert(message_signing, "Message signing enabled but not required")
75      elseif not(signing_enabled) and not(signing_required) then
76        table.insert(message_signing, "Message signing is disabled and not required!")
77      elseif not(signing_enabled) and signing_required then
78        table.insert(message_signing, "Message signing is disabled!")
79      end
80      output[stdnse.tohex(dialect[1], {separator = ".", group = 2})] = message_signing
81      -- We exit after first accepted dialect,
82      --  SMB signing configuration appears to be global so
83      --  there is no point of trying other dialects.
84      break
85    end
86
87    smb.stop(smbstate)
88    status = false
89  end
90
91  if #output>0 then
92    return output
93  else
94    stdnse.debug1("No SMB2/SMB3 dialects were accepted.")
95    if nmap.verbosity()>1 then
96      return "Couldn't establish a SMBv2 connection."
97    end
98  end
99end
100