mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 09:49:05 +00:00
I made every script follow a standard form: it starts with the id, followed by the description. The description is contained in [[ ]] delimiters. The description is in the global description variable, not in a LuaDoc comment. Other LuaDoc information such as @args and @usage follows the description in a comment. The first paragraph of each description is a a short summary of what the script does. More detailed information, if any, is given in following paragraphs. I also improved some wording and formatting in a few cases.
184 lines
6.7 KiB
Lua
184 lines
6.7 KiB
Lua
id = "MSRPC: List of domains"
|
|
description = [[
|
|
Attempts to enumerate domains on a system, along with their policies. This will
|
|
likely only work without credentials against Windows 2000.
|
|
\n\n
|
|
After the initial bind() to SAMR, the sequence of calls is:\n
|
|
Connect4() -- get a connect_handle\n
|
|
EnumDomains() -- get a list of the domains (stop here if you just want the names)\n
|
|
QueryDomain() -- get the sid for the domain\n
|
|
OpenDomain() -- get a handle for each domain\n
|
|
QueryDomainInfo2() -- get the domain information\n
|
|
]]
|
|
|
|
---
|
|
-- @usage
|
|
-- nmap --script smb-enumdomains.nse -p445 <host>\n
|
|
-- sudo nmap -sU -sS --script smb-enumdomains.nse -p U:137,T:139 <host>\n
|
|
--
|
|
-- @output
|
|
-- Host script results:\n
|
|
-- | MSRPC: List of domains:\n
|
|
-- | Domain: TEST1\n
|
|
-- | |_ SID: S-1-5-21-1060284298-842925246-839522115\n
|
|
-- | |_ Users: Administrator, ASPNET, Guest, Ron, test\n
|
|
-- | |_ Creation time: 2006-10-17 15:35:07\n
|
|
-- | |_ Min password length: 0 characters\n
|
|
-- | |_ Max password age: 10675199 days\n
|
|
-- | |_ Min password age: 0 days\n
|
|
-- | |_ Password history length: 0 passwords\n
|
|
-- | |_ Lockout threshold: 0 login attempts\n
|
|
-- | |_ Lockout duration: 60 minutes\n
|
|
-- | |_ Lockout window: 60 minutes\n
|
|
-- | |_ Password properties: \n
|
|
-- | |_ Password complexity requirements do not exist\n
|
|
-- |_ |_ Administrator account cannot be locked out\n
|
|
-----------------------------------------------------------------------
|
|
|
|
author = "Ron Bowes"
|
|
copyright = "Ron Bowes"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"discovery","intrusive"}
|
|
|
|
require 'msrpc'
|
|
require 'smb'
|
|
require 'stdnse'
|
|
|
|
hostrule = function(host)
|
|
|
|
local port = smb.get_port(host)
|
|
|
|
if(port == nil) then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
|
|
end
|
|
|
|
action = function(host)
|
|
local response = " \n"
|
|
local status, socket
|
|
local uid, tid, fid
|
|
|
|
-- Create the SMB session
|
|
status, socket, uid, tid, fid = msrpc.start_smb(host, msrpc.SAMR_PATH)
|
|
if(status == false) then
|
|
return "ERROR: " .. socket
|
|
end
|
|
|
|
-- Bind to SAMR service
|
|
status, bind_result = msrpc.bind(socket, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. bind_result
|
|
end
|
|
|
|
-- Call connect4()
|
|
status, connect4_result = msrpc.samr_connect4(socket, host.ip, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. connect4_result
|
|
end
|
|
|
|
-- Save the connect_handle
|
|
connect_handle = connect4_result['connect_handle']
|
|
|
|
-- Call EnumDomains()
|
|
status, enumdomains_result = msrpc.samr_enumdomains(socket, connect_handle, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. enumdomains_result
|
|
end
|
|
|
|
-- If no domanis were returned, print an error (I don't expect this will actually happen)
|
|
if(#enumdomains_result['domains'] == 0) then
|
|
return "ERROR: Couldn't find any domains to check"
|
|
end
|
|
|
|
for i = 1, #enumdomains_result['domains'], 1 do
|
|
|
|
local domain = enumdomains_result['domains'][i]
|
|
-- We don't care about the 'builtin' domain
|
|
if(domain ~= 'Builtin') then
|
|
local sid
|
|
local domain_handle
|
|
|
|
-- Call LookupDomain()
|
|
status, lookupdomain_result = msrpc.samr_lookupdomain(socket, connect_handle, domain, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. lookupdomain_result
|
|
end
|
|
|
|
-- Save the sid
|
|
sid = lookupdomain_result['sid']
|
|
|
|
-- Call OpenDomain()
|
|
status, opendomain_result = msrpc.samr_opendomain(socket, connect_handle, sid, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. opendomain_result
|
|
end
|
|
|
|
-- Save the domain handle
|
|
domain_handle = opendomain_result['domain_handle']
|
|
|
|
-- Call QueryDomainInfo2() to get domain properties. We call these for three types == 1, 8, and 12, since those return
|
|
-- the most useful information.
|
|
status, querydomaininfo2_result = msrpc.samr_querydomaininfo2(socket, domain_handle, 1, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. querydomaininfo2_result
|
|
end
|
|
status, querydomaininfo2_result = msrpc.samr_querydomaininfo2(socket, domain_handle, 8, uid, tid, fid, querydomaininfo2_result)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. querydomaininfo2_result
|
|
end
|
|
status, querydomaininfo2_result = msrpc.samr_querydomaininfo2(socket, domain_handle, 12, uid, tid, fid, querydomaininfo2_result)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. querydomaininfo2_result
|
|
end
|
|
|
|
-- Call EnumDomainUsers() to get users
|
|
status, enumdomainusers_result = msrpc.samr_enumdomainusers(socket, domain_handle, uid, tid, fid)
|
|
if(status == false) then
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
return "ERROR: " .. enumdomainusers_result
|
|
end
|
|
|
|
-- Close the domain handle
|
|
msrpc.samr_close(socket, domain_handle, uid, tid, fid)
|
|
|
|
-- Finally, fill in the response!
|
|
response = response .. string.format("Domain: %s\n", domain)
|
|
response = response .. string.format(" |_ SID: %s\n", msrpc.sid_to_string(lookupdomain_result['sid']))
|
|
response = response .. string.format(" |_ Users: %s\n", stdnse.strjoin(", ", enumdomainusers_result['names']))
|
|
response = response .. string.format(" |_ Creation time: %s\n", querydomaininfo2_result['create_date'])
|
|
response = response .. string.format(" |_ Min password length: %d characters\n", querydomaininfo2_result['min_password_length'])
|
|
response = response .. string.format(" |_ Max password age: %d days\n", querydomaininfo2_result['max_password_age'])
|
|
response = response .. string.format(" |_ Min password age: %d days\n", querydomaininfo2_result['min_password_age'])
|
|
response = response .. string.format(" |_ Password history length: %d passwords\n", querydomaininfo2_result['password_history_length'])
|
|
response = response .. string.format(" |_ Lockout threshold: %d login attempts\n", querydomaininfo2_result['lockout_threshold'])
|
|
response = response .. string.format(" |_ Lockout duration: %d minutes\n", querydomaininfo2_result['lockout_duration'])
|
|
response = response .. string.format(" |_ Lockout window: %d minutes\n", querydomaininfo2_result['lockout_window'])
|
|
if(#querydomaininfo2_result['password_properties_list'] > 0) then
|
|
response = response .. " |_ Password properties: \n |_ " .. stdnse.strjoin("\n |_ ", querydomaininfo2_result['password_properties_list']) .. "\n"
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Close the connect handle
|
|
msrpc.samr_close(socket, connect_handle, uid, tid, fid)
|
|
|
|
-- Close the SMB session
|
|
msrpc.stop_smb(socket, uid, tid)
|
|
|
|
return response
|
|
|
|
end
|
|
|
|
|