| 12
 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
 169
 170
 171
 172
 173
 174
 
 | local msrpc = require "msrpc"
local smb = require "smb"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local tableaux = require "tableaux"
description = [[
Obtains a list of groups from the remote Windows system, as well as a list of the group's users.
This works similarly to <code>enum.exe</code> with the <code>/G</code> switch.
The following MSRPC functions in SAMR are used to find a list of groups and the RIDs of their users. Keep
in mind that MSRPC refers to groups as "Aliases".
* <code>Bind</code>: bind to the SAMR service.
* <code>Connect4</code>: get a connect_handle.
* <code>EnumDomains</code>: get a list of the domains.
* <code>LookupDomain</code>: get the RID of the domains.
* <code>OpenDomain</code>: get a handle for each domain.
* <code>EnumDomainAliases</code>: get the list of groups in the domain.
* <code>OpenAlias</code>: get a handle to each group.
* <code>GetMembersInAlias</code>: get the RIDs of the members in the groups.
* <code>Close</code>: close the alias handle.
* <code>Close</code>: close the domain handle.
* <code>Close</code>: close the connect handle.
Once the RIDs have been termined, the
* <code>Bind</code>: bind to the LSA service.
* <code>OpenPolicy2</code>: get a policy handle.
* <code>LookupSids2</code>: convert SIDs to usernames.
I (Ron Bowes) originally looked into the possibility of using the SAMR function <code>LookupRids2</code>
to convert RIDs to usernames, but the function seemed to return a fault no matter what I tried. Since
enum.exe also switches to LSA to convert RIDs to usernames, I figured they had the same issue and I do
the same thing.
]]
---
-- @usage
-- nmap --script smb-enum-users.nse -p445 <host>
-- sudo nmap -sU -sS --script smb-enum-users.nse -p U:137,T:139 <host>
--
-- @output
-- Host script results:
-- | smb-enum-groups:
-- |   Builtin\Administrators (RID: 544): Administrator, Daniel
-- |   Builtin\Users (RID: 545): <empty>
-- |   Builtin\Guests (RID: 546): Guest
-- |   Builtin\Performance Monitor Users (RID: 558): <empty>
-- |   Builtin\Performance Log Users (RID: 559): Daniel
-- |   Builtin\Distributed COM Users (RID: 562): <empty>
-- |   Builtin\IIS_IUSRS (RID: 568): <empty>
-- |   Builtin\Event Log Readers (RID: 573): <empty>
-- |   azure\HomeUsers (RID: 1000): Administrator, Daniel, HomeGroupUser$
-- |_  azure\HelpLibraryUpdaters (RID: 1003): <empty>
--
-- @xmloutput
-- <table key="Builtin">
--   <table key="RID 544">
--     <table key="member_sids">
--       <elem>S-1-5-21-12345678-1234567890-0987654321-500</elem>
--       <elem>S-1-5-21-12345678-1234567890-0987654321-1001</elem>
--     </table>
--     <elem key="name">Administrators</elem>
--     <table key="members">
--       <elem>Administrator</elem>
--       <elem>Daniel</elem>
--     </table>
--   </table>
--   <table key="RID 545">
--     <table key="member_sids">
--       <elem>S-1-5-4</elem>
--       <elem>S-1-5-11</elem>
--     </table>
--     <elem key="name">Users</elem>
--     <table key="members"></table>
--   </table>
--   <table key="RID 546">
--     <table key="member_sids">
--       <elem>S-1-5-21-12345678-1234567890-0987654321-501</elem>
--     </table>
--     <elem key="name">Guests</elem>
--     <table key="members">
--       <elem>Guest</elem>
--     </table>
--   </table>
--   <table key="RID 559">
--     <table key="member_sids">
--       <elem>S-1-5-21-12345678-1234567890-0987654321-1001</elem>
--     </table>
--     <elem key="name">Performance Log Users</elem>
--     <table key="members">
--       <elem>Daniel</elem>
--     </table>
--   </table>
--   <table key="RID 562">
--     <table key="member_sids"></table>
--     <elem key="name">Distributed COM Users</elem>
--     <table key="members"></table>
--   </table>
--   <table key="RID 568">
--     <table key="member_sids">
--       <elem>S-1-5-17</elem>
--     </table>
--     <elem key="name">IIS_IUSRS</elem>
--     <table key="members"></table>
--   </table>
-- </table>
-- <table key="azure">
--   <table key="RID 1000">
--     <table key="member_sids">
--       <elem>S-1-5-21-12345678-1234567890-0987654321-500</elem>
--       <elem>S-1-5-21-12345678-1234567890-0987654321-1001</elem>
--       <elem>S-1-5-21-12345678-1234567890-0987654321-1002</elem>
--     </table>
--     <elem key="name">HomeUsers</elem>
--     <table key="members">
--       <elem>Administrator</elem>
--       <elem>Daniel</elem>
--       <elem>HomeGroupUser$</elem>
--     </table>
--   </table>
--   <table key="RID 1003">
--     <table key="member_sids"></table>
--     <elem key="name">HelpLibraryUpdaters</elem>
--     <table key="members"></table>
--   </table>
-- </table>
author = "Ron Bowes"
copyright = "Ron Bowes"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery","intrusive"}
dependencies = {"smb-brute"}
hostrule = function(host)
  return smb.get_port(host) ~= nil
end
local empty = {"<empty>"}
action = function(host)
  local status, groups = msrpc.samr_enum_groups(host)
  if(not(status)) then
    return stdnse.format_output(false, "Couldn't enumerate groups: " .. groups)
  end
  local response = stdnse.output_table()
  local response_str = {}
  local domains = tableaux.keys(groups)
  table.sort(domains)
  for _, domain_name in ipairs(domains) do
    local dom_groups = stdnse.output_table()
    response[domain_name] = dom_groups
    local domain_data = groups[domain_name]
    local rids = tableaux.keys(domain_data)
    table.sort(rids)
    for _, rid in ipairs(rids) do
      local group_data = domain_data[rid]
      -- TODO: Map SIDs to names, show non-named SIDs
      table.insert(response_str,
        string.format("\n  %s\\%s (RID: %s): %s", domain_name, group_data.name, rid,
          table.concat(#group_data.members > 0 and group_data.members or empty, ", "))
        )
      dom_groups[string.format("RID %d", rid)] = group_data
    end
  end
  return response, table.concat(response_str)
end
 |