Module: WPScan::Target::Platform::WordPress
- Includes:
- CMSScanner::Target::Platform::PHP
- Included in:
- WPScan::Target
- Defined in:
- lib/wpscan/target/platform/wordpress.rb,
lib/wpscan/target/platform/wordpress/custom_directories.rb
Overview
wp-content & plugins directory implementation
Constant Summary collapse
- WORDPRESS_PATTERN =
%r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
- COOKIE_PATTERNS =
{ 'vjs' => /createCookie\('vjs','(?<c_value>\d+)',\d+\);/i }.freeze
Instance Attribute Summary collapse
-
#mu_plugins ⇒ Object
(also: #mu_plugins?)
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again.
-
#multisite ⇒ Object
(also: #multisite?)
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again.
-
#registration_enabled ⇒ Object
(also: #registration_enabled?)
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again.
Instance Method Summary collapse
-
#content_dir(detection_mode = :mixed) ⇒ String
The wp-content directory.
- #content_dir=(dir) ⇒ Object
- #content_uri ⇒ Addressable::URI
- #content_url ⇒ String
- #default_content_dir_exists? ⇒ Boolean
- #do_login(username, password) ⇒ Typhoeus::Response
- #login_request(username, password) ⇒ Typhoeus::Request
-
#login_url ⇒ String
The login page is checked for a potential redirection (from http to https) the first time the method is called, and the effective_url is then used if suitable, otherwise the default wp-login will be.
-
#maybe_add_cookies ⇒ Object
Sometimes there is a mechanism in place on the blog, which requires a specific cookie and value to be added to requests.
- #plugin_url(slug) ⇒ String
- #plugins_dir ⇒ String
- #plugins_dir=(dir) ⇒ Object
- #plugins_uri ⇒ Addressable::URI
- #plugins_url ⇒ String
- #registration_url ⇒ String
-
#sub_dir ⇒ String, False
@note: nil can not be returned here, otherwise if there is no sub_dir the check would be done each time, which would make enumeration of long list of items very slow to generate.
- #theme_url(slug) ⇒ String
- #themes_dir ⇒ String
- #themes_uri ⇒ Addressable::URI
- #themes_url ⇒ String
-
#url(path = nil) ⇒ String
Override of the WebSite#url to consider the custom WP directories.
- #wordpress?(detection_mode) ⇒ Boolean
-
#wordpress_hosted? ⇒ Boolean
Whether or not the target is hosted on wordpress.com.
Instance Attribute Details
#mu_plugins ⇒ Object Also known as: mu_plugins?
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again
18 19 20 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 18 def mu_plugins @mu_plugins end |
#multisite ⇒ Object Also known as: multisite?
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again
18 19 20 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 18 def multisite @multisite end |
#registration_enabled ⇒ Object Also known as: registration_enabled?
These methods are used in the associated interesting_findings finders to keep the boolean state of the finding rather than re-check the whole thing again
18 19 20 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 18 def registration_enabled @registration_enabled end |
Instance Method Details
#content_dir(detection_mode = :mixed) ⇒ String
Returns The wp-content directory.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 18 def content_dir(detection_mode = :mixed) unless @content_dir # scope_url_pattern is from CMSScanner::Target pattern = %r{#{scope_url_pattern}([\w\s\-/]+)\\?/(?:themes|plugins|uploads|cache)\\?/}i in_scope_uris(homepage_res) do |uri| return @content_dir = Regexp.last_match[1] if uri.to_s.match(pattern) end # Checks for the pattern in raw JS code, as well as @content attributes of meta tags xpath_pattern_from_page('//script[not(@src)]|//meta/@content', pattern, homepage_res) do |match| return @content_dir = match[1] end unless detection_mode == :passive return @content_dir = 'wp-content' if default_content_dir_exists? end end @content_dir end |
#content_dir=(dir) ⇒ Object
8 9 10 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 8 def content_dir=(dir) @content_dir = dir.chomp('/') end |
#content_uri ⇒ Addressable::URI
47 48 49 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 47 def content_uri uri.join("#{content_dir}/") end |
#content_url ⇒ String
52 53 54 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 52 def content_url content_uri.to_s end |
#default_content_dir_exists? ⇒ Boolean
40 41 42 43 44 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 40 def default_content_dir_exists? # url('wp-content') can't be used here as the folder has not yet been identified # and the method would try to replace it by nil which would raise an error [200, 401, 403].include?(Browser.forge_request(uri.join('wp-content/').to_s, head_or_get_params).run.code) end |
#do_login(username, password) ⇒ Typhoeus::Response
100 101 102 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 100 def do_login(username, password) login_request(username, password).run end |
#login_request(username, password) ⇒ Typhoeus::Request
108 109 110 111 112 113 114 115 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 108 def login_request(username, password) Browser.instance.forge_request( login_url, method: :post, cache_ttl: 0, body: { log: username, pwd: password } ) end |
#login_url ⇒ String
The login page is checked for a potential redirection (from http to https) the first time the method is called, and the effective_url is then used if suitable, otherwise the default wp-login will be.
122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 122 def login_url return @login_url if @login_url @login_url = url('wp-login.php') res = Browser.get_and_follow_location(@login_url) @login_url = res.effective_url if res.effective_url =~ /wp\-login\.php\z/i && in_scope?(res.effective_url) @login_url end |
#maybe_add_cookies ⇒ Object
Sometimes there is a mechanism in place on the blog, which requires a specific cookie and value to be added to requests. Lets try to detect and add them
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 54 def COOKIE_PATTERNS.each do |, pattern| next unless homepage_res.body =~ pattern browser = Browser.instance = "#{}=#{Regexp.last_match[:c_value]}" += "; #{browser.}" if browser. browser. = # Force recheck of the homepage when retying wordpress? # No need to clear the cache, as the request (which will contain the cookies) # will be different @homepage_res = nil @homepage_url = nil break end end |
#plugin_url(slug) ⇒ String
74 75 76 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 74 def plugin_url(slug) plugins_uri.join("#{URI.encode(slug)}/").to_s end |
#plugins_dir ⇒ String
57 58 59 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 57 def plugins_dir @plugins_dir ||= "#{content_dir}/plugins" end |
#plugins_dir=(dir) ⇒ Object
12 13 14 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 12 def plugins_dir=(dir) @plugins_dir = dir.chomp('/') end |
#plugins_uri ⇒ Addressable::URI
62 63 64 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 62 def plugins_uri uri.join("#{plugins_dir}/") end |
#plugins_url ⇒ String
67 68 69 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 67 def plugins_url plugins_uri.to_s end |
#registration_url ⇒ String
77 78 79 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 77 def registration_url multisite? ? url('wp-signup.php') : url('wp-login.php?action=register') end |
#sub_dir ⇒ String, False
@note: nil can not be returned here, otherwise if there is no sub_dir
the check would be done each time, which would make enumeration of
long list of items very slow to generate
104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 104 def sub_dir return @sub_dir unless @sub_dir.nil? # url_pattern is from CMSScanner::Target pattern = %r{#{url_pattern}(.+?)/(?:xmlrpc\.php|wp\-includes/)}i in_scope_uris(homepage_res) do |uri| return @sub_dir = Regexp.last_match[1] if uri.to_s.match(pattern) end @sub_dir = false end |
#theme_url(slug) ⇒ String
96 97 98 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 96 def theme_url(slug) themes_uri.join("#{URI.encode(slug)}/").to_s end |
#themes_dir ⇒ String
79 80 81 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 79 def themes_dir @themes_dir ||= "#{content_dir}/themes" end |
#themes_uri ⇒ Addressable::URI
84 85 86 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 84 def themes_uri uri.join("#{themes_dir}/") end |
#themes_url ⇒ String
89 90 91 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 89 def themes_url themes_uri.to_s end |
#url(path = nil) ⇒ String
Override of the WebSite#url to consider the custom WP directories
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/wpscan/target/platform/wordpress/custom_directories.rb', line 122 def url(path = nil) return @uri.to_s unless path if %r{wp\-content/plugins}i.match?(path) path = +path.gsub('wp-content/plugins', plugins_dir) elsif /wp\-content/i.match?(path) path = +path.gsub('wp-content', content_dir) elsif path[0] != '/' && sub_dir path = "#{sub_dir}/#{path}" end super(path) end |
#wordpress?(detection_mode) ⇒ Boolean
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 26 def wordpress?(detection_mode) in_scope_uris(homepage_res) do |uri| return true if uri.path.match(WORDPRESS_PATTERN) end homepage_res.html.css('meta[name="generator"]').each do |node| return true if /wordpress/i.match?(node['content']) end return true unless comments_from_page(/wordpress/i, homepage_res).empty? if %i[mixed aggressive].include?(detection_mode) %w[wp-admin/install.php wp-login.php].each do |path| in_scope_uris(Browser.get_and_follow_location(url(path))).each do |uri| return true if uri.path.match(WORDPRESS_PATTERN) end end end false end |
#wordpress_hosted? ⇒ Boolean
Returns Whether or not the target is hosted on wordpress.com.
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/wpscan/target/platform/wordpress.rb', line 82 def wordpress_hosted? return true if /\.wordpress\.com$/i.match?(uri.host) unless content_dir(:passive) pattern = %r{https?://s\d\.wp\.com#{WORDPRESS_PATTERN}}i.freeze uris_from_page(homepage_res) do |uri| return true if uri.to_s.match?(pattern) end end false end |