first feedback implemented
parent
556f17c47e
commit
de3fc1fa6c
|
@ -11,22 +11,17 @@ module Msf::HTTP::Wordpress::Base
|
|||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri)
|
||||
}, 20)
|
||||
if res and res.code == 200
|
||||
if res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
|
||||
return true if res and
|
||||
res.code == 200 and
|
||||
(
|
||||
res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
|
||||
res.body =~ /<link rel=["']wlwmanifest["'].*href=["'].*\/wp-includes\/wlwmanifest\.xml["'] \/>/i or
|
||||
res.body =~ /<link rel=["']pingback["'].*href=["'].*\/xmlrpc\.php["'] \/>/i
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
)
|
||||
return false
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||
print_error("Error connecting to #{target_uri}")
|
||||
return false
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,9 +3,9 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
|
||||
# Returns the POST data for a Wordpress login request
|
||||
#
|
||||
# @param user Usernam
|
||||
# @param pass Password
|
||||
# @param redirect URL to redirect after successful login
|
||||
# @param user [String] Username
|
||||
# @param pass [String] Password
|
||||
# @param redirect URL [String] to redirect after successful login
|
||||
# @return [String] The post data
|
||||
def wordpress_helper_login_post_data(user, pass, redirect=nil)
|
||||
post_data = "log=#{Rex::Text.uri_encode(user.to_s)}"
|
||||
|
@ -17,13 +17,13 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
|
||||
# Helper method to post a comment to Wordpress
|
||||
#
|
||||
# @param comment The comment
|
||||
# @param comment_post_id The Post ID to post the comment to
|
||||
# @param login_cookie The valid login_cookie
|
||||
# @param author The author name
|
||||
# @param email The author email
|
||||
# @param url The author url
|
||||
# @return [String] The location of the new comment/post
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param login_cookie [String] The valid login_cookie
|
||||
# @param author [String] The author name
|
||||
# @param email [String] The author email
|
||||
# @param url [String] The author url
|
||||
# @return [String] The location of the new comment/post, nil on error
|
||||
def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url)
|
||||
vars_post = {
|
||||
'comment' => comment,
|
||||
|
@ -44,21 +44,24 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
options.merge!({'vars_post' => vars_post})
|
||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
||||
res = send_request_cgi(options)
|
||||
if res and res.code == 302
|
||||
location = URI(res.headers['Location'])
|
||||
return location
|
||||
if res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
return wordpress_helper_parse_location_header(res)
|
||||
else
|
||||
message = 'Post comment failed.'
|
||||
message << " Status Code: #{res.code}" if res
|
||||
print_error(message)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method for bruteforcing a valid post id
|
||||
#
|
||||
# @param comments_enabled If true try to find a post id with comments enabled, otherwise return the first found
|
||||
# @param login_cookie A valid login cookie to perform the bruteforce as an authenticated user
|
||||
# @param range [Range] The Range of post_ids to bruteforce
|
||||
# @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found
|
||||
# @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user
|
||||
# @return [Integer] The post id, nil when nothing found
|
||||
def wordpress_helper_get_valid_post_id(comments_enabled=false, login_cookie=nil)
|
||||
(1..1000).each { |id|
|
||||
def wordpress_helper_get_valid_post_id(range, comments_enabled=false, login_cookie=nil)
|
||||
range.each { |id|
|
||||
vprint_status("#{rhost}:#{rport} - Checking POST ID #{id}...") if (id % 100) == 0
|
||||
body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie)
|
||||
return id if body
|
||||
|
@ -69,9 +72,9 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
|
||||
# Helper method to check if a post is valid an has comments enabled
|
||||
#
|
||||
# @param uri the Post URI
|
||||
# @param comments_enabled Check if comments are enabled on this post
|
||||
# @param login_cookie A valid login cookie to perform the check as an authenticated user
|
||||
# @param uri [String] the Post URI Path
|
||||
# @param comments_enabled [Boolean] Check if comments are enabled on this post
|
||||
# @param login_cookie [String] A valid login cookie to perform the check as an authenticated user
|
||||
# @return [String] the HTTP response body of the post, nil otherwise
|
||||
def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil)
|
||||
options = {
|
||||
|
@ -94,11 +97,28 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
return res.body
|
||||
end
|
||||
elsif res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
location = URI(res.headers['Location'])
|
||||
uri = location.path
|
||||
uri << "?#{location.query}" unless location.query.nil? or location.query.empty?
|
||||
return wordpress_helper_check_post_id(uri, comments_enabled, login_cookie)
|
||||
path = wordpress_helper_parse_location_header(res)
|
||||
return wordpress_helper_check_post_id(path, comments_enabled, login_cookie)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Helper method parse a Location header and returns only the path and query. Returns nil on error
|
||||
#
|
||||
# @param res [Rex::Proto::Http::Response] The HTTP response
|
||||
# @return [String] the path and query, nil on error
|
||||
def wordpress_helper_parse_location_header(res)
|
||||
return nil unless res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
|
||||
location = res.headers['Location']
|
||||
begin
|
||||
temp = URI(res.headers['Location'])
|
||||
uri = temp.path
|
||||
uri << "?#{temp.query}" unless temp.query.nil? or temp.query.empty?
|
||||
return uri
|
||||
rescue URI::Error
|
||||
print_error("Invalid Location Header returned (not an URI): #{location}")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,8 @@ module Msf::HTTP::Wordpress::Login
|
|||
|
||||
# performs a wordpress login
|
||||
#
|
||||
# @param user Username
|
||||
# @param pass Password
|
||||
# @param user [String] Username
|
||||
# @param pass [String] Password
|
||||
# @return [String] the session cookie on successful login, nil otherwise
|
||||
def wordpress_login(user, pass)
|
||||
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
|
||||
|
@ -12,7 +12,7 @@ module Msf::HTTP::Wordpress::Login
|
|||
'method' => 'POST',
|
||||
'uri' => wordpress_uri_login,
|
||||
'data' => wordpress_helper_login_post_data(user, pass, redirect),
|
||||
}, 20)
|
||||
})
|
||||
|
||||
if res and res.code == 302 and res.headers['Location'] == redirect
|
||||
match = res.get_cookies.match(/(wordpress(?:_sec)?_logged_in_[^=]+=[^;]+);/i)
|
||||
|
|
|
@ -3,9 +3,9 @@ module Msf::HTTP::Wordpress::Posts
|
|||
|
||||
# Posts a comment as an authenticated user
|
||||
#
|
||||
# @param comment The comment
|
||||
# @param comment_post_id The Post ID to post the comment to
|
||||
# @param login_cookie The valid login_cookie
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param login_cookie [String] The valid login_cookie
|
||||
# @return [String] The location of the new comment/post
|
||||
def wordpress_post_comment_auth(comment, comment_post_id, login_cookie)
|
||||
wordpress_helper_post_comment(comment, comment_post_id, login_cookie, nil, nil, nil)
|
||||
|
@ -13,11 +13,11 @@ module Msf::HTTP::Wordpress::Posts
|
|||
|
||||
# Posts a comment as an unauthenticated user
|
||||
#
|
||||
# @param comment The comment
|
||||
# @param comment_post_id The Post ID to post the comment to
|
||||
# @param author The author name
|
||||
# @param email The author email
|
||||
# @param url The author url
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param author [String] The author name
|
||||
# @param email [String] The author email
|
||||
# @param url [String] The author url
|
||||
# @return [String] The location of the new comment/post
|
||||
def wordpress_post_comment_no_auth(comment, comment_post_id, author, email, url)
|
||||
wordpress_helper_post_comment(comment, comment_post_id, nil, author, email, url)
|
||||
|
@ -25,24 +25,32 @@ module Msf::HTTP::Wordpress::Posts
|
|||
|
||||
# Tries to bruteforce a valid post_id
|
||||
#
|
||||
# @param login_cookie If set perform the bruteforce as an authenticated user
|
||||
# @param min_post_id [Integer] The first post_id to bruteforce
|
||||
# @param max_post_id [Integer] The last post_id to bruteforce
|
||||
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
|
||||
# @return [Integer] The post id, nil when nothing found
|
||||
def wordpress_get_valid_post_id(login_cookie=nil)
|
||||
wordpress_helper_get_valid_post_id(false, login_cookie)
|
||||
def wordpress_get_valid_post_id(min_post_id, max_post_id, login_cookie=nil)
|
||||
return nil if min_post_id > max_post_id
|
||||
range = Range.new(min_post_id, max_post_id)
|
||||
wordpress_helper_get_valid_post_id(range, false, login_cookie)
|
||||
end
|
||||
|
||||
# Tries to bruteforce a valid post_id with comments enabled
|
||||
#
|
||||
# @param login_cookie If set perform the bruteforce as an authenticated user
|
||||
# @param min_post_id [Integer] The first post_id to bruteforce
|
||||
# @param max_post_id [Integer] The last post_id to bruteforce
|
||||
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
|
||||
# @return [Integer] The post id, nil when nothing found
|
||||
def wordpress_get_valid_post_id_with_comments_enabled(login_cookie=nil)
|
||||
wordpress_helper_get_valid_post_id(true, login_cookie)
|
||||
def wordpress_get_valid_post_id_with_comments_enabled(min_post_id, max_post_id, login_cookie=nil)
|
||||
return nil if min_post_id > max_post_id
|
||||
range = Range.new(min_post_id, max_post_id)
|
||||
wordpress_helper_get_valid_post_id(range, true, login_cookie)
|
||||
end
|
||||
|
||||
# Checks if the provided post has comments enabled
|
||||
#
|
||||
# @param post_id The post ID to check
|
||||
# @param login_cookie If set perform the check as an authenticated user
|
||||
# @param post_id [Integer] The post ID to check
|
||||
# @param login_cookie [String] If set perform the check as an authenticated user
|
||||
# @return [String] the HTTP response body of the post, nil otherwise
|
||||
def wordpress_post_comments_enabled?(post_id, login_cookie=nil)
|
||||
wordpress_helper_check_post_id(wordpress_url_post(post_id), true, login_cookie)
|
||||
|
|
|
@ -10,7 +10,7 @@ module Msf::HTTP::Wordpress::URIs
|
|||
|
||||
# Returns the Wordpress Post URL
|
||||
#
|
||||
# @param post_id Post ID
|
||||
# @param post_id [Integer] Post ID
|
||||
# @return [String] Wordpress Post URL
|
||||
def wordpress_url_post(post_id)
|
||||
normalize_uri(target_uri.path) + "/?p=#{post_id}"
|
||||
|
@ -18,7 +18,7 @@ module Msf::HTTP::Wordpress::URIs
|
|||
|
||||
# Returns the Wordpress Author URL
|
||||
#
|
||||
# @param author_id Author ID
|
||||
# @param author_id [Integer] Author ID
|
||||
# @return [String] Wordpress Author URL
|
||||
def wordpress_url_author(author_id)
|
||||
normalize_uri(target_uri.path) + "/?author=#{author_id}"
|
||||
|
|
|
@ -3,14 +3,14 @@ module Msf::HTTP::Wordpress::Users
|
|||
|
||||
# Checks if the given user exists
|
||||
#
|
||||
# @param user Username
|
||||
# @param user [String] Username
|
||||
# @return [Boolean] true if the user exists
|
||||
def wordpress_user_exists?(user)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_uri_login,
|
||||
'data' => wordpress_helper_login_post_data(user, 'x'),
|
||||
}, 20)
|
||||
})
|
||||
|
||||
exists = false
|
||||
if res and res.code == 200
|
||||
|
@ -26,7 +26,7 @@ module Msf::HTTP::Wordpress::Users
|
|||
|
||||
# Checks if the given userid exists
|
||||
#
|
||||
# @param user_id user_id
|
||||
# @param user_id [Integer] user_id
|
||||
# @return [String] the Username if it exists, nil otherwise
|
||||
def wordpress_userid_exists?(user_id)
|
||||
url = wordpress_url_author(user_id)
|
||||
|
|
|
@ -60,6 +60,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
OptString.new('USERNAME', [ false, "The user to authenticate as (anonymous if username not provided)"]),
|
||||
OptString.new('PASSWORD', [ false, "The password to authenticate with (anonymous if password not provided)" ])
|
||||
], self.class)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new('MIN_POST_ID', [ false, 'Specify the first post_id used for bruteforce', 1]),
|
||||
OptInt.new('MAX_POST_ID', [ false, 'Specify the last post_id used for bruteforce', 1000])
|
||||
])
|
||||
end
|
||||
|
||||
def peer
|
||||
|
@ -115,7 +121,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
print_status("#{peer} - Using the user supplied POST ID #{@post_id}...")
|
||||
else
|
||||
print_status("#{peer} - Trying to brute force a valid POST ID...")
|
||||
@post_id = wordpress_get_valid_post_id_with_comments_enabled
|
||||
min_post_id = datastore['MIN_POST_ID']
|
||||
max_post_id = datastore['MAX_POST_ID']
|
||||
@post_id = wordpress_get_valid_post_id_with_comments_enabled(min_post_id, max_post_id, @cookie)
|
||||
if @post_id.nil?
|
||||
fail_with(Failure::BadConfig, "#{peer} - Unable to post without a valid POST ID where comment")
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue