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 enum.exe with the /G 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". * Bind: bind to the SAMR service. * Connect4: get a connect_handle. * EnumDomains: get a list of the domains. * LookupDomain: get the RID of the domains. * OpenDomain: get a handle for each domain. * EnumDomainAliases: get the list of groups in the domain. * OpenAlias: get a handle to each group. * GetMembersInAlias: get the RIDs of the members in the groups. * Close: close the alias handle. * Close: close the domain handle. * Close: close the connect handle. Once the RIDs have been termined, the * Bind: bind to the LSA service. * OpenPolicy2: get a policy handle. * LookupSids2: convert SIDs to usernames. I (Ron Bowes) originally looked into the possibility of using the SAMR function LookupRids2 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 -- sudo nmap -sU -sS --script smb-enum-users.nse -p U:137,T:139 -- -- @output -- Host script results: -- | smb-enum-groups: -- | Builtin\Administrators (RID: 544): Administrator, Daniel -- | Builtin\Users (RID: 545): -- | Builtin\Guests (RID: 546): Guest -- | Builtin\Performance Monitor Users (RID: 558): -- | Builtin\Performance Log Users (RID: 559): Daniel -- | Builtin\Distributed COM Users (RID: 562): -- | Builtin\IIS_IUSRS (RID: 568): -- | Builtin\Event Log Readers (RID: 573): -- | azure\HomeUsers (RID: 1000): Administrator, Daniel, HomeGroupUser$ -- |_ azure\HelpLibraryUpdaters (RID: 1003): -- -- @xmloutput -- --
--
-- S-1-5-21-12345678-1234567890-0987654321-500 -- S-1-5-21-12345678-1234567890-0987654321-1001 --
-- Administrators -- -- Administrator -- Daniel --
-- -- --
-- S-1-5-4 -- S-1-5-11 --
-- Users --
-- -- --
-- S-1-5-21-12345678-1234567890-0987654321-501 --
-- Guests -- -- Guest --
-- -- --
-- S-1-5-21-12345678-1234567890-0987654321-1001 --
-- Performance Log Users -- -- Daniel --
-- -- --
-- Distributed COM Users --
-- -- --
-- S-1-5-17 --
-- IIS_IUSRS --
-- -- -- --
--
-- S-1-5-21-12345678-1234567890-0987654321-500 -- S-1-5-21-12345678-1234567890-0987654321-1001 -- S-1-5-21-12345678-1234567890-0987654321-1002 --
-- HomeUsers -- -- Administrator -- Daniel -- HomeGroupUser$ --
-- -- --
-- HelpLibraryUpdaters --
-- -- 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 = {""} 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 = stdnse.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 = stdnse.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