generate list of popular or all themes
This commit is contained in:
@@ -23,7 +23,7 @@ rescue LoadError => e
|
|||||||
puts "[ERROR] #{e}"
|
puts "[ERROR] #{e}"
|
||||||
|
|
||||||
if missing_gem = e.to_s[%r{ -- ([^\s]+)}, 1]
|
if missing_gem = e.to_s[%r{ -- ([^\s]+)}, 1]
|
||||||
puts "[TIP] Try to run 'gem install #{missing_gem}' or 'gem install --user-install #{missing_gem}'. If you still get an error, Please see README file or http://code.google.com/p/wpscan/"
|
puts "[TIP] Try to run 'gem install #{missing_gem}' or 'gem install --user-install #{missing_gem}'. If you still get an error, Please see README file or https://github.com/wpscanteam/wpscan"
|
||||||
end
|
end
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
#
|
|
||||||
# WPScan - WordPress Security Scanner
|
|
||||||
# Copyright (C) 2011 Ryan Dewhurst AKA ethicalhack3r
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# ryandewhurst at gmail
|
|
||||||
#
|
|
||||||
|
|
||||||
# This tool generates a plugin list to use for plugin enumeration
|
|
||||||
|
|
||||||
class Generate_Plugin_List
|
|
||||||
|
|
||||||
attr_accessor :pages, :verbose
|
|
||||||
|
|
||||||
def initialize(pages, verbose)
|
|
||||||
@pages = pages.to_i
|
|
||||||
@verbose = verbose
|
|
||||||
@browser = Browser.instance
|
|
||||||
@hydra = @browser.hydra
|
|
||||||
end
|
|
||||||
|
|
||||||
# Send a HTTP request to the WordPress most popular plugins webpage
|
|
||||||
# parse the response for the plugin names.
|
|
||||||
|
|
||||||
def parse_popular_plugins
|
|
||||||
|
|
||||||
found_plugins = []
|
|
||||||
page_count = 1
|
|
||||||
queue_count = 0
|
|
||||||
|
|
||||||
(1...@pages).each do |page|
|
|
||||||
|
|
||||||
request = @browser.forge_request('http://wordpress.org/extend/plugins/browse/popular/page/'+page.to_s+'/')
|
|
||||||
|
|
||||||
queue_count += 1
|
|
||||||
|
|
||||||
request.on_complete do |response|
|
|
||||||
puts "[+] Parsing page " + page_count.to_s if @verbose
|
|
||||||
page_count += 1
|
|
||||||
response.body.scan(%r{<h3><a href="http://wordpress.org/extend/plugins/(.*)/">.+</a></h3>}i).each do |plugin|
|
|
||||||
found_plugins << plugin[0]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@hydra.queue(request)
|
|
||||||
|
|
||||||
if queue_count == @browser.max_threads
|
|
||||||
@hydra.run
|
|
||||||
queue_count = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
@hydra.run
|
|
||||||
|
|
||||||
found_plugins.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_full_plugins
|
|
||||||
found_plugins = []
|
|
||||||
index = @browser.get('http://plugins.svn.wordpress.org/').body
|
|
||||||
index.scan(%r{<li><a href=".*">(.*)/</a></li>}i).each do |plugin|
|
|
||||||
found_plugins << plugin[0]
|
|
||||||
end
|
|
||||||
found_plugins.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
# Use the WordPress plugin SVN repo to find a
|
|
||||||
# valid plugin file. This will cut down on
|
|
||||||
# false positives. See issue 39.
|
|
||||||
|
|
||||||
def parse_plugin_files(plugins)
|
|
||||||
|
|
||||||
plugins_with_paths = ""
|
|
||||||
queue_count = 0
|
|
||||||
|
|
||||||
plugins.each do |plugin|
|
|
||||||
|
|
||||||
request = @browser.forge_request('http://plugins.svn.wordpress.org/' + plugin + '/trunk/')
|
|
||||||
|
|
||||||
request.on_complete do |response|
|
|
||||||
|
|
||||||
puts "[+] Parsing plugin " + plugin + " [" + response.code.to_s + "]" if @verbose
|
|
||||||
file = response.body[%r{<li><a href="(\d*?[a-zA-Z].*\..*)">.+</a></li>}i, 1]
|
|
||||||
if file
|
|
||||||
# Only count Plugins with contents
|
|
||||||
plugin += "/" + file
|
|
||||||
plugins_with_paths << plugin + "\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
queue_count += 1
|
|
||||||
@hydra.queue(request)
|
|
||||||
|
|
||||||
# the wordpress server stops
|
|
||||||
# responding if we dont use this.
|
|
||||||
if queue_count == @browser.max_threads
|
|
||||||
@hydra.run
|
|
||||||
queue_count = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
@hydra.run
|
|
||||||
|
|
||||||
plugins_with_paths
|
|
||||||
end
|
|
||||||
|
|
||||||
# Save the file
|
|
||||||
|
|
||||||
def save_file(full=false)
|
|
||||||
begin
|
|
||||||
if (full)
|
|
||||||
plugins = parse_full_plugins
|
|
||||||
else
|
|
||||||
plugins = parse_popular_plugins
|
|
||||||
end
|
|
||||||
puts "[*] We have parsed " + plugins.size.to_s
|
|
||||||
plugins_with_paths = parse_plugin_files(plugins)
|
|
||||||
File.open(DATA_DIR + '/plugins.txt', 'w') { |f| f.write(plugins_with_paths) }
|
|
||||||
puts "New data/plugin.txt file created with " + plugins_with_paths.scan(/\n/).size.to_s + " entries."
|
|
||||||
rescue => e
|
|
||||||
puts "ERROR: Something went wrong :( " + e.inspect
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
128
lib/wpstools/parse_svn.rb
Normal file
128
lib/wpstools/parse_svn.rb
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
#
|
||||||
|
# WPScan - WordPress Security Scanner
|
||||||
|
# Copyright (C) 2012
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# This Class Parses SVN Repositories via HTTP
|
||||||
|
class Svn_Parser
|
||||||
|
|
||||||
|
attr_accessor :verbose, :svn_root, :keep_empty_dirs
|
||||||
|
|
||||||
|
def initialize(svn_root, verbose, keep_empty_dirs = false)
|
||||||
|
@svn_root = svn_root
|
||||||
|
@verbose = verbose
|
||||||
|
@keep_empty_dirs = keep_empty_dirs
|
||||||
|
@svn_browser = Browser.instance
|
||||||
|
@svn_hydra = @svn_browser.hydra
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(dirs = nil)
|
||||||
|
if dirs == nil
|
||||||
|
dirs = get_root_directories
|
||||||
|
end
|
||||||
|
urls = get_svn_project_urls(dirs)
|
||||||
|
entries = get_svn_file_entries(urls)
|
||||||
|
return entries
|
||||||
|
end
|
||||||
|
|
||||||
|
# Gets all directories in the SVN root
|
||||||
|
def get_root_directories
|
||||||
|
dirs = []
|
||||||
|
rootindex = @svn_browser.get(@svn_root).body
|
||||||
|
rootindex.scan(%r{<li><a href=".*">(.*)/</a></li>}i).each do |dir|
|
||||||
|
dirs << dir[0]
|
||||||
|
end
|
||||||
|
dirs.uniq
|
||||||
|
dirs.sort
|
||||||
|
return dirs
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_svn_project_urls(dirs)
|
||||||
|
urls = []
|
||||||
|
queue_count = 0
|
||||||
|
# First get all trunk or version directories
|
||||||
|
dirs.each do |dir|
|
||||||
|
svnurl = @svn_root + dir + "/"
|
||||||
|
request = @svn_browser.forge_request(svnurl)
|
||||||
|
request.on_complete do |response|
|
||||||
|
# trunk folder present
|
||||||
|
if contains_trunk(response)
|
||||||
|
puts "[+] Adding trunk on #{dir}" if @verbose
|
||||||
|
urls << (svnurl << "trunk/")
|
||||||
|
# no trunk folder. This is true on theme svn repos
|
||||||
|
else
|
||||||
|
folders = response.body.scan(%r{^\s*<li><a href="(.*)/">.*/</a></li>$}i)
|
||||||
|
if folders != nil and folders.length > 0
|
||||||
|
last_version = folders.last[0]
|
||||||
|
puts "[+] Adding #{last_version} on #{dir}" if @verbose
|
||||||
|
urls << (svnurl + last_version + "/")
|
||||||
|
else
|
||||||
|
puts "[+] No content in #{dir}" if @verbose
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
queue_count += 1
|
||||||
|
@svn_hydra.queue(request)
|
||||||
|
# the wordpress server stops
|
||||||
|
# responding if we dont use this.
|
||||||
|
if queue_count == @svn_browser.max_threads
|
||||||
|
@svn_hydra.run
|
||||||
|
queue_count = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@svn_hydra.run
|
||||||
|
return urls
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get a file in each directory
|
||||||
|
def get_svn_file_entries(urls)
|
||||||
|
entries = []
|
||||||
|
queue_count = 0
|
||||||
|
urls.each do |url|
|
||||||
|
request = @svn_browser.forge_request(url)
|
||||||
|
request.on_complete do |response|
|
||||||
|
puts "[+] Parsing url #{url} [#{response.code.to_s}]" if @verbose
|
||||||
|
file = response.body[%r{<li><a href="(.*\..*)">.*</a></li>}i, 1]
|
||||||
|
# TODO: recursive parsing of subdirectories if there is no file in the root directory
|
||||||
|
if file
|
||||||
|
url += "/" + file
|
||||||
|
entries << url
|
||||||
|
elsif @keep_empty_dirs
|
||||||
|
entries << url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
queue_count += 1
|
||||||
|
@svn_hydra.queue(request)
|
||||||
|
# the wordpress server stops
|
||||||
|
# responding if we dont use this.
|
||||||
|
if queue_count == @svn_browser.max_threads
|
||||||
|
@svn_hydra.run
|
||||||
|
queue_count = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@svn_hydra.run
|
||||||
|
return entries
|
||||||
|
end
|
||||||
|
|
||||||
|
def contains_trunk(body)
|
||||||
|
contains = false
|
||||||
|
if !!(body =~ %r[<li><a href="trunk/">trunk/</a></li>]i)
|
||||||
|
contains = true
|
||||||
|
end
|
||||||
|
return contains
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -15,6 +15,12 @@ def usage()
|
|||||||
puts "- Generate a new full plugin list"
|
puts "- Generate a new full plugin list"
|
||||||
puts "ruby " + script_name + " --generate_full_plugin_list"
|
puts "ruby " + script_name + " --generate_full_plugin_list"
|
||||||
puts
|
puts
|
||||||
|
puts "- Generate a new 'most popular' theme list, up to 150 pages ..."
|
||||||
|
puts "ruby " + script_name + " --generate_theme_list 150"
|
||||||
|
puts
|
||||||
|
puts "- Generate a new full theme list"
|
||||||
|
puts "ruby " + script_name + " --generate_full_theme_list"
|
||||||
|
puts
|
||||||
puts "See README for further information."
|
puts "See README for further information."
|
||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
@@ -29,5 +35,10 @@ def help()
|
|||||||
puts "--gpl Alias for --generate_plugin_list"
|
puts "--gpl Alias for --generate_plugin_list"
|
||||||
puts "--generate_full_plugin_list Generate a new full data/plugins.txt file"
|
puts "--generate_full_plugin_list Generate a new full data/plugins.txt file"
|
||||||
puts "--gfpl Alias for --generate_full_plugin_list"
|
puts "--gfpl Alias for --generate_full_plugin_list"
|
||||||
|
|
||||||
|
puts "--generate_theme_list [number of pages] Generate a new data/themes.txt file. (supply number of *pages* to parse, default : 150)"
|
||||||
|
puts "--gtl Alias for --generate_theme_list"
|
||||||
|
puts "--generate_full_theme_list Generate a new full data/themes.txt file"
|
||||||
|
puts "--gftl Alias for --generate_full_theme_list"
|
||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ begin
|
|||||||
puts '[+] Finished at ' + Time.now.asctime
|
puts '[+] Finished at ' + Time.now.asctime
|
||||||
exit() # must exit!
|
exit() # must exit!
|
||||||
rescue => e
|
rescue => e
|
||||||
puts "[ERROR] #{e}"
|
puts "[ERROR] #{e.message}"
|
||||||
puts "Trace : #{e.backtrace}"
|
puts "Trace :"
|
||||||
|
puts e.backtrace.join("\n")
|
||||||
end
|
end
|
||||||
|
|||||||
36
wpstools.rb
36
wpstools.rb
@@ -38,8 +38,12 @@ begin
|
|||||||
["--verbose", "-v", GetoptLong::NO_ARGUMENT],
|
["--verbose", "-v", GetoptLong::NO_ARGUMENT],
|
||||||
["--generate_plugin_list", GetoptLong::OPTIONAL_ARGUMENT],
|
["--generate_plugin_list", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
["--generate_full_plugin_list", GetoptLong::NO_ARGUMENT],
|
["--generate_full_plugin_list", GetoptLong::NO_ARGUMENT],
|
||||||
|
["--generate_theme_list", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
|
["--generate_full_theme_list", GetoptLong::NO_ARGUMENT],
|
||||||
["--gpl", GetoptLong::OPTIONAL_ARGUMENT],
|
["--gpl", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
["--gfpl", GetoptLong::OPTIONAL_ARGUMENT],
|
["--gfpl", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
|
["--gtl", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
|
["--gftl", GetoptLong::OPTIONAL_ARGUMENT],
|
||||||
["--update", "-u", GetoptLong::NO_ARGUMENT]
|
["--update", "-u", GetoptLong::NO_ARGUMENT]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,23 +63,46 @@ begin
|
|||||||
end
|
end
|
||||||
|
|
||||||
@generate_plugin_list = true
|
@generate_plugin_list = true
|
||||||
|
when "--generate_theme_list", "--gtl"
|
||||||
|
if argument == ''
|
||||||
|
puts "Number of pages not supplied, defaulting to 150 pages ..."
|
||||||
|
@number_of_pages = 150
|
||||||
|
else
|
||||||
|
@number_of_pages = argument.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
@generate_theme_list = true
|
||||||
when "--update"
|
when "--update"
|
||||||
@update = true
|
@update = true
|
||||||
when "--generate_full_plugin_list", "--gfpl"
|
when "--generate_full_plugin_list", "--gfpl"
|
||||||
@generate_full_plugin_list = true
|
@generate_full_plugin_list = true
|
||||||
|
when "--generate_full_theme_list", "--gftl"
|
||||||
|
@generate_full_theme_list = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if @generate_plugin_list
|
if @generate_plugin_list
|
||||||
puts "[+] Generating new most popular plugin list"
|
puts "[+] Generating new most popular plugin list"
|
||||||
puts
|
puts
|
||||||
Generate_Plugin_List.new(@number_of_pages, @verbose).save_file(false)
|
Generate_List.new('plugins', @verbose).generate_popular_list(@number_of_pages)
|
||||||
end
|
end
|
||||||
|
|
||||||
if @generate_full_plugin_list
|
if @generate_full_plugin_list
|
||||||
puts "[+] Generating new full plugin list"
|
puts "[+] Generating new full plugin list"
|
||||||
puts
|
puts
|
||||||
Generate_Plugin_List.new(-1, @verbose).save_file(true)
|
Generate_List.new('plugins', @verbose).generate_full_list
|
||||||
|
end
|
||||||
|
|
||||||
|
if @generate_theme_list
|
||||||
|
puts "[+] Generating new most popular theme list"
|
||||||
|
puts
|
||||||
|
Generate_List.new('themes', @verbose).generate_popular_list(@number_of_pages)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @generate_full_theme_list
|
||||||
|
puts "[+] Generating new full theme list"
|
||||||
|
puts
|
||||||
|
Generate_List.new('themes', @verbose).generate_full_list
|
||||||
end
|
end
|
||||||
|
|
||||||
if @update
|
if @update
|
||||||
@@ -88,6 +115,7 @@ begin
|
|||||||
end
|
end
|
||||||
|
|
||||||
rescue => e
|
rescue => e
|
||||||
puts "[ERROR] #{e}"
|
puts "[ERROR] #{e.message}"
|
||||||
puts "Trace : #{e.backtrace}"
|
puts "Trace :"
|
||||||
|
puts e.backtrace.join("\n")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user