mirror of
https://github.com/nmap/nmap.git
synced 2025-12-15 12:19:02 +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:
@@ -1,40 +1,75 @@
|
||||
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.
|
||||
description = [[ Attempts to enumerate domains on a system, along with their policies. This will likely
|
||||
only work without credentials against Windows 2000.
|
||||
|
||||
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
|
||||
After the initial bind() to SAMR, the sequence of calls is:
|
||||
* Connect4() -- get a connect_handle
|
||||
* EnumDomains() -- get a list of the domains (stop here if you just want the names)
|
||||
* QueryDomain() -- get the sid for the domain
|
||||
* OpenDomain() -- get a handle for each domain
|
||||
* QueryDomainInfo2() -- get the domain information
|
||||
* QueryDomainUsers() -- get a list of the users in the domain
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- nmap --script smb-enumdomains.nse -p445 <host>\n
|
||||
-- sudo nmap -sU -sS --script smb-enumdomains.nse -p U:137,T:139 <host>\n
|
||||
--@usage
|
||||
-- nmap --script smb-enumdomains.nse -p445 <host>
|
||||
-- sudo nmap -sU -sS --script smb-enumdomains.nse -p U:137,T:139 <host>
|
||||
--
|
||||
--@output
|
||||
-- Host script results:
|
||||
-- | MSRPC: List of domains:
|
||||
-- | Domain: LOCALSYSTEM
|
||||
-- | |_ SID: S-1-5-21-2956463495-2656032972-1271678565
|
||||
-- | |_ Users: Administrator, Guest, SUPPORT_388945a0
|
||||
-- | |_ Creation time: 2007-11-26 15:24:04
|
||||
-- | |_ Passwords: min length: 11 characters; min age: 5 days; max age: 63 days
|
||||
-- | |_ Password lockout: 3 attempts in under 15 minutes will lock the account until manually reset
|
||||
-- | |_ Password history : 5 passwords
|
||||
-- | |_ Password properties:
|
||||
-- | |_ Password complexity requirements exist
|
||||
-- | |_ Administrator account cannot be locked out
|
||||
-- | Domain: Builtin
|
||||
-- | |_ SID: S-1-5-32
|
||||
-- | |_ Users:
|
||||
-- | |_ Creation time: 2007-11-26 15:24:04
|
||||
-- | |_ Passwords: min length: n/a; min age: n/a; max age: 42 days
|
||||
-- | |_ Account lockout disabled
|
||||
-- | |_ Password properties:
|
||||
-- | |_ Password complexity requirements do not exist
|
||||
-- |_ |_ Administrator account cannot be locked out
|
||||
--
|
||||
--@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
|
||||
--
|
||||
-- @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
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
description = "Tries calling the EnumDomains() and QueryDomainInfo2() RPC function to obtain a list of domains/policies."
|
||||
author = "Ron Bowes"
|
||||
copyright = "Ron Bowes"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
@@ -58,123 +93,201 @@ end
|
||||
|
||||
action = function(host)
|
||||
local response = " \n"
|
||||
local status, socket
|
||||
local uid, tid, fid
|
||||
local status, smbstate
|
||||
|
||||
-- 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 "ERROR: " .. socket
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. smbstate
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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)
|
||||
return "ERROR: " .. bind_result
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. bind_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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)
|
||||
return "ERROR: " .. connect4_result
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. connect4_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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)
|
||||
status, enumdomains_result = msrpc.samr_enumdomains(smbstate, connect_handle)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(socket, uid, tid)
|
||||
return "ERROR: " .. enumdomains_result
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. enumdomains_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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"
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: Couldn't find any domains to check"
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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
|
||||
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)
|
||||
-- Call LookupDomain()
|
||||
status, lookupdomain_result = msrpc.samr_lookupdomain(smbstate, connect_handle, domain)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. lookupdomain_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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)
|
||||
-- Save the sid
|
||||
sid = lookupdomain_result['sid']
|
||||
|
||||
-- Call OpenDomain()
|
||||
status, opendomain_result = msrpc.samr_opendomain(smbstate, connect_handle, sid)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. opendomain_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
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
|
||||
-- Save the domain handle
|
||||
domain_handle = opendomain_result['domain_handle']
|
||||
|
||||
-- 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)
|
||||
-- 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(smbstate, domain_handle, 1)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. querydomaininfo2_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
status, querydomaininfo2_result = msrpc.samr_querydomaininfo2(smbstate, domain_handle, 8, querydomaininfo2_result)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. querydomaininfo2_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
status, querydomaininfo2_result = msrpc.samr_querydomaininfo2(smbstate, domain_handle, 12, querydomaininfo2_result)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. querydomaininfo2_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Call EnumDomainUsers() to get users
|
||||
status, enumdomainusers_result = msrpc.samr_enumdomainusers(smbstate, domain_handle)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
if(nmap.debugging() > 0) then
|
||||
return "ERROR: " .. enumdomainusers_result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Close the domain handle
|
||||
msrpc.samr_close(socket, domain_handle, uid, tid, fid)
|
||||
-- Close the domain handle
|
||||
msrpc.samr_close(smbstate, domain_handle)
|
||||
|
||||
-- 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
|
||||
-- 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'])
|
||||
|
||||
-- Password characteristics
|
||||
local min_password_length = querydomaininfo2_result['min_password_length']
|
||||
local max_password_age = querydomaininfo2_result['max_password_age']
|
||||
local min_password_age = querydomaininfo2_result['min_password_age']
|
||||
|
||||
if(min_password_length > 0) then
|
||||
min_password_length = string.format("%d characters", min_password_length)
|
||||
else
|
||||
min_password_length = "n/a"
|
||||
end
|
||||
|
||||
if(max_password_age > 0 and max_password_age < 5000) then
|
||||
max_password_age = string.format("%d days", max_password_age)
|
||||
else
|
||||
max_password_age = "n/a"
|
||||
end
|
||||
|
||||
if(min_password_age > 0) then
|
||||
min_password_age = string.format("%d days", min_password_age)
|
||||
else
|
||||
min_password_age = "n/a"
|
||||
end
|
||||
|
||||
response = response .. string.format(" |_ Passwords: min length: %s; min age: %s; max age: %s\n", min_password_length, min_password_age, max_password_age)
|
||||
|
||||
local lockout_duration = querydomaininfo2_result['lockout_duration']
|
||||
if(lockout_duration < 0) then
|
||||
lockout_duration = string.format("for %d minutes", querydomaininfo2_result['lockout_duration'])
|
||||
else
|
||||
lockout_duration = "until manually reset"
|
||||
end
|
||||
|
||||
if(querydomaininfo2_result['lockout_threshold'] > 0) then
|
||||
response = response .. string.format(" |_ Password lockout: %d attempts in under %d minutes will lock the account %s\n", querydomaininfo2_result['lockout_threshold'], querydomaininfo2_result['lockout_window'], lockout_duration)
|
||||
else
|
||||
response = response .. string.format(" |_ Account lockout disabled\n")
|
||||
end
|
||||
|
||||
if(querydomaininfo2_result['password_history_length']) > 0 then
|
||||
response = response .. string.format(" |_ Password history : %d passwords\n", querydomaininfo2_result['password_history_length'])
|
||||
end
|
||||
|
||||
if(#querydomaininfo2_result['password_properties_list'] > 0) then
|
||||
response = response .. " |_ Password properties: \n |_ " .. stdnse.strjoin("\n |_ ", querydomaininfo2_result['password_properties_list']) .. "\n"
|
||||
end
|
||||
end
|
||||
|
||||
-- Close the connect handle
|
||||
msrpc.samr_close(socket, connect_handle, uid, tid, fid)
|
||||
msrpc.samr_close(smbstate, connect_handle)
|
||||
|
||||
-- Close the SMB session
|
||||
msrpc.stop_smb(socket, uid, tid)
|
||||
msrpc.stop_smb(smbstate)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
Reference in New Issue
Block a user