pointer subterfuge
DESCRIPTION
Pointer Subterfuge. COEN 296A. Pointer Subterfuge. Pointer Subterfuge is a general expression for exploits that modify a pointer’s value. Function pointers are overwritten to transfer control to an attacker supplied shellcode. - PowerPoint PPT PresentationTRANSCRIPT
Pointer Subterfuge
COEN 296A
Pointer Subterfuge Pointer Subterfuge is a general
expression for exploits that modify a pointer’s value. Function pointers are overwritten to
transfer control to an attacker supplied shellcode.
Data pointers can also be changed to modify the program flow according to the attacker’s wishes.
Pointer Subterfuge Using a buffer overflow:
Buffer must be allocated in the same segment as the target pointer.
Buffer must have a lower memory address than the target pointer.
Buffer must be susceptible to a buffer overflow exploit.
Pointer Subterfuge UNIX executables:
Data Segment All initialized global variables and
constants BSS Segment
All uninitialized global variables Stack
All automatic variables Heap
All dynamically allocated variables
Pointer Subterfuge
1. static int GLOBAL_INIT = 1; /* data segment, global */ 2. static int global_uninit; /* BSS segment, global */ 3. 4. void main(int argc, char **argv) { /* stack, local */ 5. int local_init = 1; /* stack, local */ 6. int local_uninit; /* stack, local */ 7. static int local_static_init = 1; /* data seg, local */ 8. static int local_static_uninit; /* BSS segment, local */ /* storage for buff_ptr is stack, local */ /* allocated memory is heap, local */ 9. int *buff_ptr = (int*) malloc(sizeof(int));}
Pointer Subterfugevoid good_function(const char *str) {
//do something}
int main(int argc, char **argv) {if (argc !=2){
printf("Usage: prog_name <string1>\n");exit(-1);
}static char buff [BUFFSIZE];static void (*funcPtr)(const char *str);funcPtr = &good_function;strncpy(buff, argv[1], strlen(argv[1]));(void)(*funcPtr)(argv[2]);return 0;
}
Pointer Subterfuge
Program vulnerable to buffer overflow Variables buff and functPtr are
uninitialized and static Both stored in BSS segment
Attacker can choose function and argument to execute
This vulnerability happens in BSS
Pointer Subterfugevoid good_function(const char *str) {
//do something}
int main(int argc, char **argv) {if (argc !=2){
printf("Usage: prog_name <string1>\n");exit(-1);
}static char buff [BUFFSIZE];static void (*funcPtr)(const char *str);funcPtr = &good_function;strncpy(buff, argv[1], strlen(argv[1]));(void)(*funcPtr)(argv[2]);return 0;
}
Function Pointer Example
funcPtr declared are both uninitialized and stored in the BSS segment.
The static character array buff
1. void good_function(const char *str) {...} 2. void main(int argc, char **argv) {3. static char buff[BUFFSIZE]; 4. static void (*funcPtr)(const char *str); 5. funcPtr = &good_function;6. strncpy(buff, argv[1], strlen(argv[1])); 7. (void)(*funcPtr)(argv[2]); 8. }
Function Pointer Example
1. void good_function(const char *str) {...} 2. void main(int argc, char **argv) {3. static char buff[BUFFSIZE]; 4. static void (*funcPtr)(const char *str); 5. funcPtr = &good_function;6. strncpy(buff, argv[1], strlen(argv[1])); 7. (void)(*funcPtr)(argv[2]); 8. }
A buffer overflow occurs when the length of argv[1] exceeds BUFFSIZE.
Function Pointer Example
1. void good_function(const char *str) {...} 2. void main(int argc, char **argv) {3. static char buff[BUFFSIZE]; 4. static void (*funcPtr)(const char *str); 5. funcPtr = &good_function;6. strncpy(buff, argv[1], strlen(argv[1])); 7. (void)(*funcPtr)(argv[2]); 8. }
When the program invokes the function identified by funcPtr, the shellcode is invoked instead of good_function().
Data PointersExample
void foo(void * arg, size_t len) {char buff[100];long val = …;long *ptr = …;memcpy(buff, arg, len);*ptr = val;…return;
}
Buffer is vulnerable to overflow.
Both val and ptr are located after the buffer and can be overwritten.
This allows a buffer overflow to write an arbitrary address in memory.
Data Pointers
Arbitrary memory writes can change the control flow.
Exploits are easier if the length of a pointer is equal to the length of data. Intel 32 Architectures:
sizeof(void*) = sizeof(int) = sizeof(long) = 4B.
Instruction Pointer Modification Instruction Counter (IC) (a.k.a Program
Counter (PC)) contains address of next instruction to be executed.
Intel: EIP register. IC cannot be directly manipulated. IC is incremented or changed by a number of
instructions: jmp Conditional jumps call ret
Instruction Pointer Modification
Arbitrary code execution attacks need to change IP But can only so indirectly.
Instruction Pointer Modification
int _tmain(int argc, _TCHAR* argv[]) {if (argc !=1){
printf("Usage: prog_name\n");exit(-1);
}static void (*funcPtr)(const char *str);funcPtr = &good_function;(void)(*funcPtr)("hi ");good_function("there!\n");return 0;
}
Invoke good function through a pointer.
Invoke good function directly.
Instruction Pointer Modification
(void)(*funcPtr)(“hi “);00424178 mov esi, esp 0042417A push offset string "hi" (46802Ch) 0042417F call dword ptr [funcPtr (478400h)] 00424185 add esp, 4 00424188 cmp esi, esp
good_function(“there!\n”);0042418F push offset string "there!\n" (468020h) 00424194 call good_function (422479h) 00424199 add esp, 4
First invocation of good function.Machine code isff 15 00 84 47 00.The last four bytes are the address of the called function.
Second invocation of good function.Machine code ise8 e0 e2 ff ff.The last four bytes are the relative address of the called function.
Note: Relative addressing adds / subtracts to the current IP
Instruction Pointer Modification Static invocation uses an immediate
value for the address of the function. Address is encoded in the instruction. Address is calculated and put into IC. It cannot be changed without changing the
executable. Invocation through function pointer is
indirect. Future value of IC is in a memory location
that can be changed.
Instruction Pointer Modification
Controlling the IC allows attacker to select code to be executed. Function invocations that cannot be
resolved at compile time are vulnerable
Exploit easy if attacker can write arbitrary values at an arbitrary location
Instruction Pointer Modification
Big Red Button:
Attacker can write arbitrary data at arbitrary location
Targets for Instruction Pointer Modification:Global Offset Table
Windows and Linux use a similar mechanism for linking and transferring control for library functions. Windows’ is not exploitable. Linux’ is.
Targets for Instruction Pointer Modification:Global Offset Table
ELF (executable & linking format) Default binary format for
Linux Solaris 2.x SVR4 Adopted by TIS (Tool Interface Standards
Committee) Global Offset Table (GOT)
Included in process space of ELF binaries. GOT contains absolute addresses. Allows easy dynamic linking.
Targets for Instruction Pointer Modification:Global Offset Table
GOT Initially, GOT entry contains address
of RTL (runtime linker) If that function is called, the RTL
resolves the real address of the intended function and puts it into GOT.
Subsequent calls invoke the function directly.
Targets for Instruction Pointer Modification:Global Offset Table
GOT
main
…
…
# RTL
# RTL
# RTL
# RTL
# RTL
… Program calls printf
First call to printf
Go to GOT and invoke function
there
Invoke RTL
RTL resolves address.
RTL writes address into GOT
# printf
Targets for Instruction Pointer Modification:Global Offset Table
Address of a GOT entry is fixed in the ELF executable. It does not vary between executable
process images. Use objdump to obtain the address
of a GOT entry.
Targets for Instruction Pointer Modification:Global Offset Table
% objdump --dynamic-reloc test-progformat: file format elf32-i386
DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 08049bc0 R_386_GLOB_DAT __gmon_start__08049ba8 R_386_JUMP_SLOT __libc_start_main08049bac R_386_JUMP_SLOT strcat08049bb0 R_386_JUMP_SLOT printf08049bb4 R_386_JUMP_SLOT exit08049bb8 R_386_JUMP_SLOT sprintf08049bbc R_386_JUMP_SLOT strcpyThe offsets specified for each
R_386_JUMP_SLOT relocation record contain the address of the specified function (or the RTL linking function)
Targets for Instruction Pointer Modification:Global Offset Table
How to use GOT? Attacker needs to provide their own
shellcode. Attacker needs to be able to write an
arbitrary value to an arbitrary address. Attack:
Attacker overwrites GOT entry (that is going to be used) with the address of their shellcode.
Targets for Instruction Pointer Modification:.dtors
gcc allows attributes keyword is __attribute__
constructor attribute: function will be executed before main()
destructor attribute: function will be executed just after main() exits.
ELF places these in the .ctors and the .dtors sections.
static void start(void) __attribute__ ((constructor));static void stop(void) __attribute__ ((destructor));
Targets for Instruction Pointer Modification:.dtorsstatic void create(void)
__attribute__ ((constructor));static void destroy (void)
__attribute__ ((destructor));
int main(int argc, char *argv[]) {printf("create: %p.\n", create);printf("destroy: %p.\n", destroy);exit(EXIT_SUCCESS);}
void create(void) {printf("create called.\n");}
void destroy(void) {printf("destroy called.\n");}
create called.create: 0x80483a0. destroy: 0x80483b8.destroy called.
Targets for Instruction Pointer Modification:.dtors
Both sections have the following layout: 0xffffffff {function-address} 0x00000000
The .ctors and .dtors sections are mapped into the process address space and are writable by default.
Constructors have not been used in exploits because they are called before the main program.
The focus is on destructors and the .dtors section. The contents of the .dtors section in the executable
image can be examined with the objdump command.
Targets for Instruction Pointer Modification:.dtors
Attacker transfers control by overwriting the address of a function pointer in the .dtors section.
Given a binary: Attacker finds exact position for
overwrite by analyzing ELF image.
Targets for Instruction Pointer Modification:.dtors
.dtors section is always present
If no destructor is specified: .dtors consists of head and tail
tag with no function address between them
Attacker overwrites tail tag with address of shell code
After executing shell code Following words interpreted as
function addresses to execute Until crash
00 00 00 00
ff ff ff ff
12 34 56 78
00 00 00 00
01 00 00 60
12 34 56 78
Empty .dtors
section
Attacked .dtors section:
Execute shell code
at 01 00 00 60, then
call 12 34 56
78, …
Targets for Instruction Pointer Modification:.dtors
For an attacker, overwriting the .dtors section has advantages over other targets: .dtors is always present and mapped into
memory. However:
The .dtors target only exists in programs that have been compiled and linked with GCC.
It is difficult to find a location to inject the shellcode onto so that it remains in memory after main() has exited.
Targets for Instruction Pointer Modification:Virtual Functions
Important feature for OO programming. Allows dynamic binding (resolved
during run-time) of function calls. Virtual function is:
A member function of a class Declared with virtual keyword Usually has a different functionality in the
derived class A function call is resolved at run-time
Targets for Instruction Pointer Modification:Virtual Functions
#include <iostream>using namespace std;
class a {public: void f(void) { cout << "base f" << endl;};
virtual void g(void) { cout << "base g" << endl;};};
class b: public a {public: void f(void) { cout << "derived f" << endl;};
void g(void) { cout << "derived g" << endl;};};
int main(int argc, char *argv[]) {a *my_b = new b();my_b->f();my_b->g();return 0; }
Targets for Instruction Pointer Modification:Virtual Functions Typical Implementation:
Virtual Function Table (VTBL). Array of function pointers used at runtime for
dispatching virtual function calls. Each individual object pointer points to the VTBL via
a VPTR in the object header. VTBL contains pointers to all implementations of a
virtual function.
my_b
b-obj:
VPTRcode for g()
VTBL:
g()
Targets for Instruction Pointer Modification:Virtual Functions
Attacks: overwrite function pointers in the VTBLor change the VPTR to point to a new VTBL.
Attacker can use an arbitrary memory write or a buffer overflow directly on the object.
Targets for Instruction Pointer Modification:atexit() on_exit()
atexit() General utility defined in C99 Registers a function to be called at
normal program termination. C99 allows registration of at least 32
functions.
Targets for Instruction Pointer Modification:atexit() on_exit()
on_exit() Similar functionality under SunOS Present in libc4, libc5, glibc
Targets for Instruction Pointer Modification:atexit() on_exit()
#include <stdio.h>char *glob;void test(void) {
printf("%s", glob);}
int main(void) {atexit(test);glob = "Exiting.\n";
}
Targets for Instruction Pointer Modification:atexit() on_exit()
atexit() adds a specific function to an array of functions to be called when exiting.
exit() invokes each function in LIFO order.
Array is allocated as a global symbol __atexit in BSD __exit_funcs in Linux
Targets for Instruction Pointer Modification:atexit() on_exit()
(gdb) b mainBreakpoint 1 at 0x80483f6: file atexit.c, line 6.(gdb) rStarting program: /home/rcs/book/dtors/atexit Breakpoint 1, main (argc=1, argv=0xbfffe744) at atexit.c:66 atexit(test);(gdb) next7 glob = "Exiting.\n";(gdb) x/12x __exit_funcs0x42130ee0 <init>: 0x00000000 0x00000003 0x00000004 0x4000c6600x42130ef0 <init+16>: 0x00000000 0x00000000 0x00000004 0x0804844c0x42130f00 <init+32>: 0x00000000 0x00000000 0x00000004 0x080483c8(gdb) x/4x 0x4000c6600x4000c660 <_dl_fini>: 0x57e58955 0x5ce85356 0x81000054 0x0091c1c3(gdb) x/3x 0x0804844c0x804844c <__libc_csu_fini>: 0x53e58955 0x9510b850 x102d0804 (gdb) x/8x 0x080483c80x80483c8 <test>: 0x83e58955 0xec8308ec 0x2035ff08 0x68080496
Targets for Instruction Pointer Modification:atexit() on_exit()
In the debug session, a breakpoint is set before the call to atexit() in main() and the program is run.
The call to atexit() is then executed to register the test() function.
After the test() function is registered, memory at __exit_funcs is displayed.
Each function is contained in a structure consisting of four doublewords. Last doubleword contains address of
function.
Targets for Instruction Pointer Modification:atexit() on_exit()(gdb) b mainBreakpoint 1 at 0x80483f6: file atexit.c, line 6.(gdb) rStarting program: /home/rcs/book/dtors/atexit Breakpoint 1, main (argc=1, argv=0xbfffe744) at atexit.c:66 atexit(test);(gdb) next7 glob = "Exiting.\n";(gdb) x/12x __exit_funcs0x42130ee0 <init>: 0x00000000 0x00000003 0x00000004 0x4000c6600x42130ef0 <init+16>: 0x00000000 0x00000000 0x00000004 0x0804844c0x42130f00 <init+32>: 0x00000000 0x00000000 0x00000004 0x080483c8(gdb) x/4x 0x4000c6600x4000c660 <_dl_fini>: 0x57e58955 0x5ce85356 0x81000054 0x0091c1c3(gdb) x/3x 0x0804844c0x804844c <__libc_csu_fini>: 0x53e58955 0x9510b850 x102d0804 (gdb) x/8x 0x080483c80x80483c8 <test>: 0x83e58955 0xec8308ec 0x2035ff08 0x68080496
Targets for Instruction Pointer Modification:atexit() on_exit()
In the example: Three function have been registered:
_dl_fini() __libc_csu_fini() test()
Attacker can overwrite any entry of the __exit_funcs structure.
Targets for Instruction Pointer Modification:longjmp()
C99 defines alternate function call and return discipline Intended for dealing with errors and
interrupts encountered in a low-level subroutine of a program
setjmp() macro Saves calling environment
longjmp(), siglongjmp() Non-local jump to a saved stack context
Targets for Instruction Pointer Modification:longjmp()
longjmp() restores environment saved by the most recent invocation of setjmp() Environment:
All accessible objects You can give arguments to jmp_buf
and setjmp() to distinguish between jump targets
Targets for Instruction Pointer Modification:longjmp()
longjmp() example: longjmp() returns
control back to the point of the set_jmp() invocation.
#include <setjmp.h>jmp_buf buf;void g(int n);void h(int n);int n = 6;
void f(void){ setjmp(buf); g(n);
}void g(int n){
h(n);}void h(int n) { longjmp(buf, 2);}int main (void){
f();return 0;
}
Targets for Instruction Pointer Modification:longjmp()
Linux implementation of jmp_buf
Notice the JB_PC field. This is the target of an
attack. An arbitrary memory
write can overwrite this field with the address of shellcode in the overflowing buffer.
1. typedef int __jmp_buf[6];
2. #define JB_BX 0 3. #define JB_SI 1 4. #define JB_DI 2 5. #define JB_BP 3 6. #define JB_SP 4 7. #define JB_PC 5 8. #define JB_SIZE 24
9. typedef struct __jmp_buf_tag {10. __jmp_buf __jmpbuf; 11. int __mask_was_saved; 12. __sigset_t __saved_mask; 13. } jmp_buf[1]
Targets for Instruction Pointer Modification:longjmp()
longjmp(env, i) movl i, %eax /* return i */movl env.__jmpbuf[JB_BP],
%ebp movl env.__jmpbuf[JB_SP],
%espjmp (env.__jmpbuf[JB_PC])
The movl instruction on line 2 restores the BP
The movl instruction on line 3 restores the stack pointer (SP).
Line 4 transfers control to the stored PC
Targets for Instruction Pointer Modification:Exception Handling
Exception Event outside of the normal operation of a
procedure. Windows provides three types of exception
handlers: Vectored Exception Handling (VEH)
Added in Windows XP Called first to override SEH.
Structured Exception Handling (SEH) Implemented as per-function or per-thread
exception handling. System Default Exception Handling
Targets for Instruction Pointer Modification:Exception Handling
Exception Event outside of the normal operation of a
procedure. Windows provides three types of exception
handlers: Vectored Exception Handling (VEH)
Added in Windows XP Called first to override SEH.
Structured Exception Handling (SEH) Implemented as per-function or per-thread
exception handling. System Default Exception Handling
Targets for Instruction Pointer Modification:Exception Handling
SEH Implemented through try …
catch blocks Any exception raised in the try
block is handled in the matching catch block.
If the catch block cannot handle it, it is passed back to prior scope.
__finally is a MS extension to C/C++
Used to clean-up anything instantiated in the try block.
try { // Do stuff here}catch(…){ // Handle exception here} __finally { // Handle cleanup here}
Targets for Instruction Pointer Modification:Exception Handling
SEH Uses the EXECPTION_REGISTRATION structure Located on stack. Previous EXECPTION_REGISTRATION prev is at a
higher stack address. If the executable image header lists SAFE SEH
handler addresses, the handler address must be listed as a SAFE SEH handler. Otherwise, any structured exception handler may be called.
EXCEPTION_REGISTRATION struc prev dd ? handler dd ?_EXCEPTION_REGISTRATION ends
Targets for Instruction Pointer Modification:Exception Handling
Stack Frame Initialization During Function Prologue in Visual C++ Notice:
Local variables followed immediately by exception handler address. This puts the exception handler address at risk from buffer overflow.
push ebp
mov ebp, esp
and esp, 0FFFFFFF8h
push 0FFFFFFFFh
push ptr [Exception_Handler]
mov eax, dword ptr fs:[00000000h]
push eax
mov dword ptr fs:[0], esp
Targets for Instruction Pointer Modification:Exception Handling
Stack Frame with Exception Handler:Stack Offset Description Value
-0x10 Handler [Exception Handler]
-0x0c Previous Handler fs:[0] at function start
-8 Guard -1
-4 Saved ebp ebp
0 Return Address Return Address
Targets for Instruction Pointer Modification:Exception Handling
Local variables are immediately followed by exception handler address
Overflow in a local variable will change the exception handler address
Targets for Instruction Pointer Modification:Exception Handling
Attacker can: Overwrite the exception handler address.
(supra) Replace the pointer in the Thread
Environment Block (TEB). TEB contains lists of registered exception
handlers. Attacker mocks up a list entry as part of the payload. Modify the first exception handler field using an
arbitrary memory write. Seems to be still possible despite recent
Windows version checking validity of list entries.
Targets for Instruction Pointer Modification:Exception Handling
Windows provides a global exception filter and handler for the entire process that is called if no previous exception handler can handle the exception.
Implement an unhandled exception filter for the entire process to gracefully handle unexpected error conditions and for debugging.
An unhandled exception filter function is assigned using the SetUnhandledExceptionFilter() function.
If an attacker overwrites specific memory addresses through an arbitrary memory write, the unhandled exception filter can be redirected to run arbitrary code.
Targets for Instruction Pointer Modification:Mitigation Strategies
Eliminate vulnerabilities that allow memory to be improperly overwritten. These mistakes arise from:
Overwriting data pointers (this presentation)
Common errors managing dynamic memory
Format string vulnerabilities.
Targets for Instruction Pointer Modification:Mitigation Strategies
Eliminate exposure. W^X
Reduce privileges of vulnerable processes. Memory segment can either be writable or
executable, but not both. Difficult to implement. Does not work with targets such as atexit() that
need to be both writable at runtime and executable.
Targets for Instruction Pointer Modification:Mitigation Strategies
Canaries Does protect against
Overflowing a buffer on a stack & overwrite stack pointer and other protected regions.
Do not protect against Overflowing a stack by itself. Modification of
variables data pointers function pointers
Targets for Instruction Pointer Modification:Summary
Pointer subterfuge is a response to anti-stack smashing measures Canaries, Stack-Guard
Method is a buffer overflow in the vicinity of a target pointer. Function pointer overwrite:
Attacker can move control to arbitrary code provided in the payload.
Data pointer overwrite: Can result in arbitrary writes to arbitrary memory. These modify one of a large list of “juicy” targets.