diff options
Diffstat (limited to 'scripts/smb-os-discovery.nse')
-rw-r--r-- | scripts/smb-os-discovery.nse | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/scripts/smb-os-discovery.nse b/scripts/smb-os-discovery.nse new file mode 100644 index 0000000..8799415 --- /dev/null +++ b/scripts/smb-os-discovery.nse @@ -0,0 +1,220 @@ +local nmap = require "nmap" +local smb = require "smb" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" +local os = require "os" +local datetime = require "datetime" + +description = [[ +Attempts to determine the operating system, computer name, domain, workgroup, and current +time over the SMB protocol (ports 445 or 139). +This is done by starting a session with the anonymous +account (or with a proper user account, if one is given; it likely doesn't make +a difference); in response to a session starting, the server will send back all this +information. + +The following fields may be included in the output, depending on the +circumstances (e.g. the workgroup name is mutually exclusive with domain and forest +names) and the information available: +* OS +* Computer name +* Domain name +* Forest name +* FQDN +* NetBIOS computer name +* NetBIOS domain name +* Workgroup +* System time + +Some systems, like Samba, will blank out their name (and only send their domain). +Other systems (like embedded printers) will simply leave out the information. Other +systems will blank out various pieces (some will send back 0 for the current +time, for example). + +If this script is used in conjunction with version detection it can augment the +standard nmap version detection information with data that this script has discovered. + +Retrieving the name and operating system of a server is a vital step in targeting +an attack against it, and this script makes that retrieval easy. Additionally, if +a penetration tester is choosing between multiple targets, the time can help identify +servers that are being poorly maintained (for more information/random thoughts on +using the time, see http://www.skullsecurity.org/blog/?p=76. + +Although the standard <code>smb*</code> script arguments can be used, +they likely won't change the outcome in any meaningful way. However, <code>smbnoguest</code> +will speed up the script on targets that do not allow guest access. +]] + +--- +--@usage +-- nmap --script smb-os-discovery.nse -p445 127.0.0.1 +-- sudo nmap -sU -sS --script smb-os-discovery.nse -p U:137,T:139 127.0.0.1 +-- +--@output +-- Host script results: +-- | smb-os-discovery: +-- | OS: Windows Server (R) 2008 Standard 6001 Service Pack 1 (Windows Server (R) 2008 Standard 6.0) +-- | OS CPE: cpe:/o:microsoft:windows_2008::sp1 +-- | Computer name: Sql2008 +-- | NetBIOS computer name: SQL2008 +-- | Domain name: lab.test.local +-- | Forest name: test.local +-- | FQDN: Sql2008.lab.test.local +-- | NetBIOS domain name: LAB +-- |_ System time: 2011-04-20T13:34:06-05:00 +-- +--@xmloutput +-- <elem key="os">Windows Server (R) 2008 Standard 6001 Service Pack 1</elem> +-- <elem key="cpe">cpe:/o:microsoft:windows_2008::sp1</elem> +-- <elem key="lanmanager">Windows Server (R) 2008 Standard 6.0</elem> +-- <elem key="domain">LAB</elem> +-- <elem key="server">SQL2008</elem> +-- <elem key="date">2011-04-20T13:34:06-05:00</elem> +-- <elem key="fqdn">Sql2008.lab.test.local</elem> +-- <elem key="domain_dns">lab.test.local</elem> +-- <elem key="forest_dns">test.local</elem> + +author = "Ron Bowes" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"default", "discovery", "safe"} +dependencies = {"smb-brute"} + + +--- Check whether or not this script should be run. +hostrule = function(host) + return smb.get_port(host) ~= nil +end + +-- Some observed OS strings: +-- "Windows 5.0" (is Windows 2000) +-- "Windows 5.1" (is Windows XP) +-- "Windows Server 2003 3790 Service Pack 2" +-- "Windows Vista (TM) Ultimate 6000" +-- "Windows Server (R) 2008 Standard 6001 Service Pack 1" +-- "Windows 7 Professional 7601 Service Pack 1" +-- http://msdn.microsoft.com/en-us/library/cc246806%28v=prot.20%29.aspx has a +-- list of strings that don't quite match these. +function make_cpe(result) + local os = result.os + local parts = {} + + if string.match(os, "^Windows 5%.0") then + parts = {"o", "microsoft", "windows_2000"} + elseif string.match(os, "^Windows 5%.1") then + parts = {"o", "microsoft", "windows_xp"} + elseif string.match(os, "^Windows Server.*2003") then + parts = {"o", "microsoft", "windows_server_2003"} + elseif string.match(os, "^Windows Vista") then + parts = {"o", "microsoft", "windows_vista"} + elseif string.match(os, "^Windows Server.*2008") then + parts = {"o", "microsoft", "windows_server_2008"} + elseif string.match(os, "^Windows 7") then + parts = {"o", "microsoft", "windows_7"} + elseif string.match(os, "^Windows 8%f[^%d.]") then + parts = {"o", "microsoft", "windows_8"} + elseif string.match(os, "^Windows 8.1") then + parts = {"o", "microsoft", "windows_8.1"} + elseif string.match(os, "^Windows 10%f[^%d.]") then + parts = {"o", "microsoft", "windows_10"} + elseif string.match(os, "^Windows Server.*2012") then + parts = {"o", "microsoft", "windows_server_2012"} + end + + if parts[1] == "o" and parts[2] == "microsoft" + and string.match(parts[3], "^windows") then + parts[4] = "" + local sp = string.match(os, "Service Pack (%d+)") + if sp then + parts[5] = "sp" .. tostring(sp) + else + parts[5] = "-" + end + if string.match(os, "Professional") then + parts[6] = "professional" + end + end + + if #parts > 0 then + return "cpe:/" .. table.concat(parts, ":") + end +end + +function add_to_output(output_table, label, value) + if value then + table.insert(output_table, string.format("%s: %s", label, value)) + end +end + +action = function(host) + local response = stdnse.output_table() + local request_time = os.time() + local status, result = smb.get_os(host) + + if(status == false) then + return stdnse.format_output(false, result) + end + + -- Collect results. + response.os = result.os + response.lanmanager = result.lanmanager + response.domain = result.domain + response.server = result.server + if result.time and result.timezone then + response.date = datetime.format_timestamp(result.time, result.timezone * 60 * 60) + datetime.record_skew(host, result.time - result.timezone * 60 * 60, request_time) + end + response.fqdn = result.fqdn + response.domain_dns = result.domain_dns + response.forest_dns = result.forest_dns + response.workgroup = result.workgroup + response.cpe = make_cpe(result) + + -- Build normal output. + local output_lines = {} + if response.os and response.lanmanager then + add_to_output(output_lines, "OS", string.format("%s (%s)", smb.get_windows_version(response.os), response.lanmanager)) + else + add_to_output(output_lines, "OS", "Unknown") + end + add_to_output(output_lines, "OS CPE", response.cpe) + if response.fqdn then + -- Pull the first part of the FQDN as the computer name. + add_to_output(output_lines, "Computer name", string.match(response.fqdn, "^([^.]+)%.?")) + end + add_to_output(output_lines, "NetBIOS computer name", result.server) + if response.fqdn and response.domain_dns and response.fqdn ~= response.domain_dns then + -- If the FQDN doesn't match the domain name, the target is a domain member. + add_to_output(output_lines, "Domain name", response.domain_dns) + add_to_output(output_lines, "Forest name", response.forest_dns) + add_to_output(output_lines, "FQDN", response.fqdn) + add_to_output(output_lines, "NetBIOS domain name", response.domain) + else + add_to_output(output_lines, "Workgroup", response.workgroup or response.domain) + end + add_to_output(output_lines, "System time", response.date or "Unknown") + + -- Augment service version detection + if result.port and response.lanmanager then + local proto + if result.port == 445 or result.port == 139 then + proto = 'tcp' + else + proto = 'udp' + end + + local port = nmap.get_port_state(host,{number=result.port,protocol=proto}) + + local version, product + if string.match(response.lanmanager,"^Samba ") then + port.version.product = 'Samba smbd' + port.version.version = string.match(response.lanmanager,"^Samba (.*)") + nmap.set_port_version(host,port) + elseif smb.get_windows_version(response.os) then + port.version.product = string.format("%s %s",smb.get_windows_version(response.os), port.version.name) + nmap.set_port_version(host,port) + end + end + + return response, stdnse.format_output(true, output_lines) +end |