home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Networking / nmap-5.00-setup.exe / scripts / smb-enum-domains.nse < prev    next >
Text File  |  2009-07-06  |  10KB  |  291 lines

  1. description = [[
  2. Attempts to enumerate domains on a system, along with their policies. This generally requires
  3. credentials, except against Windows 2000. In addition to the actual domain, the "Builtin" 
  4. domain is generally displayed. Windows returns this in the list of domains, but its policies 
  5. don't appear to be used anywhere. 
  6.  
  7. Much of the information provided is useful to a penetration tester, because it tells the
  8. tester what types of policies to expect. For example, if passwords have a minimum length of 8, 
  9. the tester can trim his database to match; if the minimum length is 14, the tester will
  10. probably start looking for sticky notes on people's monitors. 
  11.  
  12. Another useful piece of information is the password lockouts -- a penetration tester often wants
  13. to know whether or not there's a risk of negatively impacting a network, and this will 
  14. indicate it. The SID is displayed, which may be useful in other tools; the users are listed, 
  15. which uses different functions than <code>smb-enum-users.nse</code> (though likely won't 
  16. get different results), and the date and time the domain was created may give some insight into
  17. its history. 
  18.  
  19. After the initial <code>bind</code> to SAMR, the sequence of calls is:
  20. * <code>Connect4</code>: get a connect_handle
  21. * <code>EnumDomains</code>: get a list of the domains (stop here if you just want the names).
  22. * <code>QueryDomain</code>: get the SID for the domain.
  23. * <code>OpenDomain</code>: get a handle for each domain.
  24. * <code>QueryDomainInfo2</code>: get the domain information.
  25. * <code>QueryDomainUsers</code>: get a list of the users in the domain.
  26. ]]
  27.  
  28. ---
  29. --@usage
  30. -- nmap --script smb-enum-domains.nse -p445 <host>
  31. -- sudo nmap -sU -sS --script smb-enum-domains.nse -p U:137,T:139 <host>
  32. --
  33. --@output
  34. -- Host script results:
  35. -- |  smb-enum-domains:
  36. -- |  Domain: LOCALSYSTEM
  37. -- |   |_ SID: S-1-5-21-2956463495-2656032972-1271678565
  38. -- |   |_ Users: Administrator, Guest, SUPPORT_388945a0
  39. -- |   |_ Creation time: 2007-11-26 15:24:04
  40. -- |   |_ Passwords: min length: 11 characters; min age: 5 days; max age: 63 days
  41. -- |   |_ Password lockout: 3 attempts in under 15 minutes will lock the account until manually reset
  42. -- |   |_ Password history : 5 passwords
  43. -- |   |_ Password properties:
  44. -- |     |_  Password complexity requirements exist
  45. -- |     |_  Administrator account cannot be locked out
  46. -- |  Domain: Builtin
  47. -- |   |_ SID: S-1-5-32
  48. -- |   |_ Users:
  49. -- |   |_ Creation time: 2007-11-26 15:24:04
  50. -- |   |_ Passwords: min length: n/a; min age: n/a; max age: 42 days
  51. -- |   |_ Account lockout disabled
  52. -- |   |_ Password properties:
  53. -- |     |_  Password complexity requirements do not exist
  54. -- |_    |_  Administrator account cannot be locked out
  55. -----------------------------------------------------------------------
  56.  
  57. author = "Ron Bowes"
  58. copyright = "Ron Bowes"
  59. license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  60. categories = {"discovery","intrusive"}
  61.  
  62. require 'msrpc'
  63. require 'smb'
  64. require 'stdnse'
  65.  
  66. hostrule = function(host)
  67.     return smb.get_port(host) ~= nil
  68. end
  69.  
  70. action = function(host)
  71.  
  72.     local response = " \n"
  73.     local status, smbstate
  74.     local i, j
  75.  
  76.     -- Create the SMB session
  77.     status, smbstate  = msrpc.start_smb(host, msrpc.SAMR_PATH)
  78.     if(status == false) then
  79.         if(nmap.debugging() > 0) then
  80.             return "ERROR: " .. smbstate
  81.         else
  82.             return nil
  83.         end
  84.     end
  85.  
  86.     -- Bind to SAMR service
  87.     status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
  88.     if(status == false) then
  89.         msrpc.stop_smb(smbstate)
  90.         if(nmap.debugging() > 0) then
  91.             return "ERROR: " .. bind_result
  92.         else
  93.             return nil
  94.         end
  95.     end
  96.  
  97.     -- Call connect4()
  98.     status, connect4_result = msrpc.samr_connect4(smbstate, host.ip)
  99.     if(status == false) then
  100.         msrpc.stop_smb(smbstate)
  101.         if(nmap.debugging() > 0) then
  102.             return "ERROR: " .. connect4_result
  103.         else
  104.             return nil
  105.         end
  106.     end
  107.  
  108.     -- Save the connect_handle
  109.     connect_handle = connect4_result['connect_handle']
  110.  
  111.     -- Call EnumDomains()
  112.     status, enumdomains_result = msrpc.samr_enumdomains(smbstate, connect_handle)
  113.     if(status == false) then
  114.         msrpc.stop_smb(smbstate)
  115.         if(nmap.debugging() > 0) then
  116.             return "ERROR: " .. enumdomains_result
  117.         else
  118.             return nil
  119.         end
  120.     end
  121.  
  122.     -- If no domains were returned, print an error (I don't expect this will actually happen)
  123.     if(#enumdomains_result['sam']['entries'] == 0) then
  124.         if(nmap.debugging() > 0) then
  125.             return "ERROR: Couldn't find any domains to check"
  126.         else
  127.             return nil
  128.         end
  129.     end
  130.  
  131.     for i = 1, #enumdomains_result['sam']['entries'], 1 do
  132.  
  133.         local domain = enumdomains_result['sam']['entries'][i]['name']
  134.         local sid
  135.         local domain_handle
  136.  
  137.         -- Call LookupDomain()
  138.         status, lookupdomain_result = msrpc.samr_lookupdomain(smbstate, connect_handle, domain)
  139.         if(status == false) then
  140.             msrpc.stop_smb(smbstate)
  141.             if(nmap.debugging() > 0) then
  142.                 return "ERROR: " .. lookupdomain_result
  143.             else
  144.                 return nil
  145.             end
  146.         end
  147.         -- Save the sid
  148.         sid = lookupdomain_result['sid']
  149.  
  150.         -- Call OpenDomain()
  151.         status, opendomain_result = msrpc.samr_opendomain(smbstate, connect_handle, sid)
  152.         if(status == false) then
  153.             msrpc.stop_smb(smbstate)
  154.             if(nmap.debugging() > 0) then
  155.                 return "ERROR: " .. opendomain_result
  156.             else
  157.                 return nil
  158.             end
  159.         end
  160.  
  161.         -- Save the domain handle
  162.         domain_handle = opendomain_result['domain_handle']
  163.  
  164.         -- Call QueryDomainInfo2() to get domain properties. We call these for three types -- 1, 8, and 12, since those return
  165.         -- the most useful information. 
  166.         status_1,  querydomaininfo2_result_1  = msrpc.samr_querydomaininfo2(smbstate, domain_handle, 1)
  167.         status_8,  querydomaininfo2_result_8  = msrpc.samr_querydomaininfo2(smbstate, domain_handle, 8)
  168.         status_12, querydomaininfo2_result_12 = msrpc.samr_querydomaininfo2(smbstate, domain_handle, 12)
  169.  
  170.         if(status_1 == false) then
  171.             msrpc.stop_smb(smbstate)
  172.             if(nmap.debugging() > 0) then
  173.                 return "ERROR: " .. querydomaininfo2_result_1
  174.             else
  175.                 return nil
  176.             end
  177.         end
  178.         if(status_8 == false) then
  179.             msrpc.stop_smb(smbstate)
  180.             if(nmap.debugging() > 0) then
  181.                 return "ERROR: " .. querydomaininfo2_result_8
  182.             else
  183.                 return nil
  184.             end
  185.         end
  186.         if(status_12 == false) then
  187.             msrpc.stop_smb(smbstate)
  188.             if(nmap.debugging() > 0) then
  189.                 return "ERROR: " .. querydomaininfo2_result_12
  190.             else
  191.                 return nil
  192.             end
  193.         end
  194.  
  195.         -- Call EnumDomainUsers() to get users
  196.         status, enumdomainusers_result = msrpc.samr_enumdomainusers(smbstate, domain_handle)
  197.         if(status == false) then
  198.             msrpc.stop_smb(smbstate)
  199.             if(nmap.debugging() > 0 and enumdomainusers_result ~= nil) then
  200.                 return "ERROR: " .. enumdomainusers_result
  201.             else
  202.                 return nil
  203.             end
  204.         end
  205.  
  206.         -- Close the domain handle
  207.         msrpc.samr_close(smbstate, domain_handle)
  208.  
  209.         -- Create the list of users
  210.         local names = {}
  211.         if(enumdomainusers_result['sam'] ~= nil and enumdomainusers_result['sam']['entries'] ~= nil) then
  212.             for j = 1, #enumdomainusers_result['sam']['entries'], 1 do
  213.                 local name = enumdomainusers_result['sam']['entries'][j]['name']
  214.                 names[#names + 1] = name
  215.             end
  216.         end
  217.  
  218.         -- Finally, fill in the response!
  219.         response = response .. string.format("Domain: %s\n", domain)
  220.         response = response .. string.format(" |_ SID: %s\n",             lookupdomain_result['sid'])
  221.         if(#names ~= 0) then
  222.             response = response .. string.format(" |_ Users: %s\n",           stdnse.strjoin(", ", names))
  223.         end
  224.  
  225.         if(querydomaininfo2_result_8['info']['domain_create_time'] ~= 0) then
  226.             response = response .. string.format(" |_ Creation time: %s\n",   os.date("%Y-%m-%d %H:%M:%S", querydomaininfo2_result_8['info']['domain_create_time']))
  227.         end
  228.  
  229.         -- Password characteristics
  230.         local min_password_length = querydomaininfo2_result_1['info']['min_password_length']
  231.         local max_password_age = querydomaininfo2_result_1['info']['max_password_age'] / 60 / 60 / 24
  232.         local min_password_age = querydomaininfo2_result_1['info']['min_password_age'] / 60 / 60 / 24
  233.  
  234.         if(min_password_length > 0) then
  235.             min_password_length = string.format("%d characters", min_password_length)
  236.         else
  237.             min_password_length = "n/a"
  238.         end
  239.  
  240.         if(max_password_age > 0 and max_password_age < 5000) then
  241.             max_password_age = string.format("%d days", max_password_age)
  242.         else
  243.             max_password_age = "n/a"
  244.         end
  245.  
  246.         if(min_password_age > 0) then
  247.             min_password_age = string.format("%d days", min_password_age)
  248.         else
  249.             min_password_age = "n/a"
  250.         end
  251.  
  252.         response = response .. string.format(" |_ Passwords: min length: %s; min age: %s; max age: %s\n", min_password_length, min_password_age, max_password_age)
  253.  
  254.         local lockout_duration = querydomaininfo2_result_12['info']['lockout_duration']
  255.         if(lockout_duration < 0) then
  256.             lockout_duration = string.format("for %d minutes", querydomaininfo2_result_12['info']['lockout_duration'])
  257.         else
  258.             lockout_duration = "until manually reset"
  259.         end
  260.  
  261.         if(querydomaininfo2_result_12['info']['lockout_threshold'] > 0) then
  262.             response = response .. string.format(" |_ Password lockout: %d attempts in under %d minutes will lock the account %s\n",  querydomaininfo2_result_12['info']['lockout_threshold'], querydomaininfo2_result_12['info']['lockout_window'] / 60, lockout_duration)
  263.         else
  264.             response = response .. string.format(" |_ Account lockout disabled\n")
  265.         end
  266.  
  267.         if(querydomaininfo2_result_1['info']['password_history_length']) > 0 then
  268.             response = response .. string.format(" |_ Password history: %d passwords\n", querydomaininfo2_result_1['info']['password_history_length'])
  269.         end
  270.  
  271.         local password_properties = querydomaininfo2_result_1['info']['password_properties']
  272.         if(#password_properties > 0) then
  273.             response = response .. " |_ Password properties:\n"
  274.             for j = 1, #password_properties, 1 do
  275.                 response = response .. "    |_ " .. msrpc.samr_PasswordProperties_tostr(password_properties[j]) .. "\n"
  276.             end
  277.         end
  278.     end
  279.  
  280.     -- Close the connect handle
  281.     msrpc.samr_close(smbstate, connect_handle)
  282.  
  283.     -- Close the SMB session
  284.     msrpc.stop_smb(smbstate)
  285.  
  286.     return response
  287.  
  288. end
  289.  
  290.  
  291.