1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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
|