metasploit-framework/lib/msf/http/wordpress/helpers.rb

123 lines
4.4 KiB
Ruby

# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Helpers
# Helper methods are private and should not be called by modules
private
# Returns the POST data for a Wordpress login request
#
# @param user [String] Username
# @param pass [String] Password
# @param redirect URL [String] to redirect after successful login
# @return [Hash] The post data for vars_post Parameter
def wordpress_helper_login_post_data(user, pass, redirect=nil)
post_data = {
'log' => user.to_s,
'pwd' => pass.to_s,
'redirect_to' => redirect.to_s,
'wp-submit' => 'Login'
}
post_data
end
# Helper method to post a comment to Wordpress
#
# @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,nil] 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,
'submit' => 'Post+Comment',
'comment_post_ID' => comment_post_id.to_s,
'comment_parent' => '0'
}
vars_post.merge!({
'author' => author,
'email' => email,
'url' => url,
}) unless login_cookie
options = {
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
'method' => 'POST'
}
options.merge!({'vars_post' => vars_post})
options.merge!({'cookie' => login_cookie}) if login_cookie
res = send_request_cgi(options)
if res and (res.code == 301 or res.code == 302) and res.headers['Location']
return wordpress_helper_parse_location_header(res)
else
message = "#{peer} - 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 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,nil] The post id, nil when nothing found
def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled=false, login_cookie=nil)
range.each { |id|
vprint_status("#{peer} - 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
}
# no post found
return nil
end
# Helper method to check if a post is valid an has comments enabled
#
# @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,nil] the HTTP response body of the post, nil otherwise
def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil)
options = {
'method' => 'GET',
'uri' => uri
}
options.merge!({'cookie' => login_cookie}) if login_cookie
res = send_request_cgi(options)
# post exists
if res and res.code == 200
# also check if comments are enabled
if comments_enabled
if res.body =~ /form.*action.*wp-comments-post\.php/
return res.body
else
return nil
end
# valid post found, not checking for comments
else
return res.body
end
elsif res and (res.code == 301 or res.code == 302) and res.headers['Location']
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,nil] 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']
path_from_uri(location)
end
end