Software Security
(Part Corruptions, Use
#3: Integer Overflows, Heap
– SFL @ TU Dortmund
Copyright By PowCoder代写 加微信 powcoder
Integer Overflows
Integer Overflow
• Integers wrap around before/after their minimum/maximum value
• Problematic, e.g., in the context of array bound checks
• Several arithmetic instructions may exceed integer bounds:
– Addition: A+B may exceed the integer bounds if sum of both is larger than integer size
– Multiplication: A*B exceed integer bounds even more likely
(second register, as implemented in assembly (i)mul, does not help)
– Subtraction: A-B results in large positive value if B>A (integer underflow)
Integer overflow by adding two integers without integer bound checks
#define MAX_SIZE (int32_t) 10000
int32_t cur_str_len = strlen(curstr);
int32_t new_str_len = strlen(newstr);
if (cur_str_len + new_str_len <= MAX_SIZE) {
strcat(curstr, newstr);
cur_str_len += strlen(newstr); }
Integer Overflow
• Also integer de-/increments can under-/overflow an integer
Function vulnerable to integer overflow by increments
#define MAX_ATTEMPTS 3
uint8_t failed_attempts = 0;
char *password = "abc";
/* return 1 if password is correct, and 0 if wrong */
int verify_password(char *claimed_password) {
if (failed_attempts >= MAX_ATTEMPTS) {
goto bail; }
int rval = strcmp(password, claimed_password); if (rval != 0) {
goto bail; }
return 1; /* auth successful */
failed_attempts++;
return 0; /* auth failed */
Misc Attacks
Uninitialized Stack Variables
• If variables are not explicitly initialized, their content is undefined
• Usually just placeholders on stack (possibly using content of old stack frames)
• Example (see on the right):
• callme() does not initialize variable a
• callmetoo()’s stack frame will initialize variable a, which then the second call to callme() will use
• Output: 0 (undefined); 1; 1 (undefined)
• NOTE: If compiled such that variable a is kept in a register, the output may differ. gcc, e.g., zeroes register vars.
Example of an Unitialized Read in callme()
#include
int callme() {
printf(“%lx\n”, a);
int callmetoo() {
int a = 1;
printf(“%lx\n”, a);
int main( int argc, char **argv ) {
callmetoo();
callme(); }
Command Injection Attack
• Insufficient checks for command input
• User-driven input may combine multiple commands
• E.g.: give “/tmp; rm -rf /” as input
• Similarly: use ../../../.. to browse to paths up in the tree
Program with a command injection vulnerability
char cmdbuf[200], filepath[100];
strcpy(cmdbuf, “cat “);
printf(“Enter file name to show: \n”); gets(filepath); // also susceptible to buf overfl.
strcat(cmdbuf, filepath);
system(cmdbuf);
Installation: python3 -m pip install –upgrade pwntools
Pwntools (1/4)
• Import module and specify environment from pwn import * context(arch=’amd64′, os=’linux’)
• Extract program information elf_info = ELF(‘./bin’)
elf_info.aslr # true if ASLR enabled elf_info.nx # true if stack non-executable elf_info.symbols[‘main’] # address of main function
• Compile assembly using pwntools
bc = asm(‘mov eax, 0x01020304’) # \xb8\x04\x03\x02\x01
• Disassemble the machine code back to assembly
disasm(bc) # 0: b8 04 03 02 01 mov eax,0x1020304
Pwntools (2/4)
• Communicate with a program on a remote server (at 10.0.0.1:1234) p = remote(‘10.0.0.1’, 1234)
p.send(‘a’)
p.sendline(‘a’)
data = p.recv()
data = p.recvn(4)
data = p.recvall()
data = p.recvline()
data = p.recvuntil(‘mark’) # receive until mark
data = p.recvregex(‘\d+’) # receive until regex match
# send “a”
# send “a\n”
# receive everything printed so far # receive n bytes
# receive everything until EOF
# receive a single line
Pwntools (3/4)
• Writing (‘\n’- and ‘\0’-free) shellcode
shellcraft.amd64.mov(‘eax’, 1) # move 1 to eax w/o \n / term.
shellcraft.amd64.pushstr(‘abc’) # push ‘abc’ on stack • Custom encoding functions
encode(asm(‘mov eax, 1234’), ‘abcd’) # avoid chars: ‘abcd’
Pwntools (4/4)
• Visit http://docs.pwntools.com for more information, such as:
• http://docs.pwntools.com/en/stable/tubes/processes.html
• http://docs.pwntools.com/en/stable/tubes/sockets.html
• http://docs.pwntools.com/en/stable/tubes.html
• http://docs.pwntools.com/en/stable/asm.html
• http://docs.pwntools.com/en/stable/shellcraft/amd64.html • http://docs.pwntools.com/en/stable/encoders.html
• http://docs.pwntools.com/en/stable/rop/rop.html
• http://docs.pwntools.com/en/stable/gdb.html
• http://docs.pwntools.com/en/stable/util/packing.html
Heap Overflows: Metadata Rewriting
Heap Memory Management (1/2)
• Heap stores dynamically allocated memory
• e.g., glibc’s malloc() in Linux,
or HeapAlloc() in Windows
• Memory management maintains heap elements
in custom data structures (e.g., linked lists)
• in glibc, chunk metadata stores chunk size (and size of predecessor, if predecessor is free, otherwise data of predecessor)
• Example with 4 memory chunks in glibc’s malloc():
data0[256]
data1[128]
data2[512]
data3[256]
Allocation four elements on the heap
void *hp0 = malloc(256);
void *hp1 = malloc(128);
void *hp2 = malloc(512);
void *hp3 = malloc(256);
Heap Memory Management (2/2)
• glibc’s malloc maintains linked lists of free chunks • Consecutive free chunks are merged
into one larger chunk (defragmentation)
• All others are stored in a linked list of unallocated chunks
• Example: Linked list with three non-consecutive unallocated chunks
alloc() 7 elements; then free() even IDs
void *freeme1 = malloc(256); void *freeme2 = malloc(256); void *freeme3 = malloc(256); void *freeme4 = malloc(256); void *freeme5 = malloc(256); void *freeme6 = malloc(256); void *freeme7 = malloc(256);
free(freeme6); free(freeme4); free(freeme2);
data2[256]
data4[256]
data6[256]
Heap Chunk Overflows (1/4)
• Operations when removing a chunk C from the free list
BK = C->bk # ptr to previous free element
FD = C->fd # ptr to next free element C->fd->bk = BK # update backward ptr of next element C->bk->fd = FD # update forward ptr of prev. element
• Risk: Attacker might control BK and FD pointers if overflow in chunk’s data
• Chunk data overflows meta data (bk and fd pointers) of subsequent chunks
• Subsequent free() operation will implicitly write to the attacker-specified pointers
data4[256]
data6[128]
Heap Chunk Overflows (2/4)
• Assume data5 is overflown…
– Attacker now controls bk6 and fd6 • … and then chunk 6 is reallocated
FD = C6->fd
C6->bk->fd = FD
(stores the value FD at struct offset fd in an attacker-provided pointer specified in bk6)
BK = C6->bk
C6->fd->bk = BK
(stores the value BK at struct offset bk in an attacker-provided pointer specified in fd6)
data40[256]
data1[128]
data6[128]
Heap Chunk Overflows (3/4)
• glibc thus guards linked list updates by assertions on the pointer integrity
• Basically, glibc checks if forward pointer of current and backward pointer of subsequent element are symmetric
BK = C->bk
FD = C->fd
if (FD->bk != C || BK->fd != C) { goto error; } C->fd->bk = BK
C->bk->fd = FD
• This symmetry is broken in case of overflows (unless attacker carefully crafts multiple overwrites)
data4[256]
data6[128]
Heap Chunk Overflows (4/4)
• In practice, glibc’s malloc is more evolved
• Chunks also store size of them and their neighbors and update size whenever chunk merges happen (full struct of unallocated chunk see on the right)
• Chunks may come from different allocation pools, grouped by size and per thread
• Other memory allocators exist and are common in practice • Not all of them store metadata in line (as glibc’s ptmalloc2 does) • jemalloc(): Allocator used by Firefox and FreeBSD
• tcmalloc(): Google’s allocator
size of prev chunk
size of current chunk
unused space
Double-Free Vulnerabilities
• Double-free is a related vulnerability
• Freeing the same chunk twice (without reallocating chunk in between)
results in chunk being twice in list of free chunks
• Problem: Multiple reallocations will retrieve the same chunk
– Changes to one allocation will affect the other allocation, and vice versa
after both free()s
top
after malloc()s
a =
top bottom
Basic double-free vulnerability
void *freeme = malloc(256); free(freeme);
free(freeme);
void *a = malloc(256);
void *b = malloc(256);
Heap Overflows: Hijacking Function Pointers
Function Pointers
• Function pointers allow to dynamically compute function addresses
• Instead of calling a function at a fixed address, …
– … compute and call function address on the fly (e.g., jump table based on switch)
– … call function stored at fixed address (e.g., callback function in case of an event)
– … call function whose address is stored as part of a structure (e.g., C++ class functions)
• Example: Call a void function without arguments at funaddr
Calling a function pointer in C
((void(*)()) funaddr)();
… which gets compiled to …
Indirect call in asm
lea rbx, [funaddr] ; move function address in rbx call rbx ; call function
Overwriting Function Pointers
• Assume an attacker controls a function pointer (e.g., overflow)
• Consequences:
• Attacker can divert control flow to invalid location (crash)
• Attacker can jump to an existing, possibly protected, function (code reuse) • Attacker can jump to its own code (heap spraying in JIT environments)
Overwriting Function Pointers: An Example
Buffer overflow within menu_choice struct element on the heap
typedef struct _menu_choice {
char choice[8];
void *menu_function;
} menu_choice;
void fun_help() { printf(“help(), so useful!\n”); } void fun_compute() { /* do some computation */ }
void fun_exit() { printf(“Exiting…\n”); exit(0); } void fun_secret() { printf(“\\flg{0x0917fae0}\n”); }
void map_function(menu_choice *c) {
if (!strcmp(c->choice, “help”)) c->menu_function = fun_help; if (!strcmp(c->choice, “compute”)) c->menu_function = fun_compute; if (!strcmp(c->choice, “exit”)) c->menu_function = fun_exit;
void read_choice(c) {
read(stdin, c, sizeof(menu_choice)); // overflows into *menu_function!
int main(int argc, char *argv[]) {
menu_choice *c = malloc(sizeof(menu_choice)); read_choice(c);
map_function(c);
((void(*)()) c->menu_function)();
Countermeasure: Fat Pointers
• Classical pointers have no object size information and only store address • Object size information is known during allocation (e.g., malloc(16)→16 bytes) • However, object size is lost when pointer is passed to other functions
• Fat pointers additionally store bounds (or size) of a pointer
• Store end of pointer (address) or size (in bytes) before the actual data
• Then, for each fat pointer access, check bounds
– Grant access (read or write) if within buffer bounds
– Deny access (e.g., raise error) if outside of buffer bounds
• Prevents buffer overflows on both stack and heap
• Downsides
• Additional runtime overhead for bounds checks
• Space (memory) overhead for storing bounds information
size_of_buffer
Use-after-Free (Dangling Pointers)
Use-after-Free
• Memory management does not forbid memory usage beyond free() • malloc() receives uninitialized blob of memory from heap
• free() returns this blob to the list of free chunks, but leaves data as is
• Pointers survive the free() call and need to be explicitly destroyed
• Use-after-free: Reuse pointers after their target was free()d, e.g.: • Reading old pointer might leak data of new allocations
• Memory writes to pointer that may have been reused for other purposes
Use-after-Free
Use-after-Free read vulnerability
char *mybuf = NULL;
char *secret = NULL;
• Problem #1: Read dangling pointer • free() does not zero the freed buffer,
void get_secret() {
secret = malloc(8);
strcpy(secret, “secret!”);
printf(“%p\n”, secret);
nor does it destroy the pointer
• Content stored in allocation survives
• If pointer to free()d allocation can be reused, one can potentially read memory of other allocations
void free_buf() {
if (mybuf)
free(mybuf);
void print_buf() {
printf(“mybuf = %s\n”, mybuf);
void fill_buf() {
mybuf = malloc(8);
printf(“%p\n”, mybuf);
strcpy(mybuf, “my__buf”);
Use-after-Free
• Problem #2: Writing to dangling pointer
• Again, pointer survives free() and remains valid
• If subsequent write to free()d memory address is possible, one can change the content of other allocated objects
Use-after-Free write vulnerability
int *A = (int *) malloc(128);
int year_of_birth = read_user_input();
if (year_of_birth < 1900) {
printf(“You entered an invalid year.\n”);
// do something
A[0] = year_of_birth;
Use-after-Free and vtables (1/2)
• Dangling pointers are especially critical for C++ virtual objects
Cls1 *A, *B;
A = new Cls1(); B = A;
B.method1()
// two variables of type Cls1
// create single Cls1 object
// create alias
// free A, but not B (B dangles!)
// call method on dangling pointer
Virtual Object vtable
Cls1::vtableptr;
obj1:var1;
obj1:var2;
obj1:var3;
Cls1::method1;
Cls1::method2;
Cls1::method3;
Use-after-Free and vtables (2/2)
• Heap spraying
• Inject (pointers to) shellcode to overwrite former pointer to vtable
• Spraying increases chances to actually overwrite at the address of the deallocated former object
&rogue_vtable &rogue_vtable
&rogue_vtable
&rogue_vtable &rogue_vtable
&rogue_vtable
Rogue vtable Deallocated Object (former) vtable
&Clrso1g::uveta_bvlteapbtler;
obj1:var1;
obj1:var2;
obj1:var3;
Cls1::method1;
Cls1::method2;
Cls1::method3;
mprotect();
mprotect();
mprotect();
• Subsequent call to any of the functions on a dangling pointer of the deallocated object will call function of the attacker-injected rogue vtable
Vtable Hijacking Countermeasures
• Various academic approaches, rarely deployed in practice
• Idea 1: Freezing vtable pointers [VTPin]
• When deallocating objects, do not free pointer to former vtable • Attacker cannot overwrite vtable pointer
• But: Parts of memory will not be freed
• Idea 2: Call target checks (CFI) for tables [SafeDispatch,ForwardEdge] • Statically analyze source code to determine the valid per-object functions
• Before calling vtable function, check if function target is valid
• Little memory requirements, but about ~7.5% performance loss due to CFI
• Idea 3: Deny calls to functions in writable vtables
• Attackers by definition spray writable vtables, benign vtables are readable
• Very little overhead, yet susceptible to vtable reuse attacks
General Use-after-Free Countermeasures
• Idea 1: Track pointers to objects, and once freed, destroy them
• Feasible and efficient for single-threaded programs [FreeSentry’15], ...
• but more complex and terribly slow for multi-threaded programs [DangNULL’15] • Even highly improved designs suffer from 22%-41% overhead [DangSan’17]
• Idea 2: More secure memory allocators [DieHard,DieHarder,Cling]
• Prevent allocations at the locations that have been previously free()d
• Fairly efficient and low overhead to defend against accidental use-after-free • Yet attackers can force allocators to reuse addresses eventually [LeeNDSS’15]
• Idea 3: Static analysis to identify potential use-after-free vulnerabilities • No performance overhead, as all vulnerabilities solved during compilation
• Prone to false negatives: miss several edge cases
Conclusion and Outlook
Secure Programming
• We focused on attacks resulting from C/C++ programming mistakes
• How can developers avoid and fix such vulnerabilities from the start?
• A) Choose more secure programming languages that offer strict type safety and memory safety (e.g., C#, Rust, OCaml, ...) or sandboxes (e.g., Java)
• B) Use compiler plugins or source code analyzers that eliminate certain classes of vulnerabilities in the code (e.g., https://wiki.sei.cmu.edu/confluence/display/c/EE.+Analyzers)
• C) Follow best-practice coding standards https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard
Further Study Topics (out of scope for SFL!)
• Deeper into the covered topics
• Exception handler corruptions and defenses like SafeSEH • Jump-Oriented Programming
• Topics entirely uncovered
• Security impact of race conditions • Denial-of-Service vulnerabilities
• Logic vulnerabilities
• Side channel vulnerabilities
Further Reading (to support your understanding)
• Anley et al.: The Shellcoder’s Handbook
• Chapters 2-5: Stack and Heap Overflows, Shellcode and Format Strings Bugs
(find them as PDF in Moodle)
• Tanenbaum / Bos: Modern Operating Systems • Chapter 9.7: Exploiting Software
• Research papers:
• CFI: https://users.soe.ucsc.edu/~abadi/Papers/cfi-tissec-revised.pdf
• XnR: https://www.infsec.cs.uni-saarland.de/wp-content/uploads/sites/2/2014/10/nuernberger2014ccs_disclosure.pdf • JIT-ROP: https://cs.unc.edu/~fabian/papers/oakland2013.pdf
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com