diff options
Diffstat (limited to 'scripts/http-svn-enum.nse')
-rw-r--r-- | scripts/http-svn-enum.nse | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/scripts/http-svn-enum.nse b/scripts/http-svn-enum.nse new file mode 100644 index 0000000..4a23113 --- /dev/null +++ b/scripts/http-svn-enum.nse @@ -0,0 +1,132 @@ +local http = require "http" +local shortport = require "shortport" +local slaxml = require "slaxml" +local stdnse = require "stdnse" +local tab = require "tab" + +description = [[Enumerates users of a Subversion repository by examining logs of most recent commits. +]] + +--- +-- @usage nmap --script http-svn-enum <target> +-- +-- @args http-svn-enum.count The number of logs to fetch. Defaults to the last 1000 commits. +-- @args http-svn-enum.url This is a URL relative to the scanned host eg. /default.html (default: /). +-- +-- @output +-- PORT STATE SERVICE REASON +-- 443/tcp open https syn-ack +-- | http-svn-enum: +-- | Author Count Revision Date +-- | gyani 183 34965 2015-07-24 +-- | robert 1 34566 2015-06-02 +-- | david 2 34785 2015-06-28 +-- +-- @xmloutput +-- <table></table> +-- <table> +-- <elem>Author</elem> +-- <elem>Count</elem> +-- <elem>Revision</elem> +-- <elem>Date</elem> +-- </table> +-- <table> +-- <elem>gyani</elem> +-- <elem>183</elem> +-- <elem>34965</elem> +-- <elem>2015-07-24</elem> +-- </table> +-- <table> +-- <elem>robert</elem> +-- <elem>1</elem> +-- <elem>34566</elem> +-- <elem>2015-06-02</elem> +-- </table> +-- <table> +-- <elem>david</elem> +-- <elem>2</elem> +-- <elem>34785</elem> +-- <elem>2015-06-28</elem> +-- </table> + +author = "Gyanendra Mishra" + +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" + +categories = {"default", "discovery", "safe"} + +local ELEMENTS = { + ["creator-displayname"] = "author", + ["version-name"] = "version", + ["date"] = "date", +} + +local function get_callback(name, unames, temp) + if ELEMENTS[name] then + return function(content) + if not content then content = "unknown" end --useful for "nil" authors + temp[ELEMENTS[name]] = name == "date" and content:sub(1, 10) or content + if temp.date and temp.version and temp.author then + unames[temp.author] = {unames[temp.author] and unames[temp.author][1] + 1 or 1, temp.version, temp.date} + end + end + end +end + +portrule = shortport.http + +action = function(host, port) + + local count = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".count")) or 1000 + local url = stdnse.get_script_args(SCRIPT_NAME .. ".url") or "/" + local output, revision, unames = tab.new(), nil, {} + + local options = { + header = { + ["Depth"] = 0, + }, + } + + -- first we fetch the current revision number + local response = http.generic_request(host, port, "PROPFIND", url, options) + if response and response.status == 207 then + + local parser = slaxml.parser:new() + parser._call = {startElement = function(name) + parser._call.text = name == "version-name" and function(content) revision = tonumber(content) end end, + closeElement = function(name) parser._call.text = function() return nil end end + } + parser:parseSAX(response.body, {stripWhitespace=true}) + + if revision then + + local start_revision = revision > count and revision - count or 1 + local content = '<?xml version="1.0"?> <S:log-report xmlns:S="svn:"> <S:start-revision>'.. start_revision .. '</S:start-revision> <S:discover-changed-paths/> </S:log-report>' + + options = { + header = { + ["Depth"] = 1, + }, + content = content, + } + + local temp = {} + response = http.generic_request(host, port, "REPORT", url, options) + if response and response.status == 200 then + + parser._call.startElement = function(name) parser._call.text = get_callback(name, unames, temp) end + parser._call.closeElement = function(name) if name == "log-item" then temp ={} end parser._call.text = function() return nil end end + parser:parseSAX(response.body, {stripWhitespace=true}) + + tab.nextrow(output) + tab.addrow(output, "Author", "Count", "Revision", "Date") + + for revision_author, data in pairs(unames) do + tab.addrow(output, revision_author, data[1], data[2], data[3]) + end + + if next(unames) then return output end + end + end + end +end |