Advanced Buffer Overflow: Pointer subterfuge Software attacks Advanced Buffer Overflow: Pointer subterfuge
The problem What is a pointer subterfuge? It is essentially a buffer overflow + pointer manipulation The pointer could be a function pointer (a pointer to a code section) or even a data pointer This technique can help bypassing stack checks
Function-pointer clobbering Recall code from the last lesson void func(void* arg, size_t len) { char buffer[100]; void (*f)() = ...; memcpy(buff, arg, len); //buffer overflow f(); ... } 0x00401212 AAAAAAAAAAA 004119A2 00000003 00000002 Return address a b 0012FE90 EBP saved unitiliazed f buffer StackCanary locals params The function pointer could be set to a value of our own choice! And without being caught by stack checks
Data pointer modification (1) It requires a particular stack configuration BUT a modified version of this attack is also used in heap smashing exploits The basic idea: modify a pointer to a memory region AND the value assigned to perform an arbitrary memory write It is often used as a building block for other attacks
Data pointer modification (2) void func(void* arg, size_t len) { char buffer[100]; int val; int* ptr; memcpy(buff, arg, len); //overflow ... *ptr = val; return; } My Memory AAAAAAAAAAA My value 004119A2 00000003 00000002 Return address 0012FE90 EBP saved unitiliazed ptr buffer StackCanary locals params val Even in this case, we don’t have canary or ret overwriting
Data pointer modification (2) void func(void* arg, size_t len) { char buffer[100]; int val; int* ptr; memcpy(buff, arg, len); //overflow ... *ptr = val; return; } AAAAAAAAAAA 004119A2 00000003 00000002 Return address 0012FE90 EBP saved unitiliazed ptr buffer StackCanary locals params val My value My Memory My value My Memory Old value
Litchfield exploit (1) The double cookie overwrite exploit uses a data pointer modification to defeat canary based protection in VC++ 7.0 Stores shellcode in buffer as usual Modifies the pointer to point to the global cookie Overwrites stack cookie and global cookie with the same value
Litchfield exploit (2) Random value computed at process startup and stored in .data section extern int global_cookie; void vulnerable_func(void* arg, size_t len) { char buffer[100]; int i; int* ptr; int stack_cookie; memcpy(buff, arg, len); //overflow ... *ptr = i; if (stack_cookie != global_cookie) //buffer overflow occurred! exit(); return; } Inserted by compiler at stack frame bottom Check inserted by compiler just before ret instruction
Litchfield exploit (2) locals params 0x1234568 extern int global_cookie; void vulnerable_func(void* arg, size_t len) { char buffer[100]; int i; int* ptr; int stack_cookie; memcpy(buff, arg, len); //overflow ... *ptr = i; if (stack_cookie != global_cookie) //buffer overflow occurred! exit(); return; } 0x00408080 0x00408080 AAAAAAAAAAA 0x0BADF00D 004119A2 00000003 00000002 Return address 0012FE90 EBP saved unitiliazed ptr buffer 0x12345678 locals params i stack_cookie
Litchfield exploit (2) locals params 0x0BADF00D extern int global_cookie; void vulnerable_func(void* arg, size_t len) { char buffer[100]; int i; int* ptr; int stack_cookie; memcpy(buff, arg, len); //overflow ... *ptr = i; if (stack_cookie != global_cookie) //buffer overflow occurred! exit(); return; } 0x00408080 AAAAAAAAAAA 004119A2 00000003 00000002 Return address 0012FE90 EBP saved unitiliazed ptr buffer 0x12345678 locals params i 0x0BADF00D 0x00408080 0x0BADF00D stack_cookie
Litchfield exploit (2) CHECK PASS!! locals params 0x0BADF00D extern int global_cookie; void vulnerable_func(void* arg, size_t len) { char buffer[100]; int i; int* ptr; int stack_cookie; memcpy(buff, arg, len); //overflow ... *ptr = i; if (stack_cookie != global_cookie) //buffer overflow occurred! exit(); return; } 0x00408080 CHECK PASS!! AAAAAAAAAAA 004119A2 00000003 00000002 Return address 0012FE90 EBP saved unitiliazed ptr buffer 0x12345678 locals params i 0x0BADF00D 0x00408080 0x0BADF00D stack_cookie
Data pointer modification (3) An arbitrary memory overwrite can be used to set a function pointer that is everywhere in our address space The problem is… find it! =) (more on this later, maybe…) extern void (* f)(); void func(void* arg, size_t len) { char buffer[100]; int val; int* ptr; memcpy(buff, arg, len); //overflow ... *ptr = val; return; } Set ptr to &f, and val to the code we want to execute
Virtual pointer smashing Virtual pointer (VPTR): what is this? C++ programming: virtual functions Inheritance without polymorphism class B { public: int i; void f() { printf(“Base”); } }; int main() { D d; d.f(); } call D::f() class D: public B { public: int i; void f() { printf(“Derived”); } }; > Derived
Virtual pointer smashing Inheritance with polymorphism class B { public: int i; virtual void f() { printf(“Base”); } }; int main() { B* b = new D(); b.f(); b = new B(); b.f(); } class D: public B { public: int i; void f() { printf(“Derived”); } }; > Derived > Base How can the compiler distinguish?
Virtual pointer smashing class B { public: int i; virtual void f() { printf(“Base”); } }; i (4 bytes) vptr (4 bytes) vtable void (*f)() … i (4 bytes) vptr (4 bytes) int main() { B* b = new D(); b.f();
Virtual pointer smashing class B { public: int i; virtual void f() { printf(“Base”); } }; i (4 bytes) vptr (4 bytes) vtable void (*f)() … int main() { B* b = new D(); b.f(); mov edx, DWORD PTR b mov eax, DWORD PTR [edx] call DWORD PTR [eax]
Virtual pointer smashing class B { public: int i; virtual void f() { printf(“Base”); } }; i (4 bytes) vtable void (*f)() … vptr (4 bytes) 0xDDDDDDDD 0x00170000 0x0012FF6C 0x00401050 buffer void foo() { printf("Foo!!\n"); } AAAAAAAA int main() { B* b = new D1(); char buffer[20]; memcpy(buffer, msg, 24); b->f(); return 0; } f
Virtual pointer smashing class B { public: int i; virtual void f() { printf(“Base”); } }; i (4 bytes) vtable void (*f)() … vptr (4 bytes) 0x0012FF6C 0xDDDDDDDD 0x00170000 0x0012FF68 0x00401050 buffer void foo() { printf("Foo!!\n"); } AAAAAAAA int main() { B* b = new D1(); char buffer[20]; memcpy(buffer, msg, 24); b->f(); return 0; } f
Virtual pointer smashing Demo?
Virtual pointer smashing This attack relies on the method adopted by C++ compilers to have dynamic binding It’s compiler specific: where to place the vptr/vtable is up to the implementation data vptr (4 bytes) VC++ (COM-aware compilers) data vptr (4 bytes) GCC This memory layout leaves space for another exploit (anyone interested?)