Pointer Subterfuge
Secure Coding in C and C++

Robert C. Seacord
CERT® Coordination Center
Software Engineering Institute
Carnegie Mellon University
Pittsburgh, PA 15213-3890
The CERT Coordination Center is part of the Software Engineering
Institute. The Software Engineering Institute is sponsored by the
U.S. Department of Defense.
© 2004 by Carnegie Mellon University
some images copyright www.arttoday.com
1

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University2AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

3

Pointer Subterfuge
Pointer subterfuge is a general term for exploits that modify apointer’s value.
A pointer is a variable that contains the address of a function, arrayelement, or other data structure.
Function pointers can be overwritten to transfer control to attackersupplied shellcode.
When the program executes a call via the function pointer, theattacker’s code is executed instead of the intended code.
Data pointers can also be modified to run arbitrary code.
If a data pointer is used as a target for a subsequent assignment,
attackers can control the address to modify other memory
locations.
© 2004 by Carnegie Mellon University

4

Data Locations - 1
For a buffer overflow to overwrite a function or data
pointer the buffer must be• allocated in the same segment as the target function
or data pointer.
• at a lower memory address than the target function
or data pointer.
• susceptible to a buffer overflow exploit.

© 2004 by Carnegie Mellon University

5

Data Locations - 2
UNIX executables contain both a data and a BSS
segment.
The data segment contains all initialized global
variables and constants.
The Block Started by Symbols (BSS) segment contains
all uninitialized global variables.
Initialized global variables are separated fromuninitialized variables.
© 2004 by Carnegie Mellon University

6

Data declarations and process
memory organization
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.
}© 2004 by Carnegie Mellon University

7

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

8

Function Pointers - Example Program 1
The static
1. void good_function(const char *str) {...}
character2. void main(int argc, char **argv) {array buff
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. }funcPtr declared are bothuninitialized and stored
in the BSS segment.

9© 2004 by Carnegie Mellon University

Function Pointers - Example Program - 2
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
overflowoccurs when
the length ofargv[1]exceeds
BUFFSIZE.

© 2004 by Carnegie Mellon University

10

Function Pointers - Example Program - 3
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().

© 2004 by Carnegie Mellon University

11

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

12Data Pointers
Used in C and C++ to refer to• dynamically allocated structures• call-by-reference function arguments• arrays• other data structures
Can be modified by an attacker when exploiting abuffer overflow vulnerability.
Arbitrary Memory Write occurs when an Attacker
can control an address to modify other memory
locations© 2004 by Carnegie Mellon University

13

Data Pointers - Example Program
1. void foo(void * arg, size_t len) {2.
char buff[100];3.
long val = ...;
4.
long *ptr = ...;
5.
memcpy(buff, arg, len); //unbounded memory copy
6.
*ptr = val;
7.
...
8.
return;9. }After overflowing the buffer, an attacker can overwrite ptr and val.
When *ptr = val is evaluated (line 6), an arbitrary memory write is
performed.

© 2004 by Carnegie Mellon University

14

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

15

Modifying the Instruction PointerFor an attacker to succeed an exploit needs to modify the value of the
instruction pointer to reference the shellcode.
1. void good_function(const char *str) {2.
printf("%s", str);
3. }4. int _tmain(int argc, _TCHAR* argv[]) {5.
static void (*funcPtr)(const char *str);// Function pointer declaration
6.
funcPtr = &good_function;
7.
(void)(*funcPtr)("hi ");8.
good_function("there!\n");9.
return 0;
10. }© 2004 by Carnegie Mellon University

16

Function Pointer Disassembly
Example - ProgramThis address
can also befound in thedword ptr
[funcPtr(void)(*funcPtr)("hi ");00424178 mov esi, esp
0042417A push offset string "hi" (46802Ch)
0042417F call dword ptr [funcPtr (478400h)]
00424185 add esp, 4First function call invocation takes place at00424188 cmp esi, esp 0x0042417F. The machine code at this address is
ff 15 00 84 47 00

good_function("there!\n");0042418F push offset string "there!\n" (468020h)
00424194 call good_function (422479h)
The actual
00424199 add esp, 4address of
good_function()stored at thisaddress is
0x00422479.
17© 2004 by Carnegie Mellon University

Function Pointer Disassembly
Example - Program(void)(*funcPtr)("hi ");00424178 mov esi, esp
0042417A push offset string "hi" (46802Ch)
0042417F call dword ptr [funcPtr (478400h)]
00424185 add esp, 400424188 cmp esi, esp
good_function("there!\n");0042418F push offset string "there!\n" (468020h)
00424194 call good_function (422479h)
00424199 add esp, 4
The second, static call togood_function() takes place at
0x00424194. The machine code at
this location ise8 e0 e2 ff ff.
© 2004 by Carnegie Mellon University

18

Function Pointer Disassembly
Analysis - 1
This form of the call instruction indicates a near callwith a displacement relative to the next instruction.
The displacement is a negative number, whichmeans that good_function() appears at a lower
address
The invocations of good_function() provide
examples of call instructions that can and cannot
be attacked© 2004 by Carnegie Mellon University

19

Function pointer disassembly analysis - 2
The static invocation uses an immediate value as
relative displacement, and this displacement cannot be
overwritten because it is in the code segment.
The invocation through the function pointer uses anindirect reference, and the address in the referenced
location can be overwritten.
These indirect function references, as well as function
calls that cannot be resolved at compile time, can be
exploited to transfer control to arbitrary code.
© 2004 by Carnegie Mellon University

20

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

21

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction Pointer
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

22

Global Offset Table - 1
Windows and Linux use a similar mechanism for linking andtransferring control to library functions.
• Linux solution is exploitable• Windows version is not
The default binary format on Linux, Solaris 2.x, and SVR4 is called
the executable and linking format (ELF).
ELF was originally developed and published by UNIX System
Laboratories (USL) as part of the application binary interface (ABI).
The ELF standard was adopted by the Tool Interface Standards
committee (TIS) as a portable object file format for a variety of IA32 operating systems.
© 2004 by Carnegie Mellon University

23

Global Offset Table - 2
The process space of any ELF binary includes a section called the global
offset table (GOT).
The GOT holds the absolute addresses, making them available withoutcompromising the position independence of, and the ability to share, theprogram text.
This table is essential for the dynamic linking process to work.
Every library function used by a program has an entry in the GOT that
contains the address of the actual function.
Before the program uses a function for the first time, the entry contains theaddress of the runtime linker (RTL).
If the function is called by the program, control is passed to the RTL andthe function’s real address is resolved and inserted into the GOT.
Subsequent calls invoke the function directly through the GOT entry
without involving the RTL© 2004 by Carnegie Mellon University

24

Global Offset Table Example% objdump --dynamic-reloc test-prog
format:file format elf32-i386
DYNAMIC RELOCATION RECORDS
OFFSET
TYPE
08049bc0 R_386_GLOB_DAT
08049ba8 R_386_JUMP_SLOT
08049bac R_386_JUMP_SLOT
08049bb0 R_386_JUMP_SLOT
08049bb4 R_386_JUMP_SLOT
08049bb8 R_386_JUMP_SLOT
08049bbc R_386_JUMP_SLOT

VALUE__gmon_start____libc_start_main
strcatprintfexit
sprintf
strcpyThe offsets specified for each
R_386_JUMP_SLOT relocation record
contain the address of the specified
function (or the RTL linking function)© 2004 by Carnegie Mellon University

25

Global Offset Table - 3
The address of a GOT entry is fixed in the ELF executable.
The GOT entry is at the same address for any executable process
image.
The location of the GOT entry for a function can be found using the
objdumpAn attacker can overwrite a GOT entry for a function with theaddress of shellcode using an arbitrary memory write.
Control is transferred to the shellcode when the program
subsequently invokes the function corresponding to thecompromised GOT entry.
© 2004 by Carnegie Mellon University

26

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

27

The .dtors Section
Another function pointer attack is to overwrite function pointers in
the .dtors section for executables generated by GCC
GNU C allows a programmer to declare attributes about functions
by specifying the __attribute__ keyword followed by an attribute
specification inside double parentheses
Attribute specifications include constructor and destructor.
The constructor attribute specifies that the function is called before
main()The destructor attribute specifies that the function is called aftermain() has completed or exit() has been called.
© 2004 by Carnegie Mellon University

28

The .dtors Section - Example Program
1. #include <stdio.h>
2. #include <stdlib.h>
3. static void create(void)__attribute__ ((constructor));4. static void destroy(void)__attribute__ ((destructor));% ./dtors
create called.
create: 0x80483a0.

5. int main(int argc, char *argv[]) {6.
printf("create: %p.\n", create);
7.
printf("destroy: %p.\n", destroy);8.
exit(EXIT_SUCCESS);
9. }destroy: 0x80483b8.
destroy called.

10. void create(void) {11.
printf("create called.\n");12. }13. void destroy(void) {14.
printf("destroy called.\n");15. }© 2004 by Carnegie Mellon University

29

The .dtors Section - 1
Constructors and destructors are stored in the .ctors and .dtors
sections in the generated ELF executable image.
Both sections have the following layout:• 0xffffffff {function-address} 0x00000000
The .ctors and .dtors sections are mapped into the processaddress space and are writable by default.
Constructors have not been used in exploits because they arecalled 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© 2004 by Carnegie Mellon University

30

The .dtors Section - 2
An attacker can transfer control to arbitrary code by overwriting theaddress of the function pointer in the .dtors section.
If the target binary is readable by an attacker, an attacker can findthe exact position to overwrite by analyzing the ELF image.
The .dtors section is present even if no destructor is specified.
The .dtors section consists of the head and tail tag with no function
addresses between.
It is still possible to transfer control by overwriting the tail tag
0x00000000 with the address of the shellcode.
If the shellcode returns, the process will call subsequent addresses
until a tail tag is encountered or a fault occurs.
© 2004 by Carnegie Mellon University

31

The .dtors Section - 3
For an attacker, overwriting the .dtors section has
advantages over other targets:• .dtors is always present and mapped into memory.
• The .dtors target only exists in programs that havebeen 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.

© 2004 by Carnegie Mellon University

32

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

33

Virtual Pointers - 1
A virtual function is a function member of a class, declared using
the virtual keyword.
Functions may be overridden by a function of the same name in a
derived class.
A pointer to a derived class object may be assigned to a baseclass pointer, and the function called through the pointer.
Without virtual functions, the base class function is called because
it is associated with the static type of the pointer.
When using virtual functions, the derived class function is called
because it is associated with the dynamic type of the object© 2004 by Carnegie Mellon University34

Virtual Pointers - Example Program- 1
1. class a {2.
public:3.
void f(void) {4.
cout << "base f" << endl;
5.
};
6.
7.
8.
9. };

virtual void g(void) {cout << "base g" << endl;};

10. class b: public a {11.
public:12.
void f(void) {13.
cout << "derived f" << endl;
14.
};
15.
16.
17.
18. };Class a is defined as
the base class andcontains a regularfunction f() and a virtualfunction g().

Class b is derived
from a and overrides
both functions.

void g(void) {cout << "derived g" << endl;};

19. int _tmain(int argc, _TCHAR* argv[]) {20.
a *my_b = new b();A pointer my_b to the base21.
my_b->f();class is declared in main() but
22.
my_b->g();23.
returnassigned to an object of thederived class b.
35© 2004 by Carnegie Mellon University

Virtual Pointers - Example Program- 1
19. int _tmain(int argc, _TCHAR* argv[]){
pointer my_b to the base20.
a *my_b = new b(); Aclass is declared in main() but
21.
my_b->f();assigned to an object of thederived class b.
22.
my_b->g();23.
returnWhenthevirtualfunction my_b->g() iscalled on the functiong() associated with b(the derived class) iscalled© 2004 by Carnegie Mellon University

When the non-virtualfunction my_b->f() iscalled on the functionf() associated with a(the base class) iscalled.
36

Virtual Pointers - 2
Most C++ compilers implement virtual functions
using a virtual function table (VTBL).
The VTBL is an array of function pointers that isused at runtime for dispatching virtual function
calls.
Each individual object points to the VTBL via a
virtual pointer (VPTR) in the object’s header.
The VTBL contains pointers to each implementationof a virtual function.
© 2004 by Carnegie Mellon University

37

Virtual Pointers - 3
It is possible to overwrite function pointers in the
VTBL or to change the VPTR to point to anotherarbitrary VTBL.
This can be accomplished by an arbitrary memory
write or by a buffer overflow directly into an object.
The buffer overwrites the VPTR and VTBL of theobject and allows the attacker to cause function
pointers to execute arbitrary code.

© 2004 by Carnegie Mellon University

38

VTBL Runtime Representationb objectb vtable

my_b

g()
other
virtualfunction© 2004 by Carnegie Mellon University

39

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

40

The atexit() and on_exit() Functions - 1
The atexit() function is a general utility function definedin C99.
The atexit() function registers a function to be called
without arguments at normal program termination.
C99 requires that the implementation support theregistration of at least 32 functions.
The on_exit() function from SunOS performs a similarfunction.
This function is also present in libc4, libc5, and glibc© 2004 by Carnegie Mellon University

41

The atexit() and on_exit() –Example Program
1. char *glob;
2. void test(void) {3.
printf("%s", glob);
4. }5. void main(void) {6.
atexit(test);
7. glob = "Exiting.\n";8. }© 2004 by Carnegie Mellon University

42

The atexit() and on_exit() Functions - 2
The atexit() function works by adding a specified
function to an array of existing functions to be called on
exit.
When exit() is called, it invokes each function in thearray in last in, first out (LIFO) order.
Because both atexit() and exit() need to access thisarray, it is allocated as a global symbol (__atexit on*bsd and __exit_funcs on Linux)© 2004 by Carnegie Mellon University

43

Debug session of atexit programusing gdb - 1(gdb) b main
Breakpoint 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:6
6 atexit(test);(gdb) next
7 glob = "Exiting.\n";(gdb) x/12x __exit_funcs
0x42130ee0 <init>:
0x00000000 0x00000003 0x00000004 0x4000c660
0x42130ef0 <init+16>: 0x00000000 0x00000000 0x00000004 0x0804844c
0x42130f00 <init+32>: 0x00000000 0x00000000 0x00000004 0x080483c8(gdb) x/4x 0x4000c660
0x4000c660 <_dl_fini>: 0x57e58955 0x5ce85356 0x81000054 0x0091c1c3(gdb) x/3x 0x0804844c
0x804844c <__libc_csu_fini>: 0x53e58955 0x9510b850 x102d0804(gdb) x/8x 0x080483c8
0x80483c8 <test>: 0x83e58955 0xec8308ec 0x2035ff08 0x68080496© 2004 by Carnegie Mellon University

44

Debug session of atexit programusing gdb - 2
In the debug session, a breakpoint is set before the callto 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 offour doublewords.
© 2004 by Carnegie Mellon University

45

Debug session of atexit programusing gdb - 3
The last doubleword in each structure contains the actual addressof the function.
Three functions have been registered _dl_fini(), __libc_csu_fini(),test().
It is possible to transfer control to arbitrary code with an arbitrary
memory write or a buffer overflow directly into the __exit_funcs
structure.
The _dl_fini() and __libc_csu_fini() functions are present evenwhen the vulnerable program does not explicitly call the atexit()
function.
© 2004 by Carnegie Mellon University

46

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

47

The longjmp() Function
C99 defines the setjmp() macro, longjmp() function, andjmp_buf type, which can be used to bypass the normal
function call and return discipline.
The setjmp() macro saves its calling environment forlater use by the longjmp() function.
The longjmp() function restores the environment savedby the most recent invocation of the setjmp() macro.

© 2004 by Carnegie Mellon University

48

The longjmp() Function- Example
Program - 1
1. #include <setjmp.h>
2. jmp_buf buf;
3. void g(int n);
4. void h(int n);
5. int n = 6;
6. void f(void) {7.
setjmp(buf);
8.
g(n);
9. }
10. void g(int n) {
11.
h(n);
12. }
13. void h(int n){
14.
longjmp(buf, 2);
15. }
49

© 2004 by Carnegie Mellon University

The longjmp() Function Example
Program- 2
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]© 2004 by Carnegie Mellon University

The jmp_buf structure (lines 913) contains three fields.
The calling environment is stored
in __jmpbuf (declared on line 1).
The __jmp_buf type is an integer
array containing six elements.
The #define statements indicate
which values are stored in eacharray element.
The base pointer (BP) is stored
in __jmp_buf[3],The program counter (PC) is
stored in __jmp_buf[5]50The longjmp() Function Example
Program- 3
The movl instruction on line 2
restores the BP

longjmp(env, i)
1. movl i, %eax /* return i */2. movl env.__jmpbuf[JB_BP], %ebp
3. movl env.__jmpbuf[JB_SP], %esp
4. jmp (env.__jmpbuf[JB_PC])

The movl instruction
on line 3 restores thestack pointer (SP).

Line 4 transfers control to thestored PC© 2004 by Carnegie Mellon University

51

The longjmp() Function
The longjmp() function can be exploited by overwriting
the value of the PC in the jmp_buf buffer with the startof the shellcode.
This can be accomplished with an arbitrary memory
write or by a buffer overflow directly into a jmp_buf
structure© 2004 by Carnegie Mellon University

52

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamples• Global Offset Table• The .dtors Section• Virtual Pointers• The atexit() and on_exit() Functions• The longjmp() Function• Exception Handling
Mitigation Strategies
Summary© 2004 by Carnegie Mellon University

53

Exception Handling - 1
An exception is any event that is outside the normal
operations of a procedure.
Example: Dividing by zero will generate an exception.
Exception handler blocks are used to handle special
cases and avoid unexpected program termination.
Exception handlers are chained and called in a definedorder until one can handle the exception.

© 2004 by Carnegie Mellon University

54

Exception Handling - 2
Microsoft Windows exception handlers• Structured exception handling (SEH). These are
implemented as per-function or per-thread exception
handlers.
• System default exception handling. This is a
global exception filter and handler for the entire
process that is called if no previous exception
handler can handle the exception.
• Vectored exception handling (VEH). These arecalled first as a method to override a structured
exception handler.
© 2004 by Carnegie Mellon University

55

Structured Exception Handling - 1
Structured exception handling (SEH) is typically implemented at
the compiler level through try…catch blocks
Any exception that is raised during the try block is handled in thematching catch block.
If the catch block is unable to handle the exception, it is passed
back to the prior scope block.
The __finally keyword is a Microsoft extension to the C/C++
language and is used to denote a block of code that is called toclean up anything instantiated by the try block.
The keyword is called regardless of how the try block exits.
© 2004 by Carnegie Mellon University

56

Try...catch block
1. try {2.
// Do stuff here
3. }4. catch(…){
5.
// Handle exception here
6. }7. __finally {8.
// Handle cleanup here
9. }© 2004 by Carnegie Mellon University

57

Structured Exception Handling - 2
Windows implements special support for per-thread
exception handlers.
Compiler-generated code writes the address of apointer to an EXCEPTION_REGISTRATION structure
to the address referenced by the fs segment register.
This structure is defined in the assembly language strucdefinition in EXSUPP.INC in the Visual C++ runtime
source© 2004 by Carnegie Mellon University

58

EXCEPTION_REGISTRATION strucdefinition
EXCEPTION_REGISTRATION struc
prev
dd
handlerdd_EXCEPTION_REGISTRATION ends?
?

prev is a pointer to the previous
EXCEPTION_HANDLER structure in the chain
handler is a pointer to the actual exception handler
function© 2004 by Carnegie Mellon University

59

Windows exception handler rules
The EXCEPTION_REGISTRATION structure must be located on
the stack.
The prev EXCEPTION_REGISTRATION structure must be at ahigher stack address.
The EXCEPTION_REGISTRATION structure must be aligned on adoubleword boundary.
If the executable image header lists SAFE SEH handler
addresses, the handler address must be listed as a SAFE SEH
handler.
If the executable image header does not list SAFE SEH handler
addresses, any structured exception handler may be called.

© 2004 by Carnegie Mellon University

60

Stack frame initialization
1. push2. mov
3. and4. push5. push6. mov
7. push8. mov

ebp
ebp, esp
esp, 0FFFFFFF8h
0FFFFFFFFh
ptr [Exception_Handler]eax, dword ptr fs:[00000000h]
eax
dword ptr fs:[0], esp© 2004 by Carnegie Mellon University

61

Stack frame with exception handler
The compiler initializes the stack frame in the function prolog
The compiler reserves space on the stack for local variables.
The exception handler address could be overwritten by an arbitraryvalue resulting from a buffer overflow in a stack variable
It is possible to replace the pointer in the thread environment block(TEB) that references the list of registered exception handlers.
The attacker needs to mock up a list entry as part of the payload
and modify the first exception handler field using an arbitrary
memory write.

© 2004 by Carnegie Mellon University

62

System Default Exception Handling
Windows provides a global exception filter and handler for theentire process that is called if no previous exception handler canhandle the exception.
Implement an unhandled exception filter for the entire process togracefully 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 anarbitrary memory write, the unhandled exception filter can be
redirected to run arbitrary code.

© 2004 by Carnegie Mellon University

63

AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

64Mitigation Strategies
The best way to prevent pointer subterfuge is toeliminate the vulnerabilities that allow memory to be
improperly overwritten.
• Pointer subterfuge can occur as a result ofoverwriting data pointers• Common errors managing dynamic memory• Format string vulnerabilities
Eliminating these sources of vulnerabilities is the best
way to eliminate pointer subterfuge.

© 2004 by Carnegie Mellon University

65

W^X
One way to limit the exposure from some of thesetargets is to reduce the privileges of the vulnerable
processes.
The policy called “W xor X” or “W^X” states that amemory segment may be writable or executable, but
not both.
It is not clear how this policy can be effectively enforced
to prevent overwriting targets such as atexit() that need
to be both writable at runtime and executable.
© 2004 by Carnegie Mellon University

66AgendaPointer Subterfuge
Function Pointers
Data Pointers
Modifying the Instruction PointerExamplesMitigation Strategies
Summary© 2004 by Carnegie Mellon University

67

Summary - 1
Buffer overflows can be used to overwrite function or data pointersin the same fashion a stack smashing attack is used to overwrite areturn address.
The ability to overwrite a function or data pointer depends on theproximity of the buffer overflow to the target pointer, but targets ofopportunity often exist in the same memory segment.
Clobbering a function pointer allows an attacker to directly transfer
control to arbitrary, attacker-supplied code.
The ability to modify a data pointer and assigned value creates anarbitrary memory write.

© 2004 by Carnegie Mellon University

68Summary - 2
There are many opportunities for transferring control toarbitrary code given an arbitrary memory write.
Some of these targets are the result of standard
features (e.g., longjmp(), atexit()).
Some are specific to particular compilers (e.g., .dtors
section) or operating system (e.g., on_exit()).
Arbitrary memory writes can easily defeat canary-based
protection schemes.
© 2004 by Carnegie Mellon University

69

Summary - 3
Write-protecting targets is difficult because of thenumber of targets and because there is a requirement
to modify many of these targets (e.g., function pointers)
at runtime.
Buffer overflows occurring in any memory segment canbe exploited to execute arbitrary code, so moving
variables from the stack to the data segment or heap is
not a solution.
The best approach to preventing pointer subterfuge
resulting from buffer overflows is to eliminate possible
buffer overflow conditions.
© 2004 by Carnegie Mellon University

70