id = "MSRPC: Check vulnerabilities"
description = [[
Checks if a host is vulnerable to MS08-067, a Windows RPC vulnerability that
can allow remote code execution. This script is intended to check for more
vulnerabilities in the future.
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,
the business) understand the risks!
If you set the script parameter 'unsafe', then scripts will run that are almost
(or totally) guaranteed to crash a vulnerable system; do NOT specify unsafe
in a production environment! And that isn't to say that non-unsafe scripts will
not crash a system, they're just less likely to.
MS08-067 -- Checks if a host is vulnerable to MS08-067, a Windows RPC vulnerability that
can allow remote code execution. Checking for MS08-067 is very dangerous, as the check
is likelyto crash systems. On a fairly wide scan conducted by Brandon Enright, we determined
that on average, a vulnerable system is more likely to crash than to survive
the check. Out of 82 vulnerable systems, 52 crashed.
At the same time, MS08-067 is extremely critical to fix. Metasploit has a working and
stable exploit for it, and any system vulnerable can very easily be compromised.
regsvc DoS -- Checks if a host is vulnerable to a crash in regsvc, caused
by a null pointer dereference. I inadvertently discovered this crash while working
on smb-enum-sessions
, and discovered that it was repeatable. It's been
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
.
(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]).
]]
-- Currently, this script checks if a host is vulnerable to ms08-067. I'd like to add
-- checks for more vulnerabilities, but I'm worried about licensing/copyright issues
-- (since I'd be basing them on non-free tools).
---
--@usage
-- nmap --script smb-check-vulns.nse -p445
-- sudo nmap -sU -sS --script smb-check-vulns.nse -p U:137,T:139
--
--@output
-- Host script results:
-- | smb-check-vulns:
-- | MS08-067: FIXED
-- |_ regsvc DoS: VULNERABLE
--
-- @args smb* This script supports the smbusername
,
-- smbpassword
, smbhash
, and smbtype
-- script arguments of the smb
module.
-- @args unsafe If set, this script will run checks that, if the system isn't
-- patched, are basically guaranteed to crash something. Remember that
-- non-unsafe checks aren't necessarily safe either)
-----------------------------------------------------------------------
author = "Ron Bowes"
copyright = "Ron Bowes"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive"}
require 'msrpc'
require 'smb'
require 'stdnse'
hostrule = function(host)
return smb.get_port(host) ~= nil
end
local VULNERABLE = 1
local PATCHED = 2
local UNKNOWN = 3
local NOTRUN = 4
---Check if the server is patched for MS08-067. This is done by calling NetPathCompare with an
-- illegal string. If the string is accepted, then the server is vulnerable; if it's rejected, then
-- you're safe (for now).
--
-- Based on a packet cap of this script, thanks go out to the author:
-- http://labs.portcullis.co.uk/download/ms08-067_check.py
--
-- If there's a licensing issue, please let me (Ron Bowes) know so I can
--
-- NOTE: This CAN crash stuff (ie, crash svchost and force a reboot), so beware! In about 20
-- tests I did, it crashed once. This is not a guarantee.
--
--@param host The host object.
--@return (status, result) If status if alse, result is an error code; otherwise, result is either
-- VULNERABLE
for vulnerable, PATCHED
for not vulnerable, or
-- UNKNOWN
if there was an error (likely vulnerable).
function check_ms08_067(host)
local status, smbstate
local bind_result, netpathcompare_result
-- Create the SMB session
status, smbstate = msrpc.start_smb(host, "\\\\BROWSER")
if(status == false) then
return false, smbstate
end
-- Bind to SRVSVC service
status, bind_result = msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, bind_result
end
-- Call netpathcanonicalize
-- status, netpathcanonicalize_result = msrpc.srvsvc_netpathcanonicalize(smbstate, host.ip, "\\a", "\\test\\")
local path1 = "\\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\..\\n"
local path2 = "\\n"
status, netpathcompare_result = msrpc.srvsvc_netpathcompare(smbstate, host.ip, path1, path2, 1, 0)
-- Stop the SMB session
msrpc.stop_smb(smbstate)
if(status == false) then
if(string.find(netpathcompare_result, "INVALID_NAME") == nil) then
return true, UNKNOWN
else
return true, PATCHED
end
end
return true, VULNERABLE
end
---While writing smb-enum-sessions
I discovered a repeatable null-pointer dereference
-- in regsvc. I reported it to Microsoft, but because it's a simple DoS (and barely even that, because
-- the service automatically restarts), and because it's only in Windows 2000, it isn't likely that they'll
-- fix it. This function checks for that crash (by crashing the process).
--
-- The crash occurs when the string sent to winreg_enumkey() function is null.
--
--@param host The host object.
--@return (status, result) If status if alse, result is an error code; otherwise, result is either
-- VULNERABLE
for vulnerable or PATCHED
for not vulnerable. If the check
-- was skipped, NOTRUN
is returned.
function check_winreg_Enum_crash(host)
local i, j
local elements = {}
if(nmap.registry.args.unsafe == nil) then
return true, NOTRUN
end
-- Create the SMB session
status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH)
if(status == false) then
return false, smbstate
end
-- Bind to WINREG service
status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, bind_result
end
status, openhku_result = msrpc.winreg_openhku(smbstate)
if(status == false) then
msrpc.stop_smb(smbstate)
return false, openhku_result
end
-- Loop through the keys under HKEY_USERS and grab the names
status, enumkey_result = msrpc.winreg_enumkey(smbstate, openhku_result['handle'], 0, nil)
msrpc.stop_smb(smbstate)
if(status == false) then
return true, VULNERABLE
end
return true, PATCHED
end
action = function(host)
local status, result
local response = " \n"
local found = false
-- Check for ms08-067
status, result = check_ms08_067(host)
if(status == false) then
if(nmap.debugging() > 0) then
return "MS08-067: ERROR: " .. result
else
return nil
end
end
if(result == VULNERABLE) then
response = response .. "MS08-067: VULNERABLE\n"
found = true
elseif(result == UNKNOWN) then
response = response .. "MS08-067: LIKELY VULNERABLE (host stopped responding)\n"
else
if(nmap.verbosity() > 0) then
response = response .. "MS08-067: FIXED\n"
end
end
-- Check for a winreg_Enum crash
status, result = check_winreg_Enum_crash(host)
if(status == false) then
if(nmap.debugging() > 0) then
return response .. "regsvc DoS: ERROR: " .. result
else
return nil
end
end
if(result == VULNERABLE) then
response = response .. "regsvc DoS: VULNERABLE\n"
found = true
elseif(result == NOTRUN) then
if(nmap.verbosity() > 0) then
response = response .. "regsvc DoS: NOT RUN (add --script-args=unsafe=1 to run)\n"
end
else
if(nmap.verbosity() > 0) then
response = response .. "regsvc DoS: FIXED\n"
end
end
-- Don't show a response if we aren't verbose and we found nothing
if(nmap.verbosity() == 0 and found == false) then
response = nil
end
return response
end