summaryrefslogtreecommitdiffstats
path: root/scripts/http-svn-info.nse
blob: 257d38ca3ddfae39bcc70c11203bd7c05d2bde00 (plain)
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
local http = require "http"
local shortport = require "shortport"
local slaxml = require "slaxml"
local stdnse = require "stdnse"

description = [[Requests information from a Subversion repository.
]]

---
-- @usage nmap --script http-svn-info <target>
--
-- @args http-svn-info.url This is a URL relative to the scanned host eg. /default.html (default: /)
--
-- @output
-- 443/tcp open  https   syn-ack
-- | http-svn-info:
-- |   Path: .
-- |   URL: https://svn.nmap.org/
-- |   Relative URL: ^/
-- |   Repository Root: https://svn.nmap.org
-- |   Repository UUID: e0a8ed71-7df4-0310-8962-fdc924857419
-- |   Revision: 34938
-- |   Node Kind: directory
-- |   Last Changed Author: yang
-- |   Last Changed Rev: 34938
-- |_  Last Changed Date: Sun, 19 Jul 2015 13:49:59 GMT--
--
-- @xmloutput
-- <elem key="Path">.</elem>
-- <elem key="URL">https://svn.nmap.org/</elem>
-- <elem key="Relative URL">^/</elem>
-- <elem key="Repository Root">https://svn.nmap.org</elem>
-- <elem key="Repository UUID">e0a8ed71-7df4-0310-8962-fdc924857419</elem>
-- <elem key="Revision">34938</elem>
-- <elem key="Node Kind">directory</elem>
-- <elem key="Last Changed Author">yang</elem>
-- <elem key="Last Changed Rev">34938</elem>
-- <elem key="Last Changed Date">Sun, 19 Jul 2015 13:49:59 GMT</elem>


author = "Gyanendra Mishra"

license = "Same as Nmap--See https://nmap.org/book/man-legal.html"

categories = {"default", "discovery", "safe"}


portrule = shortport.http

local ELEMENTS = {
    ["repository-uuid"] =  "Repository UUID",
    ["version-name"] = "Last Changed Rev",
    ["creator-displayname"] = "Last Changed Author",
    ["getlastmodified"] = "Last Changed Date",
    ["baseline-relative-path"] = "Relative URL",
    ["href"] = "Repository Root",
    ["getcontentlength"] = "file"
}

local output_order = {
  "Last Changed Author",
  "Last Changed Rev",
  "Last Changed Date",
}

local function get_text_callback(store, name)
  if ELEMENTS[name] == nil then return end
  return function(content) store[ELEMENTS[name]] = content end
end

action = function(host, port)

  local url = stdnse.get_script_args(SCRIPT_NAME .. ".url") or "/"
  local output = {}
  local ordered_output = stdnse.output_table()

  local options = {
    header = {
      ["Depth"] = 0,
    },
  }

  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 = get_text_callback(output, name) end,
      closeElement = function(name) parser._call.text = function() return nil end end
    }
    parser:parseSAX(response.body, {stripWhitespace=true})

    if next(output) then

      ordered_output["Path"] = url:match("/([^/]*)$"):len() > 0 and url:match("/([^/]*)$") or url:match("/([^/]*)/$") or "."
      if output["file"] then
        ordered_output["Name"] = url:match("/([^/]*)$")
      end

      ordered_output["URL"] = host.targetname and port.service .. "://" .. host.targetname .. url
      ordered_output["Relative URL"] = output["Relative URL"] and "^/" .. output["Relative URL"] or "^/"
      output["Repository Root"] = output["Repository Root"]:gsub("%/%!svn.*", ""):len() > 0 and output["Repository Root"]:gsub("%/%!svn.*", "")  or "/"
      ordered_output["Repository Root"] = port.service .. "://" .. host.targetname .. output["Repository Root"]
      ordered_output["Repository UUID"] = output["Repository UUID"]
      if url ~= output["Repository Root"] then
        local temp_output = {}
        response = http.generic_request(host, port, "PROPFIND", output["Repository Root"], options)
        if response and response.status == 207 then
          parser._call.startElement = function(name) parser._call.text = get_text_callback(temp_output, name) end
          parser:parseSAX(response.body, {stripWhitespace=true})
          ordered_output["Revision"] = temp_output["Last Changed Rev"]
        end
      else
        ordered_output["Revision"] = output["Last Changed Rev"]
      end

      if not output["file"] then
        ordered_output["Node Kind"] = "directory"
      else
        ordered_output["Node Kind"] = "file"
      end

      for _, value in ipairs(output_order) do
        ordered_output[value] = output[value]
      end

      return ordered_output
    end
  end
end