diff --git a/CHANGELOG b/CHANGELOG index e8147b926..d039507a8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,7 +52,7 @@ o Integrated all of your service/version detection fingerprints submitted from telnet, and ftp to jute, bgp, and slurm. Highlights: http://seclists.org/nmap-dev/2015/q2/171 [Daniel Miller] -o [NSE] Added 25 NSE scripts from 17 authors, bringing the total up to 495. +o [NSE] Added 26 NSE scripts from 17 authors, bringing the total up to 495. They are all listed at http://nmap.org/nsedoc/, and the summaries are below (authors are listed in brackets): @@ -89,6 +89,8 @@ o [NSE] Added 25 NSE scripts from 17 authors, bringing the total up to 495. + http-vuln-cve2015-1427 detects Elasticsearch servers vulnerable to remote code execution. [Gyanendra Mishra] + + http-webdav-scan detects WebDAV installations. [Gyanendra Mishra] + + http-vuln-cve2015-1635 detects Microsoft Windows systems vulnerable to MS15-034. [Paulino Calderon] diff --git a/scripts/http-webdav-scan.nse b/scripts/http-webdav-scan.nse new file mode 100644 index 000000000..2a53596b8 --- /dev/null +++ b/scripts/http-webdav-scan.nse @@ -0,0 +1,195 @@ +local http = require "http" +local table = require "table" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" + +description = [[ +A script to detect WebDAV installations. Uses the OPTIONS and PROPFIND methods. + +The script sends an OPTIONS request which lists the dav type, server type, date +and allowed methods. It then sends a PROPFIND request and tries to fetch exposed +directories and internal ip addresses by doing pattern matching in the response body. + +This script takes inspiration from the various scripts listed here: + *http://carnal0wnage.attackresearch.com/2010/05/more-with-metasploit-and-webdav.html + *https://github.com/sussurro/Metasploit-Tools/blob/master/modules/auxiliary/scanner/http/webdav_test.rb + *http://code.google.com/p/davtest/ +]] + +--- +-- @usage +-- nmap --script http-webdav-scan -p80,8080 +-- +-- @output +-- PORT STATE SERVICE +-- 8008/tcp open http +-- | http-webdav-scan: +-- | Allowed Methods: GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE, REPORT +-- | Server Type: DAV/0.9.8 Python/2.7.6 +-- | Server Date: Fri, 22 May 2015 19:28:00 GMT +-- | WebDAV type: unkown +-- | Directory Listing: +-- | http://localhosft +-- | http://localhost:8008/WebDAVTest_b1tqTWeyRR +-- | http://localhost:8008/WebDAVTest_A0QWJb7hcK +-- | http://localhost:8008/WebDAVTest_hf9Mqqpi1M +-- | http://localhost:8008/WebDAVTest_Ds5KBFywDq +-- +-- @args path The path to start in; eg, "/web/" will try "/web/xxx". +-- +-- @xmloutput +-- GET, HEAD, COPY, MOVE, POST, PUT, +-- PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE, REPORT +-- DAV/0.9.8 Python/2.7.6 +-- Fri, 22 May 2015 19:28:00 GMT +-- unkown +-- +-- http://localhost +-- http://localhost:8008/WebDAVTest_b1tqTWeyRR +-- http://localhost:8008/WebDAVTest_A0QWJb7hcK +-- http://localhost:8008/WebDAVTest_hf9Mqqpi1M +-- http://localhost:8008/WebDAVTest_Ds5KBFywDq +--
+ +----------------------------------------------------------------------- + +author = "Gyanendra Mishra" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = { + "safe", + "discovery", + "default", +} + + +portrule = shortport.http + +-- a function to test the OPTIONS method. +local function get_options (host, port, path) + -- check if WebDAV is installed or not. + local response = http.generic_request(host, port, "OPTIONS", path) + if response and response.status == 200 then + local ret = {} + ret['Server Type'] = response.header['server'] + ret['Allowed Methods'] = response.header['allow'] + ret['Public Options'] = response.header['public'] + ret['WebDAV'] = false + ret['Server Date'] = response.header['date'] + + if response.header['dav'] and response.header['dav']:find('1') then + ret['WebDAV'] = true + ret['WebDAV type'] = 'Unkown' + if response.header['X-MSDAVEXT'] then + ret['WebDAV type'] = 'SHAREPOINT DAV' + end + if response.header['dav']:match 'apache' then + ret['WebDAV type'] = 'Apache DAV' + end + end + return ret + + else + return false + end +end + + +local function validateIP(matched_ip) + local oct_1, oct_2, oct_3, oct_4 = matched_ip:match('(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d)%.(%d%d?%d?)') + if tonumber(oct_1) > 255 or tonumber(oct_2) > 255 or tonumber(oct_3) > 255 or tonumber(oct_4) > 255 then + return false + end + return true +end + +-- a function to extract internal ip addresses from PROPFIND response. +local function getIPs(body) + local ip_pat1 = '192%.168%.%d+%.%d+' + local ip_pat2 = '10%.%d+%.%d+%.%d+' + local ip_pat3 = '172%.%d+%.%d+%.%d+' + local ip_pats = { + ip_pat1, + ip_pat2, + ip_pat3, + } + local result = {} + for _, ip_pat in pairs(ip_pats) do + for ip in body:gmatch(ip_pat) do + if validateIP(ip) then + result[ip] = true + end + end + end + return stdnse.keys(result) +end + +-- a function to test the PROPFIND method. +local function check_propfind (host, port, path) + local options = { + header = { + ["Depth"] = 1, + ["Content-Length"] = 0, + }, + } + local response = http.generic_request(host, port, "PROPFIND", path, options) + if response and response.status ~= 207 then + return false + end + local ret = {} + ret['WebDAV'] = false + local dir_pat = '<.-[hH][rR][eE][fF][^>]->(.-)' + if response.body:find 'HTTP/1.1 200 OK' then + ret['WebDAV'] = true + end + ret['Server Type'] = response.header['server'] + ret['Server Date'] = response.header['date'] + local ips = getIPs(response.body) + if next(ips) then ret['Exposed Internal IPs'] = getIPs(response.body) end + if response.body:gmatch(dir_pat) then + ret['Directory Listing'] = {} + for dir in response.body:gmatch(dir_pat) do + table.insert(ret['Directory Listing'], dir) + end + end + return ret +end + +function action (host, port) + + local path = stdnse.get_script_args(SCRIPT_NAME .. ".path") or '/' + local enabled = false + local output = stdnse.output_table() + + local info = get_options(host, port, path) + if info then + if info['WebDAV'] then + enabled = true + stdnse.debug1("Target has WebDAV enabled.") + for name, data in pairs(info) do + if name ~= 'WebDAV' then + output[name] = data + end + end + else + stdnse.debug1 "Target isn't reporting WebDAV" + end + end + + local davinfo = check_propfind(host, port, path) + if davinfo then + if davinfo['WebDAV'] then + for name, data in pairs(davinfo) do + if not output[name] and name ~= 'WebDAV' then + output[name] = data + end + end + if not enabled then + stdnse.debug1 "Target has WebDAV enabled." + end + end + end + + if #output > 0 then return output else return nil end +end + diff --git a/scripts/script.db b/scripts/script.db index 82626df23..64fb6efb6 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -242,6 +242,7 @@ Entry { filename = "http-vuln-misfortune-cookie.nse", categories = { "intrusive" Entry { filename = "http-vuln-wnr1000-creds.nse", categories = { "exploit", "intrusive", "vuln", } } Entry { filename = "http-waf-detect.nse", categories = { "discovery", "intrusive", } } Entry { filename = "http-waf-fingerprint.nse", categories = { "discovery", "intrusive", } } +Entry { filename = "http-webdav-scan.nse", categories = { "default", "discovery", "safe" } } Entry { filename = "http-wordpress-brute.nse", categories = { "brute", "intrusive", } } Entry { filename = "http-wordpress-enum.nse", categories = { "discovery", "intrusive", } } Entry { filename = "http-wordpress-users.nse", categories = { "auth", "intrusive", "vuln", } }