pointer subterfuge

63
Pointer Subterfuge COEN 296A

Upload: vaughan-stokes

Post on 30-Dec-2015

52 views

Category:

Documents


0 download

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 Presentation

TRANSCRIPT

Page 1: Pointer Subterfuge

Pointer Subterfuge

COEN 296A

Page 2: Pointer Subterfuge

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.

Page 3: Pointer Subterfuge

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.

Page 4: Pointer Subterfuge

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

Page 5: Pointer Subterfuge

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));}

Page 6: Pointer Subterfuge

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;

}

Page 7: Pointer Subterfuge

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

Page 8: Pointer Subterfuge

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;

}

Page 9: Pointer Subterfuge

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. }

Page 10: Pointer Subterfuge

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.

Page 11: Pointer Subterfuge

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().

Page 12: Pointer Subterfuge

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.

Page 13: Pointer Subterfuge

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.

Page 14: Pointer Subterfuge

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

Page 15: Pointer Subterfuge

Instruction Pointer Modification

Arbitrary code execution attacks need to change IP But can only so indirectly.

Page 16: Pointer Subterfuge

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.

Page 17: Pointer Subterfuge

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

Page 18: Pointer Subterfuge

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.

Page 19: Pointer Subterfuge

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

Page 20: Pointer Subterfuge

Instruction Pointer Modification

Big Red Button:

Attacker can write arbitrary data at arbitrary location

Page 21: Pointer Subterfuge

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.

Page 22: Pointer Subterfuge

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.

Page 23: Pointer Subterfuge

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.

Page 24: Pointer Subterfuge

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

Page 25: Pointer Subterfuge

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.

Page 26: Pointer Subterfuge

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)

Page 27: Pointer Subterfuge

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.

Page 28: Pointer Subterfuge

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));

Page 29: Pointer Subterfuge

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.

Page 30: Pointer Subterfuge

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.

Page 31: Pointer Subterfuge

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.

Page 32: Pointer Subterfuge

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, …

Page 33: Pointer Subterfuge

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.

Page 34: Pointer Subterfuge

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

Page 35: Pointer Subterfuge

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; }

Page 36: Pointer Subterfuge

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()

Page 37: Pointer Subterfuge

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.

Page 38: Pointer Subterfuge

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.

Page 39: Pointer Subterfuge

Targets for Instruction Pointer Modification:atexit() on_exit()

on_exit() Similar functionality under SunOS Present in libc4, libc5, glibc

Page 40: Pointer Subterfuge

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";

}

Page 41: Pointer Subterfuge

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

Page 42: Pointer Subterfuge

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

Page 43: Pointer Subterfuge

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.

Page 44: Pointer Subterfuge

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

Page 45: Pointer Subterfuge

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.

Page 46: Pointer Subterfuge

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

Page 47: Pointer Subterfuge

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

Page 48: Pointer Subterfuge

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;

}

Page 49: Pointer Subterfuge

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]

Page 50: Pointer Subterfuge

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

Page 51: Pointer Subterfuge

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

Page 52: Pointer Subterfuge

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

Page 53: Pointer Subterfuge

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}

Page 54: Pointer Subterfuge

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

Page 55: Pointer Subterfuge

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

Page 56: Pointer Subterfuge

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

Page 57: Pointer Subterfuge

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

Page 58: Pointer Subterfuge

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.

Page 59: Pointer Subterfuge

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.

Page 60: Pointer Subterfuge

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.

Page 61: Pointer Subterfuge

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.

Page 62: Pointer Subterfuge

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

Page 63: Pointer Subterfuge

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.