Lecture 7_ exploitation techniques.md (7896B)
1 +++ 2 title = "Lecture 7: exploitation techniques" 3 +++ 4 5 # Lecture 7: exploitation techniques 6 ## Buffer overflows: 7 - common mistake 8 - can exploit locally and remotely 9 - can modify both data and control flow 10 - architecture and OS version dependent 11 - example buffer overflow was contiguous, arbitrary-length, null-terminated, stack-based. variations in these are possible. 12 - typical signs of buffer overflows: fixed-length buffers, passing pointer to buffer without size, array access without size check, pointer arithmetic without size/end pointer 13 - vulnerable functions: 14 - `gets()` reads up to newline - replace with `fgets()` 15 - `strcpy()`/`strcat()` copies up to null byte - replace with `strncpy()`/`strncat()` 16 - `sprintf()` etc. length depends on format arguments - replace with `snprintf()` etc. 17 - `scanf()` etc. length depends on input string - put bound on `%s` formats 18 - own input functions might be sloppy, always check assumptions 19 20 ## Array overflow (provides arbitrary write) 21 22 ```c 23 #include <stdio.h> 24 #include <stdlib.h> 25 int main(int argc, char **argv) { 26 long array[8]; 27 long index = strtol(argv[1], NULL, 10); 28 long value = strtoul(argv[2], NULL, 16); 29 array[index] = value; 30 return 0; 31 } 32 ``` 33 You can load shellcode into environment, then write to this array to overwrite the return address. 34 35 36 ## Off-by-one errors 37 - e.g. wrong comparison operator, forget about string terminator 38 - similar to regular overflows, but can overwrite only one element above array size 39 - this can be exploited to overflow adjacent buffers 40 - note: every pointer contains 2 null bytes (at end in 64-bit, integers are stored little endian) 41 42 ## Data/BSS overflows 43 Data and BSS store global variables 44 No return address reachable for contiguous overflows. 45 What can you do? 46 - overwriting function pointer 47 - overwrite saved frame pointer (attacker can set up fake stack, later return from this stack) 48 - overwrite C++ object pointer (can hijack virtual function calls) 49 - overwriting variables often breaks security, like changing strings/integers 50 - changing pointers 51 52 ## Heap overflows 53 explicit allocation functions return memory on heap, which survives function return but needs explicit deallocation. 54 harder to exploit: no return addresses, relative locations depend on order and malloc implementation 55 instead you target e.g. metadata 56 57 heap organisation: 58 - heap grows towards higher memory address 59 - memory managed through in-band control structures (metadata is between buffers) 60 - control structures can be manipulated through heap overflows for arbitrary code execution 61 - depends on architecture and OS (especially libc) 62 - heap is divided in chunks, adjacent free blocks are merged 63 64 dlmalloc (used in glibc) implementation: 65 1. find free chunk from free list 66 - if not found, allocate more memory from OS and add to free list 67 2. if chunk too large, split in two and add new chunk to free list 68 3. Remove chunk from free list 69 4. Mark chunk as used in metadata 70 5. Return pointer to data area in chunk 71 72 dlmalloc's free: 73 1. Locate chunk with data pointer 74 2. Mark chunk as free in metadata 75 3. If next chunk also free, merge with next chnk 76 4. If previous chunk also free, merge with previous chunk 77 5. Add chunk to free list 78 79 Metadata at start of every chunk: 80 81 ```c 82 struct malloc_chunk { 83 size_t prev_size; 84 size_t size; 85 struct malloc_chunk* fd; // used only if free, otherwise data pointer starts here 86 struct malloc_chunk* bk; 87 }; 88 ``` 89 90 Chunk size: 91 - 8 bytes overhead per allocated block (only size field always used) 92 - size always multiple of 16 (data size+overhead rounded up, four low-order bits always 0) 93 - low-order bits of size field used for status 94 95 Free list: 96 - used to find free block to allocate 97 - doubly linked list using `fd` and `bk` fields 98 - insertion in free list: free(), splitting large block in malloc 99 - removal from free list: malloc(), merging free blocks in free() 100 101 Exploiting dlmalloc: 102 - assume we find heap buffer overflow 103 - overwrite `fd` and `bk` (requires free block) 104 - make program call unlink (e.g. to merge block when block before is freed) 105 - unlink writes chosen data (`fd`) at chosen location (`bk`) 106 107 In stack buffer overflows, return address is at fixed offset (so it's easy to reach) 108 Heap overflow/format string write to an absolute address 109 Alternative target is Global Offset Table 110 - used to lazily load library functions 111 - address is looked up and stored on first call 112 - has a fixed location 113 - can use printf 114 115 116 ## Integer overflow 117 Integers have a fixed size, each integer type has limited range. 118 If result does not fit in range of integer, CPU still computes result but discards bits that don't fit 119 Classification: 120 - truncation: integer is cast to a smaller type, discarding extra bits 121 - arithmetic overflow: computation result out of range for type, wrapping around 122 - signedness: negative integer cast to unsigned type, incorrectly interpreting sign bit 123 124 ## Format strings 125 printf and related take format string and parameters 126 careless programmers might let user specify format string 127 128 parameter passing is just like for other functions (registers, then stack) 129 missing parameters filled with whatever happened to be there -- information leaks, or position to reach all of stack 130 `%n` - writes to memory, stores number of output characters so far to pointer passed as parameter. so controlling format strings implies arbitrary write. 131 132 ```c 133 int main(int argc, char **argv) { 134 char buf[256]; 135 int y = 1; 136 snprintf(buf, sizeof(buf), argv[1]); // missing parameter! so format string is attacker-controlled 137 printf("buffer (%d): %s\n", strlen(buf), buf); 138 printf("y is %d/0x%x (@ %p)\n", y, y, &y); 139 return 0; 140 } 141 ``` 142 143 ## Temporal errors 144 Spatial errors let attacker access outside space allocated for buffer. 145 Temporal errors let attacker access buffer before/after intended time frame 146 Main types; 147 - use after free 148 - uninitialized variables 149 150 Use after free: 151 - sometimes program retains pointer to freed memory location 152 - malloc buffer that was freed 153 - local variable/alloca buffer after function return 154 - future allocation/function call can re-use memory 155 - dereferencing dangling pointer results in undefined behavior 156 - attacker can craft input to overwrite memory with own data 157 1. program allocates X 158 2. program uses X to store some data 159 3. program frees X 160 4. program allocates Y overlapping with X 161 5. data written to Y also overwrites relevant part of X 162 6. program uses X, causing incorrect result 163 164 Uninitialized variables 165 - local variables and malloc buffers not automatically zeroed 166 - instead contain whatever happened to be there 167 - compilers try to warn, but e.g. arrays, struct/union members, malloc buffers not checked 168 - attacker can initialize variable in way that programmer didn't expect: 169 1. program allocates X 170 2. program uses X to store data under attacker control 171 3. program frees X 172 4. program allocates Y overlapping X 173 5. program doesn't initialize some/all of Y, causing attacker-provided data from X to stay there 174 6. program uses Y, causing incorrect result 175 176 ## Type confusion 177 C++ provides classes (basically structs tying data to functions) 178 Instance of class is object, can be on stack or on heap 179 Classes can inherit from one or more classes, can call all functions available from parent. 180 Object pointer can be cast from child to parent. 181 182 C++ typecasts: 183 - reinterpret_cast: no checks (fast), assumes programmer knows their shit (unsafe) 184 - static_cast: compile-time check (fast at runtime), allows any possibly valid cast including parent-to-child (still unsafe) 185 - dynamic_cast: run-time check (slow), ensures runtime type is consistent with compile-time type (safe) 186 187 static_cast is common but unsafe: 188 - object may be cast to wrong type 189 - incorrect cast causes mismatch between runtime type and compile-time type, members read/written according to wrong type