1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-13 19:29:04 +00:00

Merge from /nmap-exp/ron/nmap-smb. This adds the new scripts

smb-serverstats.nse, smb-enumsessions.nse, and smb-enumshares.nse.
This commit is contained in:
david
2008-11-03 20:00:24 +00:00
parent 2cceb5184c
commit cc7a58cd7a
11 changed files with 4644 additions and 1779 deletions

View File

@@ -2,74 +2,148 @@ id = "MSRPC: List of user accounts"
description = [[
Attempts to enumerate the users on a remote Windows system, with as much
information as possible, through a variety of techniques (over SMB + MSRPC,
which uses port 445 or 139).
which uses port 445 or 139). Some functions in SAMR are used to enumerate
users, and some bruteforce guessing using LSA functions is attempted.
One technique used is calling the QueryDisplayInfo() function in the SAMR library.
If this succeeds, it will return a detailed list of users. This can be done
anonymously against Windows 2000, and with a user-level account on other Windows
versions (but not with a guest-level account).
To perform this test, the following functions are used:
* Bind() -- bind to the SAMR service
* Connect4() -- get a connect_handle
* EnumDomains() -- get a list of the domains
* QueryDomain() -- get the sid for the domain
* OpenDomain() -- get a handle for each domain
* QueryDisplayInfo() -- get the list of users in the domain
* Close() -- Close the domain handle
* Close() -- Close the connect handle
The advantage of this technique is that a lot of details are returned, including
the full name and description; the disadvantage is that it requires a user-level
account on every system except for Windows 2000. Additionally, it only pulls actual
user accounts, not groups or aliasts.
Will first attempt to call the QueryDisplayInfo() MSRPC function. If NULL
sessions are enabled, this will succeed and pull back a detailed list of users.
Unfortunately, this likely won't succeed unless we're scanning Windows 2000.
When this test is performed, the following MSRPC functions are called:\n
Bind() -- bind to the SAMR service\n
Connect4() -- get a connect_handle\n
EnumDomains() -- get a list of the domains\n
QueryDomain() -- get the sid for the domain\n
OpenDomain() -- get a handle for each domain\n
QueryDisplayInfo() -- get the list of users in the domain\n
Close() -- Close the domain handle\n
Close() -- Close the connect handle
\n\n
Credit goes out to the enum.exe program, the code I wrote for this is largely
due to packetlogs I took of its operations.
\n\n
Regardless of whether or not this succeeds, a second technique is used to pull
user accounts. This one is apparently successful against more machines,
although I haven't found a machine that this only works against. However, I did
find that this will turn up more users for certain systems (although I haven't
figured out why).
user accounts, called LSA bruteforcing. LSA bruteforcing can be done anonymously
against Windows 2000, and requires a guest account or better on other systems.
It has the advantage of running with less permissions, and will also find more
account types (ie, groups, aliases, etc). The disadvantages is that it returns
less information, and that, because it's a bruteforce, it's possible to miss
accounts.
\n\n
Each user on a Windows system has an RID. The RID of 500 is the Administrator
account (even if it's renamed), 501 is the Guest account, and 1000+ are the
user accounts. This technique, which was originally used in the
sid2user/user2sid programs, will attempt to convert common RID numbers to names
to discover users.
This isn't a bruteforce in the common sense, however; it's a bruteforce of users'
RIDs. A user's RID is a value (generally 500, 501, or 1000+) that uniquely identifies
a user on a domain or system. An LSA function is exposed which lets us convert the RID
(say, '1000') to the username (say, 'Ron'). So, the bruteforce will essentially try
converting 1000 to a name, 1001, 1002, etc., until we think we're done.
\n\n
First, the SID of the server has to be determined. This is done by looking up
any name present on the server using a technique like user2sid. For this code,
we try and convert as many names as we can find -- all we need is one valid
name for this to succeed. In this code, I use:\n
- The computer name / domain name, returned in SMB_COM_NEGOTIATE\n
- An nbstat query to get the server name and the currently loggeed in user\n
- Some common names ("administrator", "guest", and "test")
I break the users into 5-RID groups, and check them individually (checking too many
at once causes problems). I continue checking until I reach 1100, and get an empty
group. This probably isn't the most effective way, but it seems to work.
It might be a good idea to modify this, in the future, with some more
intelligence. I performed a test on an old server with a lot of accounts,
and I got these results: 500, 501, 1000, 1030, 1031, 1053, 1054, 1055,
1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1070,
1075, 1081, 1088, 1090. The jump from 1000 to 1030 is quite large and can easily
result in missing accounts, in an automated check.
\n\n
Before attempting this conversion, the SID of the server has to be determined.
The SID is determined by doing the reverse operation -- converting a name into
a RID. The name is determined by looking up any name present on the system.
In this script, I try looking up:
\n\n
<ul>
<li>The computer name / domain name, returned in SMB_COM_NEGOTIATE
<li>An nbstat query to get the server name and the currently loggeed in user
<li>Some common names ("administrator", "guest", and "test")
</ul>
\n\n
In theory, the computer name should be sufficient for this to always work, and
the rest of the names are in there for good measure.
\n\n
Once that's completed, the RIDs 500 - 505 are requested, and any responses are
displayed. Then, starting at 1000, we take small groups of RIDs which are
requestd. I break them into smaller groups because if too many are requested at
once, we get a STATUS_BUFFER_OVERFLOW error. We try every RID up to 1100, then,
as soon as we get an empty group (5 RIDs in a row without a result), we stop.
\n\n
It might be a good idea to modify this, in the future, with some more
intelligence. For example, have it run until it get 5 groups in a row with no
results instead of going up to 1100. I performed a test on an old server we
have here with a lot of accounts, and I got these results: 500, 501, 1000,
1030, 1031, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
1064, 1065, 1066, 1067, 1070, 1075, 1081, 1088, 1090. The jump from 1000 to
1030 is quite large and can easily result in missing accounts.
\n\n
The disadvantage of using the user2sid/sid2user technique is that less
information is returned about the user.
so far has in my tests, but I included the rest of the names for good measure.
\n\n
The names and details from both of these techniques are merged and displayed.
If the output is verbose, then as many details as possible are displayed,
otherwise only the list of usernames are displayed. The names are ordered
alphabetically.
If the output is verbose, then extra details. The output is ordered alphabetically.
\n\n
Credit goes out to the enum.exe, sid2user.exe, and user2sid.exe programs,
the code I wrote for this is largely based on the techniques used by them.
]]
---
-- @usage
-- nmap --script smb-enumusers.nse -p445 <host>\n
-- nmap --script smb-enumusers.nse -p445 <host>
-- sudo nmap -sU -sS --script smb-enumusers.nse -p U:137,T:139 <host>
--
-- @output
-- Host script results:
-- | MSRPC: List of user accounts:
-- |_ TESTBOX\Administrator, EXTERNAL\DnsAdmins, TESTBOX\Guest, EXTERNAL\HelpServicesGroup, EXTERNAL\PARTNERS$, TESTBOX\SUPPORT_388945a0
--
-- Host script results:
-- | MSRPC: List of user accounts:
-- | Administrator
-- | |_ Type: User
-- | |_ Domain: LOCALSYSTEM
-- | |_ Full name: Built-in account for administering the computer/domain
-- | |_ Flags: Normal account, Password doesn't expire
-- | DnsAdmins
-- | |_ Type: Alias
-- | |_ Domain: EXTRANET
-- | EventViewer
-- | |_ Type: User
-- | |_ Domain: SHARED
-- | ProxyUsers
-- | |_ Type: Group
-- | |_ Domain: EXTRANET
-- | ComputerAccounts
-- | |_ Type: Group
-- | |_ Domain: EXTRANET
-- | Helpdesk
-- | |_ Type: Group
-- | |_ Domain: EXTRANET
-- | Guest
-- | |_ Type: User
-- | |_ Domain: LOCALSYSTEM
-- | |_ Full name: Built-in account for guest access to the computer/domain
-- | |_ Flags: Normal account, Disabled, Password not required, Password doesn't expire
-- | Staff
-- | |_ Type: Alias
-- | |_ Domain: LOCALSYSTEM
-- | Students
-- | |_ Type: Alias
-- |_ |_ Domain: LOCALSYSTEM
--
--
--@args smbusername The SMB username to log in with. The form DOMAIN\username and username@DOMAIN
-- are NOT understood. To set a domain, use the smbdomain argument.
--@args smbdomain The domain to log in with. If you aren't in a domained environment, then anything
-- will (should?) be accepted by the server.
--@args smbpassword The password to connect with. Be cautious with this, since some servers will lock
-- accounts if the incorrect password is given (although it's rare for the
-- 'administrator' account to be lockoutable, in the off chance that it is, you could
-- get yourself in trouble).
--@args smbhash A password hash to use when logging in. This is given as a single hex string (32
-- characters) or a pair of hex strings (2 x 32 characters, optionally separated by a
-- single character). These hashes are the Lanman or NTLM hash of the user's password,
-- and are stored by systems, on the harddrive or memory. They can be retrived from memory
-- using the fgdump or pwdump tools.
--@args smbguest If this is set to 'true' or '1', a 'guest' login will be attempted if the normal one
-- fails. This should be harmless, but I thought I would disable it by default anyway
-- because I'm not entirely sure of any possible consequences.
--@args smbtype The type of SMB authentication to use. By default, NTLMv1 is used, which is a pretty
-- decent compromise between security and compatibility. If you are paranoid, you might
-- want to use 'v2' or 'lmv2' for this (actually, if you're paranoid, you should be
-- avoiding this protocol altogether :P). If you're using an extremely old system, you
-- might need to set this to 'v1' or 'lm', which are less secure but more compatible.
--
-- If you want finer grained control, these are the possible options:
-- * v1 -- Sends LMv1 and NTLMv1
-- * LMv1 -- Sends LMv1 only
-- * NTLMv1 -- Sends NTLMv1 only (default)
-- * v2 -- Sends LMv2 and NTLMv2
-- * LMv2 -- Sends LMv2 only
--
-----------------------------------------------------------------------
author = "Ron Bowes"
@@ -100,29 +174,32 @@ end
-- array of tables. Each table contains a 'name', 'domain', 'fullname', 'rid', and 'description'.
local function enum_samr(host)
stdnse.print_debug(3, "Entering enum_samr()")
local smbstate
local bind_result, connect4_result, enumdomains_result
local connect_handle
local status, socket
local uid, tid, fid
local status, smbstate
local response = {}
-- Create the SMB session
status, socket, uid, tid, fid = msrpc.start_smb(host, msrpc.SAMR_PATH)
status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH)
if(status == false) then
return false, socket
return false, smbstate
end
-- Bind to SAMR service
status, bind_result = msrpc.bind(socket, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil, uid, tid, fid)
status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, bind_result
end
-- Call connect4()
status, connect4_result = msrpc.samr_connect4(socket, host.ip, uid, tid, fid)
status, connect4_result = msrpc.samr_connect4(smbstate, host.ip)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, connect4_result
end
@@ -130,31 +207,32 @@ local function enum_samr(host)
connect_handle = connect4_result['connect_handle']
-- Call EnumDomains()
status, enumdomains_result = msrpc.samr_enumdomains(socket, connect_handle, uid, tid, fid)
status, enumdomains_result = msrpc.samr_enumdomains(smbstate, connect_handle)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, enumdomains_result
end
-- If no domains were returned, go back with an error
if(#enumdomains_result['domains'] == 0) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, "Couldn't find any domains"
end
-- Now, loop through the domains and find the users
for i = 1, #enumdomains_result['domains'], 1 do
local domain = enumdomains_result['domains'][i]
-- We don't care about the 'builtin' domain
-- We don't care about the 'builtin' domain, in all my tests it's empty
if(domain ~= 'Builtin') then
local sid
local domain_handle
local opendomain_result, querydisplayinfo_result
-- Call LookupDomain()
status, lookupdomain_result = msrpc.samr_lookupdomain(socket, connect_handle, domain, uid, tid, fid)
status, lookupdomain_result = msrpc.samr_lookupdomain(smbstate, connect_handle, domain)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, lookupdomain_result
end
@@ -162,9 +240,9 @@ local function enum_samr(host)
sid = lookupdomain_result['sid']
-- Call OpenDomain()
status, opendomain_result = msrpc.samr_opendomain(socket, connect_handle, sid, uid, tid, fid)
status, opendomain_result = msrpc.samr_opendomain(smbstate, connect_handle, sid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, opendomain_result
end
@@ -172,28 +250,33 @@ local function enum_samr(host)
domain_handle = opendomain_result['domain_handle']
-- Call QueryDisplayInfo()
status, querydisplayinfo_result = msrpc.samr_querydisplayinfo(socket, domain_handle, uid, tid, fid)
status, querydisplayinfo_result = msrpc.samr_querydisplayinfo(smbstate, domain_handle)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
return false, querydisplayinfo_result
end
-- Close the domain handle
msrpc.samr_close(socket, domain_handle, uid, tid, fid)
msrpc.samr_close(smbstate, domain_handle)
-- Finally, fill in the response!
for i = 1, #querydisplayinfo_result['details'], 1 do
querydisplayinfo_result['details'][i]['domain'] = domain
-- All we get from this is users
querydisplayinfo_result['details'][i]['typestr'] = "User"
querydisplayinfo_result['details'][i]['source'] = "SAMR Enumeration"
response[#response + 1] = querydisplayinfo_result['details'][i]
end
end -- Checking for 'builtin'
end -- Domain loop
-- Close the connect handle
msrpc.samr_close(socket, connect_handle, uid, tid, fid)
msrpc.samr_close(smbstate, connect_handle)
-- Stop the SAMR SMB
msrpc.stop_smb(socket, uid, tid)
msrpc.stop_smb(smbstate)
stdnse.print_debug(3, "Leaving enum_samr()")
return true, response
end
@@ -205,116 +288,126 @@ end
-- array of tables. Each table contains a 'name', 'domain', and 'rid'.
local function enum_lsa(host)
local status, socket
local uid, tid, fid
local smbstate
local status
local response = {}
-- Create the SMB session
status, socket, uid, tid, fid, negotiate_result = msrpc.start_smb(host, msrpc.LSA_PATH)
if(status == false) then
return false, socket
end
stdnse.print_debug(3, "Entering enum_lsa()")
-- Bind to LSA service
status, bind_result = msrpc.bind(socket, msrpc.LSA_UUID, msrpc.LSA_VERSION, nil, uid, tid, fid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
return false, bind_result
end
-- Create the SMB session
status, smbstate = msrpc.start_smb(host, msrpc.LSA_PATH)
if(status == false) then
return false, smbstate
end
-- Open the LSA policy
status, openpolicy2_result = msrpc.lsa_openpolicy2(socket, host.ip, uid, tid, fid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
return false, openpolicy2_result
end
-- Bind to LSA service
status, bind_result = msrpc.bind(smbstate, msrpc.LSA_UUID, msrpc.LSA_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, bind_result
end
-- Start with some common names, as well as the name returned by the negotiate call
names = {"administrator", "guest", "test", negotiate_result['domain'], negotiate_result['server'] }
-- Open the LSA policy
status, openpolicy2_result = msrpc.lsa_openpolicy2(smbstate, host.ip)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, openpolicy2_result
end
-- Get the server's name from nbstat
local result, server_name = netbios.get_server_name(host.ip)
if(result == true) then
names[#names + 1] = server_name
end
-- Start with some common names, as well as the name returned by the negotiate call
-- Vista doesn't like a 'null' after the server name, so fix that (TODO: the way I strip the null here feels hackish, is there a better way?)
names = {"administrator", "guest", "test", smbstate['domain'], string.sub(smbstate['server'], 1, #smbstate['server'] - 1) }
-- Get the logged in user from nbstat
local result, user_name = netbios.get_user_name(host.ip)
if(result == true) then
names[#names + 1] = user_name
end
-- Get the server's name from nbstat
local result, server_name = netbios.get_server_name(host.ip)
if(result == true) then
names[#names + 1] = server_name
end
-- Look up the names, if any are valid than the server's SID will be returned
status, lookupnames2_result = msrpc.lsa_lookupnames2(socket, openpolicy2_result['policy_handle'], names, uid, tid, fid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
return false, lookupnames2_result
end
-- Get the logged in user from nbstat
local result, user_name = netbios.get_user_name(host.ip)
if(result == true) then
names[#names + 1] = user_name
end
-- Loop through the domains returned and find teh users in each
for i = 1, #lookupnames2_result['domains'], 1 do
local domain = lookupnames2_result['domains'][i]['name']
local sid = lookupnames2_result['domains'][i]['sid']
local rids = { }
local start = 1000
-- Look up the names, if any are valid than the server's SID will be returned
status, lookupnames2_result = msrpc.lsa_lookupnames2(smbstate, openpolicy2_result['policy_handle'], names)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, lookupnames2_result
end
-- Start by looking up 500 - 505 (will likely be Administrator + guest)
for j = 500, 505, 1 do
-- Loop through the domains returned and find the users in each
for i = 1, #lookupnames2_result['domains'], 1 do
local domain = lookupnames2_result['domains'][i]['name']
local sid = lookupnames2_result['domains'][i]['sid']
local rids = { }
local start = 1000
-- Start by looking up 500 - 505 (will likely be Administrator + guest)
for j = 500, 505, 1 do
rids[#rids + 1] = j
end
status, lookupsids2_result = msrpc.lsa_lookupsids2(socket, openpolicy2_result['policy_handle'], sid, rids, uid, tid, fid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
return false, lookupsids2_result
end
-- Put the details for each name into an array
for j = 1, #lookupsids2_result['details'], 1 do
if(lookupsids2_result['details'][j]['name'] ~= nil) then
local result = {}
result['name'] = lookupsids2_result['details'][j]['name']
result['rid'] = 500 + j - 1
result['domain'] = domain
response[#response + 1] = result
status, lookupsids2_result = msrpc.lsa_lookupsids2(smbstate, openpolicy2_result['policy_handle'], sid, rids)
if(status == false) then
stdnse.print_debug(1, string.format("Error looking up RIDs: %s", lookupsids2_result))
else
-- Put the details for each name into an array
for j = 1, #lookupsids2_result['details'], 1 do
if(lookupsids2_result['details'][j]['type'] ~= 8) then -- 8 = user not found
local result = {}
result['name'] = lookupsids2_result['details'][j]['name']
result['rid'] = 500 + j - 1
result['domain'] = domain
result['typestr'] = lookupsids2_result['details'][j]['typestr']
result['source'] = "LSA Bruteforce"
response[#response + 1] = result
end
end
end
-- Now do groups of 5 users, until we get past 1100 and have an empty group
repeat
rids = {}
for j = start, start + 4, 1 do
-- Now do groups of 5 users, until we get past 1100 and have an empty group
repeat
local used_names = 0
local rids = {}
for j = start, start + 4, 1 do
rids[#rids + 1] = j
end
-- Try converting this group of RIDs into names
status, lookupsids2_result = msrpc.lsa_lookupsids2(socket, openpolicy2_result['policy_handle'], sid, rids, uid, tid, fid)
if(status == false) then
msrpc.stop_smb(socket, uid, tid)
return false, lookupsids2_result
end
status, lookupsids2_result = msrpc.lsa_lookupsids2(smbstate, openpolicy2_result['policy_handle'], sid, rids)
if(status == false) then
stdnse.print_debug(1, string.format("Error looking up RIDs: %s", lookupsids2_result))
else
-- Put the details for each name into an array
for j = 1, #lookupsids2_result['details'], 1 do
if(lookupsids2_result['details'][j]['type'] ~= 8) then -- 8 = user not found
local result = {}
result['name'] = lookupsids2_result['details'][j]['name']
result['rid'] = start + j - 1
result['domain'] = domain
result['typestr'] = lookupsids2_result['details'][j]['typestr']
result['source'] = "LSA Bruteforce"
response[#response + 1] = result
-- Put the details for each name into an array
for j = 1, #lookupsids2_result['details'], 1 do
if(lookupsids2_result['details'][j]['name'] ~= nil) then
local result = {}
result['name'] = lookupsids2_result['details'][j]['name']
result['rid'] = start + j - 1
result['domain'] = domain
response[#response + 1] = result
-- Increment the number of used names we have
used_names = used_names + 1
end
end
end
-- Go to the next set of RIDs
start = start + 5
until #lookupsids2_result['names'] == 0 and start > 1100
start = start + 5
until status == false or (used_names == 0 and start > 1100)
end
end
-- Close the handle
msrpc.lsa_close(smbstate, openpolicy2_result['policy_handle'])
-- Close the handle
msrpc.lsa_close(socket, openpolicy2_result['policy_handle'], uid, tid, fid)
msrpc.stop_smb(smbstate)
msrpc.stop_smb(socket, uid, tid)
stdnse.print_debug(3, "Leaving enum_lsa()")
return true, response
end
@@ -323,41 +416,53 @@ end
action = function(host)
local i, j
local status
local samr_status, lsa_status
local samr_result, lsa_result
local names = {}
local name_strings = {}
local response = " \n"
-- Try enumerating through SAMR
status, samr_result = enum_samr(host)
if(status == false) then
response = response .. "Enum via SAMR error: " .. samr_result .. "\n"
-- Try enumerating through LSA first. Since LSA provides less information, we want the
-- SAMR result to overwrite it.
lsa_status, lsa_result = enum_lsa(host)
if(lsa_status == false) then
if(nmap.debugging() > 0) then
response = response .. "ERROR: couldn't enum through LSA: " .. lsa_result .. "\n"
end
else
-- Copy the returned array into the names[] table, using the name as the key
stdnse.print_debug("EnumUsers: Received %d names from SAMR", #samr_result)
stdnse.print_debug(2, "EnumUsers: Received %d names from LSA", #lsa_result)
for i = 1, #lsa_result, 1 do
names[string.upper(lsa_result[i]['name'])] = lsa_result[i]
end
end
-- Try enumerating through SAMR
samr_status, samr_result = enum_samr(host)
if(samr_status == false) then
if(nmap.debugging() > 0) then
response = response .. "ERROR: couldn't enumerate through SAMR: " .. samr_result .. "\n"
end
else
-- Copy the returned array into the names[] table, using the name as the key
stdnse.print_debug(2, "EnumUsers: Received %d names from SAMR", #samr_result)
for i = 1, #samr_result, 1 do
names[string.upper(samr_result[i]['name'])] = samr_result[i]
end
end
-- Try enumerating through LSA
status, lsa_result = enum_lsa(host)
if(status == false) then
response = response .. "Enum via LSA error: " .. lsa_result .. "\n"
else
-- Copy the returned array into the names[] table, using the name as the key
stdnse.print_debug("EnumUsers: Received %d names from LSA", #samr_result)
for i = 1, #lsa_result, 1 do
if(names[lsa_result[i]['name']] == nil) then
names[string.upper(lsa_result[i]['name'])] = lsa_result[i]
end
-- Check if both failed
if(samr_status == false and lsa_status == false) then
if(nmap.debugging() > 0) then
return response
else
return nil
end
end
-- Put the names into an array of strings, so we can sort them
for name, details in pairs(names) do
name_strings[#name_strings + 1] = name
name_strings[#name_strings + 1] = names[name]['name']
end
-- Sort them
table.sort(name_strings, function (a, b) return string.lower(a) < string.lower(b) end)
@@ -368,16 +473,30 @@ action = function(host)
else
-- If we're not verbose, just print out the names. Otherwise, print out everything we can
if(nmap.verbosity() < 1) then
response = response .. stdnse.strjoin(", ", name_strings)
local response_array = {}
for i = 1, #name_strings, 1 do
local name = string.upper(name_strings[i])
response_array[#response_array + 1] = (names[name]['domain'] .. "\\" .. names[name]['name'])
end
response = response .. stdnse.strjoin(", ", response_array)
else
for i = 1, #name_strings, 1 do
local name = name_strings[i]
local name = string.upper(name_strings[i])
response = response .. string.format("%s\n", names[name]['name'])
if(names[name]['typestr'] ~= nil) then response = response .. string.format(" |_ Type: %s\n", names[name]['typestr']) end
if(names[name]['domain'] ~= nil) then response = response .. string.format(" |_ Domain: %s\n", names[name]['domain']) end
if(names[name]['rid'] ~= nil) then response = response .. string.format(" |_ RID: %s\n", names[name]['rid']) end
if(nmap.verbosity() > 1) then
if(names[name]['rid'] ~= nil) then response = response .. string.format(" |_ RID: %s\n", names[name]['rid']) end
end
if(names[name]['fullname'] ~= nil) then response = response .. string.format(" |_ Full name: %s\n", names[name]['fullname']) end
if(names[name]['description'] ~= nil) then response = response .. string.format(" |_ Description: %s\n", names[name]['description']) end
if(names[name]['flags'] ~= nil) then response = response .. string.format(" |_ Flags: %s\n", stdnse.strjoin(", ", names[name]['flags_list'])) end
if(nmap.verbosity() > 1) then
if(names[name]['source'] ~= nil) then response = response .. string.format(" |_ Source: %s\n", names[name]['source']) end
end
end
end
end
@@ -385,4 +504,16 @@ action = function(host)
return response
end
--real_action = action
--
-- function action (...)
-- local t = {n = select("#", ...), ...};
-- local status, ret = xpcall(function() return real_action(unpack(t, 1, t.n)) end, debug.traceback)
--
-- if not status then
-- error(ret)
-- end
--
-- return ret
-- end