133 lines
3.9 KiB
Lua
133 lines
3.9 KiB
Lua
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
|