local msrpc = require "msrpc"
local nmap = require "nmap"
local smb = require "smb"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local vulns = require "vulns"
description = [[
Checks for vulnerability:
* MS08-067, a Windows RPC vulnerability
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!
As a system administrator, performing these kinds of checks is crucial, because
a lot more damage can be done by a worm or a hacker using this vulnerability than
by a scanner. Penetration testers, on the other hand, might not want to use this
script -- crashing services is not generally a good way of sneaking through a
network.
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.
If you set the script parameter safe
, then script will run that rarely or never
crash a vulnerable system. No promises, though.
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 likely to 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.
Conficker. Checks if a host is infected with a known Conficker strain. This check
is based on the simple conficker scanner found on this page:
http://iv.cs.uni-bonn.de/wg/cs/applications/containing-conficker.
Thanks to the folks who wrote that scanner!
]]
---
--@usage
-- nmap --script smb-vuln-ms08-067.nse -p445
-- sudo nmap -sU -sS --script ssmb-vuln-ms08-067.nse -p U:137,T:139
--
--@output
-- Host script results:
-- | smb-check-vulns:
-- |_ MS08-067: NOT 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
-- non-unsafe checks aren't necessarily safe either)
-- @args safe If set, this script will only run checks that are known (or at
-- least suspected) to be safe.
-----------------------------------------------------------------------
author = "Ron Bowes"
copyright = "Ron Bowes"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive","exploit","dos","vuln"}
-- run after all smb-* scripts (so if it DOES crash something, it doesn't kill
-- other scans have had a chance to run)
dependencies = {
"smb-brute", "smb-enum-sessions", "smb-security-mode",
"smb-enum-shares", "smb-server-stats",
"smb-enum-domains", "smb-enum-users", "smb-system-info",
"smb-enum-groups", "smb-os-discovery", "smb-enum-processes",
"smb-psexec",
};
hostrule = function(host)
return smb.get_port(host) ~= nil
end
local VULNERABLE = 1
local PATCHED = 2
local UNKNOWN = 3
local NOTRUN = 4
local INFECTED = 5
local INFECTED2 = 6
local CLEAN = 7
local NOTUP = 8
---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/application/ms08-067-check/
--
-- 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 is false, result is an error code; otherwise, result is either
-- VULNERABLE
for vulnerable, PATCHED
for not vulnerable,
-- UNKNOWN
if there was an error (likely vulnerable), NOTRUN
-- if this check was disabled, and INFECTED
if it was patched by Conficker.
function check_ms08_067(host)
--check for safety flag
if(nmap.registry.args.safe ~= nil) then
return true, NOTRUN
end
if(nmap.registry.args.unsafe == nil) then
return true, NOTRUN
end
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, "WERR_INVALID_PARAMETER") ~= nil) then
return true, INFECTED
elseif(string.find(netpathcompare_result, "INVALID_NAME") ~= nil) then
return true, PATCHED
else
return true, UNKNOWN, netpathcompare_result
end
end
return true, VULNERABLE
end
-- Help messages for the more common errors seen by the Conficker check.
CONFICKER_ERROR_HELP = {
["NT_STATUS_BAD_NETWORK_NAME"] =
[[UNKNOWN; Network name not found (required service has crashed). (Error NT_STATUS_BAD_NETWORK_NAME)]],
-- http://seclists.org/nmap-dev/2009/q1/0918.html "non-Windows boxes (Samba on Linux/OS X, or a printer)"
-- http://www.skullsecurity.org/blog/?p=209#comment-156
-- "That means either it isn’t a Windows machine, or the service is
-- either crashed or not running. That may indicate a failed (or
-- successful) exploit attempt, or just a locked down system.
-- NT_STATUS_OBJECT_NAME_NOT_FOUND can be returned if the browser
-- service is disabled. There are at least two ways that can happen:
-- 1) The service itself is disabled in the services list.
-- 2) The registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Browser\Parameters\MaintainServerList
-- is set to Off/False/No rather than Auto or yes.
-- On these systems, if you reenable the browser service, then the
-- test will complete."
["NT_STATUS_OBJECT_NAME_NOT_FOUND"] =
[[UNKNOWN; not Windows, or Windows with disabled browser service (CLEAN); or Windows with crashed browser service (possibly INFECTED).
| If you know the remote system is Windows, try rebooting it and scanning
|_ again. (Error NT_STATUS_OBJECT_NAME_NOT_FOUND)]],
-- http://www.skullsecurity.org/blog/?p=209#comment-100
-- "That likely means that the server has been locked down, so we
-- don’t have access to the necessary pipe. Fortunately, that means
-- that neither does Conficker — NT_STATUS_ACCESS_DENIED probably
-- means you’re ok."
["NT_STATUS_ACCESS_DENIED"] =
[[Likely CLEAN; access was denied.
| If you have a login, try using --script-args=smbuser=xxx,smbpass=yyy
| (replace xxx and yyy with your username and password). Also try
|_ smbdomain=zzz if you know the domain. (Error NT_STATUS_ACCESS_DENIED)]],
-- The cause of these two is still unknown.
-- ["NT_STATUS_NOT_SUPPORTED"] =
-- [[]]
-- http://thatsbroken.com/?cat=5 (doesn't seem common)
-- ["NT_STATUS_REQUEST_NOT_ACCEPTED"] =
-- [[]]
}
action = function(host)
local status, result, message
local response = {}
local vuln_report = vulns.Report:new(SCRIPT_NAME, host)
local vuln_table = {
title = 'Vulnerability in Server service could allow remote code execution (MS08-067)',
state = vulns.STATE.NOT_VULN,
description = [[
The Server service in Microsoft Windows 2000 SP4, XP SP2 and SP3, Server 2003 SP1 and SP2,
Vista Gold and SP1, Server 2008, and 7 Pre-Beta allows remote attackers to execute arbitrary
code via a crafted RPC request that triggers the overflow during path canonicalization, as exploited
in the wild by Gimmiv.A in October 2008, aka "Server Service Vulnerability."
]],
IDS = {CVE = 'CVE-2008-4250'},
references = {
'https://technet.microsoft.com/en-us/library/security/ms08-067.aspx'
},
dates = {
disclosure = {year = '2008', month = '10', day = '23'},
}
}
-- Check for ms08-067
status, result, message = check_ms08_067(host)
if(status == false) then
-- table.insert(response, get_response("MS08-067", "ERROR", result, 0, 1))
vuln_table.state = vulns.STATE.NOT_VULN
else
if(result == VULNERABLE) then
vuln_table.state = vulns.STATE.VULN
elseif(result == UNKNOWN) then
-- table.insert(response, get_response("MS08-067", "LIKELY VULNERABLE", "host stopped responding", 1)) -- TODO: this isn't very accurate
vuln_table.state = vulns.STATE.LIKELY_VULN
elseif(result == NOTRUN) then
vuln_table.state = vulns.STATE.LIKELY_VULN
vuln_table.check_results = "CHECK DISABLED. Add '--script-args=unsafe=1' to run"
elseif(result == INFECTED) then
-- table.insert(response, get_response("MS08-067", "NOT VULNERABLE", "likely by Conficker", 0))
vuln_table.state = vulns.STATE.NOT_VULN
else
-- table.insert(response, get_response("MS08-067", "NOT VULNERABLE", nil, 1))
vuln_table.state = vulns.STATE.NOT_VULN
end
end
return vuln_report:make_output(vuln_table)
end