This paper was published in Oakland 2015. In this paper, the author introduced COOP (Conterfeit Object Oriented Programming) to bypass the virtual table integrity check and coarse-grained CFI. In COOP, it takes a whole virtual function in C++ code as a gadget to launch the attack. Since the state-of-art CFI does not have a deep knowledge of the semantics of the binary code in C++ and the state-of-art vtable enforcement does not take vtable reuse attack into consideration, COOP attack is hard to be distinguished from benign execution of the program.
In COOP, it is assumed that
(1) The attacker can hijack C++ objects and its vptr (by heap overflow or use-after-free)
(2) The attacker can infer the base of address of libraries and heap.
Counterfeit Object and Vfgadget
Each counterfeit object is a basic component in COOP. Usually, a counterfeit object carries an attacker-chosen vptr and a few attacker-chosen data fields. Counterfeit objects are not created by the target application, but are injected in bulk by the attacker. In COOP, payload consists of conterfeit object and possibly additional data.
Virtual functions used in COOP are called vfgadgets. And the table below introduces different types of vfgadgets used in COOP.
Design of COOP
Main Loop Gadget
In order to invoke functions repeatedly in COOP, the first step is to identify a loop to call virtual functions again and again, which is ML-G. Attacker can chain a series of vfgadgets to launch attack via ML-G.
The following picture shows a virtual destruction function in a class named Student. In this function, a for loop is used to chain various kinds of vfgadget by preparing the crafted vptr of each student[i].
In COOP, the attack needs to craft the whole data layout of the Student class, including the students and nStudents.
Arithmetic Gadget and Writing Gadget
Next, in order to write attacker-chosen data to a memory, the paper uses arithmetic gadget (ARITH-G) and writing gadget (W-G) shown as below.
The key idea here is to overlap two counterfeit object in the memory. In this example, the score field of class Exam and buffer field are overlapped in memory.
Argument Loading Gadget
Then we have to control the arguments of the function invoked. In the examples above, we want to control the value of the s in SimpleString::set(char* s). And the approaches are different on different platforms.
On windows x64 platform, the the first four (non-floating point) arguments to a function are passed through the registers rcx, rdx, r8, and r9.
Thus the paper takes vfgadgets that can be used to load argument registers as LOAD-R64-G as below:
The assembly code of the gadget is shown above. We can find that the register r8 and r9 are both used as scratch registers to store some values under attacker’s control. Later these values may be used somewhere else as argument register.
On windows x86, the arguments of a function is passed through stack, and the arguments of the function will be removed (pop) after the function returns. Thus on x86 system, an alternative is needed to pass the argument.
Thus the paper introduces another gadgets: ML-ARG-G as below.
This time, it uses id, a member variable, of class Course2 as the argument of the function called.
Memory Setting Gadget
The paper also introduces some approaches to set memory for setting argument register at attacker’s will for argument loading gadgets.
Approach 1: Fix the argument field to point to a writable scratch data with W-SA-G gadget. W-SA-G and its assembly code is given below:
To put it simple, the W-SA-G given above allows the attacker to write 16 byte to any given address.
Approach 2: Dynamically rewrite the argument field.Use a W-G to dynamically write data into a memory, and use another overlapping counterfeit object to call the function in another iteration of ML-ARG-G.
Invoke Critical API
For writing exploit, it is necessary to call WinAPI sometimes. And the paper describes three approaches:
Approach 1: Use a vfgadget that legitimately calls the WinAPI function of interest. This approach is practical in some situations, but it’s hard to find WinAPI, like WinExec(), in vfgadget.
Approach 2: Invoke the WinAPI function like a virtual function from the COOP main loop. Craft a conterfeit object, whosr vptr it pointed to the import table or export table of a loaded module.
Approach 3:Use a vfgadget that calls a C-style function pointer. In C, code pointer are taken as a pointer in the source code, thus a C-style function can be overwritten to WinAPI function, and the gadget is referred as INV-G shown as below:
Implementing a COOP attack against an application is a three-step process:
(1)Identification of vfgadgets
(2)Implementation of attack semantics using the identified vfgadget
(3)Arrangement of the possibly overlapping counterfeit objects in a buffer
The effectiveness of COOP against most of the state-of-art mitigations is the most encouraging part of this paper as given below:
vtable reuse attack is indeed an interesting technique in exploitation development. More to come…
One thought on “Counterfeit Object-oriented Programming”
[…] on windows platform, I rewrite the exploit to make it work on Linux platform and test some ideas on vtable reuse attacks. I use a chain of multiple virtual function gadgets to change memory protection and open a […]