summaryrefslogtreecommitdiffstats
path: root/scripts/http-gitweb-projects-enum.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/http-gitweb-projects-enum.nse')
-rw-r--r--scripts/http-gitweb-projects-enum.nse106
1 files changed, 106 insertions, 0 deletions
diff --git a/scripts/http-gitweb-projects-enum.nse b/scripts/http-gitweb-projects-enum.nse
new file mode 100644
index 0000000..306fb33
--- /dev/null
+++ b/scripts/http-gitweb-projects-enum.nse
@@ -0,0 +1,106 @@
+local http = require "http"
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+local string = require "string"
+local tab = require "tab"
+local table = require "table"
+
+description=[[
+Retrieves a list of Git projects, owners and descriptions from a gitweb (web interface to the Git revision control system).
+]]
+
+---
+-- @usage
+-- nmap -p80 www.example.com --script http-gitweb-projects-enum
+--
+-- @output
+-- 80/tcp open http
+-- | http-gitweb-projects-enum:
+-- | Projects from gitweb.samba.org:
+-- | PROJECT AUTHOR DESCRIPTION
+-- | sando.git authornum1 no description
+-- | camui/san.git devteam no description
+-- | albert/tdx.git/.git blueteam no description
+-- |
+-- | Number of projects: 172
+-- |_ Number of owners: 42
+--
+-- @args http-gitweb-projects-enum.path specifies the location of gitweb
+-- (default: /)
+
+author = "riemann"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"discovery", "safe"}
+
+
+portrule = shortport.http
+
+---
+-- @param author bloc (if author name are too long we have a span bloc)
+-- @return author name filtred from html entities
+---
+get_owner = function(res)
+ local result=res
+ local _
+ if ( res:match('<span') ) then
+ _,_,result=string.find(res,'title="(.-)"')
+ end
+ return result
+end
+
+action = function(host, port)
+
+ local path = stdnse.get_script_args(SCRIPT_NAME .. '.path') or '/'
+ local response = http.get(host,port,path)
+ local result, result_stats = {}, {}
+
+ if not response or not response.status or response.status ~= 200 or
+ not response.body then
+ stdnse.debug1("Failed to retrieve file: %s", path)
+ return
+ end
+
+ local html = response.body
+ local repo=tab.new()
+ tab.addrow(repo,'PROJECT','AUTHOR','DESCRIPTION')
+
+ -- verif generator
+ if (html:match('meta name="generator" content="gitweb(.-)"')) then
+ result['name'] = string.format("Projects from %s:", host.targetname or host.ip)
+
+ local owners, projects_counter, owners_counter = {}, 0, 0
+
+ for tr_code in html:gmatch('(%<tr[^<>]*%>(.-)%</tr%>)') do
+ local regx='<a[^<>]*href="(.-)">(.-)</a>(.-)title="(.-)"(.-)<i>(.-)</i>'
+ for _, project, _, desc, _, owner in tr_code:gmatch(regx) do
+
+ --if desc result return default text of gitweb replace it by no description
+ if(string.find(desc,'Unnamed repository')) then
+ desc='no description'
+ end
+
+ tab.addrow(repo, project, get_owner(owner), desc)
+
+ -- Protect from parsing errors or long owners
+ -- just an arbitrary value
+ if owner:len() < 128 and not owners[owner] then
+ owners[owner] = true
+ owners_counter = owners_counter + 1
+ end
+
+ projects_counter = projects_counter + 1
+ end
+ end
+
+ table.insert(result,tab.dump(repo))
+ table.insert(result, "")
+ table.insert(result,
+ string.format("Number of projects: %d", projects_counter))
+ if (owners_counter > 0 ) then
+ table.insert(result,
+ string.format("Number of owners: %d", owners_counter))
+ end
+
+ end
+ return stdnse.format_output(true,result)
+end