mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 13:11:28 +00:00
renamed http-wp-enum and http-wp-plugins to http-wordpress-* for consistency with the naming of http-wordpress-brute
This commit is contained in:
160
scripts/http-wordpress-plugins.nse
Normal file
160
scripts/http-wordpress-plugins.nse
Normal file
@@ -0,0 +1,160 @@
|
||||
description = [[
|
||||
Tries to obtain a list of installed WordPress plugins by brute force
|
||||
testing for known plugins.
|
||||
|
||||
The script will brute force the /wp-content/plugins/ folder with a dictionnary
|
||||
of 14K (and counting) known WP plugins. Anything but a 404 means that a given
|
||||
plugin directory probably exists, so the plugin probably also does.
|
||||
|
||||
The available plugins for Wordpress is huge and despite the efforts of Nmap to
|
||||
parallelize the queries, a whole search could take an hour or so. That's why
|
||||
the plugin list is sorted by popularity and by default the script will only
|
||||
check the first 100 ones. Users can tweak this with an option (see below).
|
||||
]]
|
||||
|
||||
---
|
||||
-- @args http-wordpress-plugins.root If set, points to the blog root directory on the website. If not, the script will try to find a WP directory installation or fall back to root.
|
||||
-- @args http-wordpress-plugins.search As the plugins list contains tens of thousand of plugins, this script will only search the 100 most popular ones by default.
|
||||
-- Use this option with a number or "all" as an argument for a more comprehensive brute force.
|
||||
--
|
||||
-- @usage
|
||||
-- nmap --script=http-wordpress-plugins --script-arg http-wordpress-plugins.root="/blog/",http-wordpress-plugins.search=500 <targets>
|
||||
--
|
||||
--@output
|
||||
-- Interesting ports on my.woot.blog (123.123.123.123):
|
||||
-- PORT STATE SERVICE REASON
|
||||
-- 80/tcp open http syn-ack
|
||||
-- | http-wordpress-plugins:
|
||||
-- | search amongst the 500 most popular plugins
|
||||
-- | akismet
|
||||
-- | wp-db-backup
|
||||
-- | all-in-one-seo-pack
|
||||
-- | stats
|
||||
-- |_ wp-to-twitter
|
||||
|
||||
author = "Ange Gutek"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery", "intrusive"}
|
||||
|
||||
require 'http'
|
||||
require 'stdnse'
|
||||
require 'shortport'
|
||||
|
||||
local DEFAULT_PLUGINS_SEARCH = 100
|
||||
|
||||
|
||||
portrule = shortport.service("http")
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local result = {}
|
||||
local all = {}
|
||||
local bfqueries = {}
|
||||
|
||||
--Check if the wp plugins list exists
|
||||
local wp_plugins_file = nmap.fetchfile("nselib/data/wp-plugins.lst")
|
||||
if not wp_plugins_file then
|
||||
return false, "Couldn't find wp-plugins.lst (should be in nselib/data)"
|
||||
end
|
||||
|
||||
local file = io.open(wp_plugins_file, "r")
|
||||
if not file then
|
||||
return false, "Couldn't find wp-plugins.lst (should be in nselib/data)"
|
||||
end
|
||||
|
||||
local wp_autoroot
|
||||
local wp_root = stdnse.get_script_args("http-wordpress-plugins.root")
|
||||
local plugins_search = DEFAULT_PLUGINS_SEARCH
|
||||
local plugins_search_arg = stdnse.get_script_args("http-wordpress-plugins.search")
|
||||
|
||||
if plugins_search_arg == "all" then
|
||||
plugins_search = nil
|
||||
elseif plugins_search_arg then
|
||||
plugins_search = tonumber(plugins_search_arg)
|
||||
end
|
||||
|
||||
stdnse.print_debug(1, "%s plugins search range: %s", SCRIPT_NAME, plugins_search or "unlimited")
|
||||
|
||||
|
||||
-- search the website root for evidences of a Wordpress path
|
||||
if not wp_root then
|
||||
local target_index = http.get(host,port, "/")
|
||||
|
||||
if target_index.status and target_index.body then
|
||||
wp_autoroot = string.match(target_index.body, "http://[%w%-%.]-/([%w%-%./]-)wp%-content")
|
||||
if wp_autoroot then
|
||||
wp_autoroot = "/" .. wp_autoroot
|
||||
stdnse.print_debug(1, "%s WP root directory: %s", SCRIPT_NAME, wp_autoroot)
|
||||
else
|
||||
stdnse.print_debug(1, "%s WP root directory: wp_autoroot was unable to find a WP content dir (root page returns %d).", SCRIPT_NAME, target_index.status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--identify the 404
|
||||
local status_404, result_404, body_404 = http.identify_404(host, port)
|
||||
if not status_404 then
|
||||
stdnse.print_debug(1, "%s unable to handle 404 pages (%s)", SCRIPT_NAME, result_404)
|
||||
end
|
||||
|
||||
|
||||
--build a table of both directories to brute force and the corresponding WP plugins' name
|
||||
local plugin_count = 0
|
||||
while true do
|
||||
local line = file:read()
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
|
||||
if plugins_search and plugin_count >= plugins_search then
|
||||
break
|
||||
end
|
||||
|
||||
local target
|
||||
if wp_root then
|
||||
-- Give user-supplied argument the priority
|
||||
target = wp_root .. "/wp-content/plugins/" .. line .. "/"
|
||||
elseif wp_autoroot then
|
||||
-- Maybe the script has discovered another Wordpress content directory
|
||||
target = wp_autoroot .. "wp-content/plugins/" .. line .. "/"
|
||||
else
|
||||
-- Default WP directory is root
|
||||
target = "/wp-content/plugins/" .. line .. "/"
|
||||
end
|
||||
|
||||
|
||||
target = string.gsub(target, "//", "/")
|
||||
table.insert(bfqueries, {target, line})
|
||||
all = http.pipeline_add(target, nil, all, "GET")
|
||||
plugin_count = plugin_count + 1
|
||||
|
||||
end
|
||||
|
||||
-- release hell...
|
||||
local pipeline_returns = http.pipeline_go(host, port, all)
|
||||
if not pipeline_returns then
|
||||
stdnse.print_debug(1, "%s : got no answers from pipelined queries", SCRIPT_NAME)
|
||||
end
|
||||
|
||||
for i, data in pairs(pipeline_returns) do
|
||||
-- if it's not a four-'o-four, it probably means that the plugin is present
|
||||
if http.page_exists(data, result_404, body_404, bfqueries[i][1], true) then
|
||||
stdnse.print_debug(1, "http-wordpress-plugins.nse: Found a plugin: %s", bfqueries[i][2])
|
||||
table.insert(result, bfqueries[i][2])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if #result > 0 then
|
||||
result.name = "search amongst the " .. plugin_count .. " most popular plugins"
|
||||
return stdnse.format_output(true, result)
|
||||
else
|
||||
return "nothing found amongst the " .. plugin_count .. " most popular plugins, use --script-arg http-wordpress-plugins.search=<number|all> for deeper analysis)\n"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user