File: smb-enum-groups.nse

package info (click to toggle)
nmap 6.47-3%2Bdeb8u2
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 44,788 kB
  • ctags: 25,108
  • sloc: ansic: 89,741; cpp: 62,412; sh: 19,492; python: 17,323; xml: 11,413; perl: 2,529; makefile: 2,503; yacc: 608; lex: 469; asm: 372; java: 45
file content (96 lines) | stat: -rw-r--r-- 3,606 bytes parent folder | download | duplicates (2)
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
local msrpc = require "msrpc"
local smb = require "smb"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"

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:
-- |  |  WINDOWS2003\HelpServicesGroup: SUPPORT_388945a0
-- |  |  WINDOWS2003\IIS_WPG: SYSTEM, SERVICE, NETWORK SERVICE, IWAM_WINDOWS2003
-- |  |  WINDOWS2003\TelnetClients: <empty>
-- |  |  Builtin\Print Operators: <empty>
-- |  |  Builtin\Replicator: <empty>
-- |  |  Builtin\Network Configuration Operators: <empty>
-- |  |  Builtin\Performance Monitor Users: <empty>
-- |  |  Builtin\Users: INTERACTIVE, Authenticated Users, ron, ASPNET, test
-- |  |  Builtin\Power Users: <empty>
-- |  |  Builtin\Backup Operators: <empty>
-- |  |  Builtin\Remote Desktop Users: <empty>
-- |  |  Builtin\Administrators: Administrator, ron, test
-- |  |  Builtin\Performance Log Users: NETWORK SERVICE
-- |  |  Builtin\Guests: Guest, IUSR_WINDOWS2003
-- |_ |_ Builtin\Distributed COM Users: <empty>
-----------------------------------------------------------------------

author = "Ron Bowes"
copyright = "Ron Bowes"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery","intrusive"}
dependencies = {"smb-brute"}


hostrule = function(host)
  return smb.get_port(host) ~= nil
end

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 = {}

  for domain_name, domain_data in pairs(groups) do

    for rid, group_data in pairs(domain_data) do
      local members = group_data['members']
      if(#members > 0) then
        members = stdnse.strjoin(", ", group_data['members'])
      else
        members = "<empty>"
      end
      table.insert(response, string.format("%s\\%s (RID: %s): %s", domain_name, group_data['name'], rid, members))
    end
  end

  return stdnse.format_output(true, response)
end