Counterfeit Objectoriented Programming COOP On the Difficulty of
Counterfeit Object-oriented Programming (COOP) On the Difficulty of Preventing Code Reuse Attacks in C++ Applications F. Schuster, T. Tendyck, C. Liebcheny, L. Daviy, A. -R. Sadeghiy, T. Holz. 2015 2018 -11 -05 Bauer Sandro 1
Table of contents • Introduction & Background • COOP • Re-Visitation, Evaluation and Conclusion • Discussion 2018 -11 -05 Bauer Sandro 2
C++ virtual functions class B { // base public: virtual void f(); }; class D : public B { // derived private: void f(); }; int main() { D dobj; B* bptr = &dobj; D* dptr = &dobj; // valid, virtual B: : f() is public, // D: : f() is called bptr->f(); class A { public: int x; char *y; class B { public: int x; char *y; void f(); }; virtual void f(); }; object: A object: B B: : v. Table x: int vptr &B: : f y: char* x: int … y: char* read-only // error, D: : f() is private dptr->f(); } 2018 -11 -05 Bauer Sandro 3
Preconditions (= same for ROP) 1. Hijack C++ object and it’s existing vptr. • By exploiting a spatial or temporal memory corruption vulnerability • buffer overflow • use-after-free 2. Gaining (partial) knowledge on the application’s address space layout. 2018 -11 -05 Bauer Sandro 4
Existing code-reuse attacks 1. 2. 3. 4. 5. Branch to code locations Use ret out of order Inject or manipulate existing code pointers Execute excessively many indirect branches Pivot the stack pointer Defenses rely on these characteristics 2018 -11 -05 Bauer Sandro 5
Defenses Memory safety Control-flow integrity Code shuffling, rewriting, hiding Heuristics Binary code • Cling • CFI + shadow call stack • CCFIR • O-CFI • vf. Guard • T-VIP • VTint • STIR • Smashing The Gadgets • k. Bouncer • EMET • ROPecker Source code • • 2018 -11 -05 CPI CPS Soft. Bound WIT • • GCC VTV LLVM IFCC Safe. Dispatch Windows CFG Bauer Sandro • G-Free • Xn. R • Readactor 6
What is COOP? • 2015 presented novel code reuse attack against applications developed in C++ • Exclusively relies on C++ virtual functions • Execute malicious program by only invoking chains of existing C++ virtual functions (using different v. Tables) • Turing complete 2018 -11 -05 Bauer Sandro 7
Counterfeit Objects • Injected by the attacker. • Payload carries counterfeit C++ objects and possibly additional data. • ROP: Payload carries fake return addresses and additional data. Attacker injects counterfeit stack. • Both: Payload typically written as one coherent chunk to single attacker-controlled memory location. 2018 -11 -05 Bauer Sandro 8
vfgadgets (virtual function gadgets) • Identification through source code analysis or reverse engineering of binary code. • Determine actual object layout of a vfgadget’s class on binary level (compiler may remove or pad certain fields). vfgadget type Purpose ML-G The main loop; iterate over container of pointers to counterfeit object and invoke a virtual function on each such object. ARITH-G Perform arithmetic or logical operation. W-G Write to chosen address. R-G Read from chosen address. INV-G Invoke C-style function pointer. W-COND-G Conditionally write to chosen address. Used to implement conditional branching. ML-ARG-G Execute vfgadgets in a loop and pass a field of the initial object to each as argument. W-SA-G Write to address pointed to by first argument. Used to write to scratch area. MOVE-SP-G Decrease/increase stack pointer. LOAD-R 64 -G Load argument register rdx, r 8, or r 9 with value (x 64 only). 2018 -11 -05 Bauer Sandro 9
Main Loop Gadget (ML-G) • Loop to call virtual functions repeatably. • Control flow in COOP Initial attackercontrolled vcall Main Loop vfgadget #1 vfgadget #2 …. 2018 -11 -05 class Student { public: virtual void inc. Course. Count() = 0; virtual void dec. Course. Count() = 0; }; class Course { private: Student **students; size_t n. Students; public: /*. . . */ virtual ~Course() { for (size_t i = 0; i < n. Students; i++) students[i]->dec. Course. Count(); delete students; ML-G } }; Bauer Sandro 10
Counterfeit vptrs • Control and data flow in a COOP attack should resemble those of a regular C++ program. Avoid introducing fake vtables, reuse existing ones. • Vptrs of all counterfeit objects should point to the beginning of existing vtables. 2018 -11 -05 Bauer Sandro 11
Overlapping Counterfeit Gadgets, Arithmetic Gadget and Writing Gadget Injected counterfeit object vptr size_t score. A size_t score. B size_t score. C … size_t score Injected counterfeit object + vptr char *buffer size_t len strncpy( dest 2018 -11 -05 src num ) class Exam { private: size_t score. A, score. B, score. C; public: /*. . . */ char *topic; size_t score; virtual void update. Absolute. Score() { score = score. A + score. B + score. C; ARITH-G } virtual float get. Weighted. Score() { return (float)(score. A*5+score. B*3+score. C*2) / 10; } }; struct Simple. String { char* buffer; size_t len; /*. . . */ virtual void set(char* s) { strncpy(buffer, s, len); W-G } }; Bauer Sandro 12
Overlapping Counterfeit Gadgets, Arithmetic Gadget and Writing Gadget Injected counterfeit object vptr size_t score. A size_t score. B size_t score. C … size_t score Injected counterfeit object + vptr char *buffer size_t len strncpy( dest 2018 -11 -05 src num ) Bauer Sandro 13
Passing arguments to vfgadgets: Argument Loading Gadget class Student 2 { private: class Exam { std: : list<Exam> exams; private: public: size_t score. A, score. B, score. C; /*. . . */ public: virtual void subscribe. Course(int id) { /*. . . */ } /*. . . */ virtual void unsubscribe. Course(int id) { /*. . . */ } char *topic; virtual bool get. Latest. Exam(Exam &e) { size_t score; if (exams. empty()) return false; virtual void update. Absolute. Score() { e = exams. back(); score = score. A + score. B + score. C; return true; } } virtual float get. Weighted. Score() { }; return (float)(score. A*5+score. B*3+score. C*2) / 10; class Course 2 { } LOAD-R 64 -G private: }; Student 2 **students; struct Simple. String { size_t n. Students; char* buffer; needed. int id; size_t len; public: /*. . . */ virtual void set(char* s) { virtual ~Course 2() { strncpy(buffer, s, len); for (size_t i = 0; i < n. Students; i++) } students[i]->unsubscribe. Course(id); }; delete students; } ML-ARG-G Bauer Sandro 14 }; • Control arguments of the invoked function. • On Windows x 64, the first 4 (non-floating point) arguments to a function are passed through the registers rcx, rdx, r 8, and r 9. use these to pass arguments mov rax, qword ptr [rcx+10 h] • On x 86, the arguments are passed mov. Windows r 8, qword ptr [rcx+18 h] xorps xmm 0, xmm 0 through the stack, and will be removed lea rdx, [rax+rax*2] (pop) after the returns. mov rax, qword ptrfunction [rcx+8] lea rcx, [rax+rax*4] Alternative to pass arguments lea r 9, [rdx+r 8*2] add r 9, rcx cvtsi 2 ss xmm 0, r 9 addss xmm 0, dword ptr [__real 0] divss xmm 0, dword ptr [__real 1] ret 2018 -11 -05 is
Memory Setting Gadget push ebp mov ebp, esp cmp dword ptr [ecx+8], 0 jne copy. Exam xor al, al pop ebp ret 4 copy. Exam: mov eax, dword ptr [ecx+4] mov ecx, dword ptr [ebp+8] mov edx, dword ptr [eax+4] mov eax, dword ptr [edx+0 Ch] mov dword ptr [ecx+4], eax mov eax, dword ptr [edx+10 h] mov dword ptr [ecx+8], eax mov eax, dword ptr [edx+14 h] mov dword ptr [ecx+0 Ch], eax mov eax, dword ptr [edx+18 h] mov dword ptr [ecx+10 h], eax mov al, 1 pop ebp ret 4 class Student 2 { private: std: : list<Exam> exams; public: /*. . . */ virtual void subscribe. Course(int id) { /*. . . */ } virtual void unsubscribe. Course(int id) { /*. . . */ } virtual bool get. Latest. Exam(Exam &e) { W-SA-G if (exams. empty()) return false; e = exams. back(); return true; } }; class Course 2 { private: Student 2 **students; size_t n. Students; int id; public: /*. . . */ virtual ~Course 2() { for (size_t i = 0; i < n. Students; i++) students[i]->unsubscribe. Course(id); delete students; } Bauer Sandro 15 }; • Approach 1: Fix the argument field to point to a writable scratch data with W-SA-G. • Approach 2: Dynamically rewrite the argument field. Use a W-G to dynamically write data into memory, use another overlapping counterfeit object to call the function in another iteration of MLARG-G. 2018 -11 -05
Implementation 1. Identification of vfgadgets 2. Implementation of attack semantics using the identified vfgadgets 3. Arrangement of possibly overlapping counterfeit objects in a buffer 2018 -11 -05 Bauer Sandro 16
Applicability and Turing Completeness • Requires at least a minimum set of vfgadgets. • Examples: • mshtml. dll (~ 20 MB, IE on Windows) • libxul. so (~ 60 MB, Firefox on Linux) • basic vfgadget types ARITH-G, W-G, R-G, LOAD-R 64 -G, and W-SA-G common in even smaller binaries • msvcp 120. dll / msvcr 120. dll (< 1 MB, dynamically linked standard C/C++ runtime libraries) contain ML-G/ML-ARG-G • Applicable to popular C++ applications on different operating systems and hardware architectures. • Implementation of a Turing machine with these gadgets. • Even loops can be implemented under realistic conditions. 2018 -11 -05 Bauer Sandro 17
Existing code-reuse attacks COOP does not execute strange instruction sequences 1. Branch to code locations does not 2. Use ret out of order 3. Inject or manipulate existing code pointers (only vptrs to read-only memory) not execute strange instruction 4. Execute excessively many indirect branches does sequences does not 5. Pivot the stack pointer Defenses rely on these characteristics Therefore …. 2018 -11 -05 Bauer Sandro 18
COOP is immune against • Plain protection of code pointers • Semantics-preserving rewriting/shuffling of code • Detection heuristics relying on frequency of indirect branches • Generic CFI and shadow call-stacks • Defenses that prevent the stack pointer to point to the program’s heap 2018 -11 -05 Bauer Sandro 19
Defenses Memory safety Control-flow integrity Code shuffling, rewriting, hiding Heuristics Binary code • Cling • CFI + shadow call stack • CCFIR • O-CFI • vf. Guard • T-VIP • VTint • STIR • Smashing The Gadgets • k. Bouncer • EMET • ROPecker Source code • • 2018 -11 -05 CPI CPS Soft. Bound WIT • • GCC VTV LLVM IFCC Safe. Dispatch Windows CFG Bauer Sandro • G-Free • Xn. R • Readactor 20
effective protection vulnerability partial protection Defenses Memory safety Control-flow integrity Code shuffling, rewriting, hiding Heuristics Binary code • Cling • CFI + shadow call stack • CCFIR • O-CFI • vf. Guard • T-VIP • VTint • STIR • Smashing The Gadgets • k. Bouncer • EMET • ROPecker Source code • • 2018 -11 -05 CPI CPS Soft. Bound WIT • • GCC VTV LLVM IFCC Safe. Dispatch Windows CFG Bauer Sandro • G-Free • Xn. R • Readactor 21
How to prevent COOP? • Conceptually prevented when • hijacking or injection of C++ objects is prevented • necessary information is concealed from the attacker • Protect C++ vptrs • C++ aware CFI • Randomization of C++ data structures Considering high-level C++ semantics (access to source code) 2018 -11 -05 Bauer Sandro 22
Conclusion • COOP is a practical code-reuse attack. • Bypasses almost all defenses that do not consider object-oriented C++ semantics. • Rethinking of defenses that rely solely on binary code. Source code-based defenses are needed. 2018 -11 -05 Bauer Sandro 24
Future Work • Protection against COOP S. Crane, S. Volckaert, F. Schuster, C. Liebchen, P. Larsen, L. Davi, A. -R. Sadeghi, T. Holz, B. De Sutter, M. Franz. It’s a TRa. P: Table Randomization and Protection against Function-Reuse Attacks, 2015. see 2018 -12 -03, Philip Holzmann • Objective-C COOP J. Lettner, B. Kollenda, A. Homescu, P. Larsen, F. Schuster, L. Davi, A. -R. Sadeghi, T. Holz, M. Franz. Subversive-C: Abusing and Protecting Dynamic Message Dispatch, 2016. 2018 -11 -05 Bauer Sandro 25
References F. Schuster, T. Tendyck, C. Liebcheny, L. Daviy, A. -R. Sadeghiy, T. Holz. Counterfeit Object-oriented Programming: On the Difficulty of Preventing Code Reuse Attacks in C++ Applications, 2015. (http: //syssec. rub. de/media/emma/veroeffentlichungen/2015/03/28/ COOP-Oakland 15. pdf) 2018 -11 -05 Bauer Sandro 26
Discussion Questions? 2018 -11 -05 Bauer Sandro 27
Appendix Assembly code of ML-ARG-G in jscrip 9. dll version 10. 0. 9200. 16521 in Internet Explorer 10 32 -bit exploit 2018 -11 -05 mov edi, edi push ebp mov ebp, esp push ecx push esi mov esi, ecx lea eax, [esi+3 ACh] ; -- inlined constructor of iterator -mov [ebp+iterator. end], eax mov [ebp+iterator. current], eax ; -loop: lea ecx, [ebp+iterator] call SList. Base: : Iterator: : Next() test al, al jnz end mov eax, [ebp+iterator. current] push [esi+140 h] ; push argument field mov ecx, [eax+4] ; read object pointer from iterator mov eax, [ecx] call [eax+4] ; call 2 nd virtual function jmp loop end: pop esi mov esp, ebp pop ebp ret Bauer Sandro 28
- Slides: 27