Computer and Network Security

Table of Contents

Lecture 7: exploitation techniques

Buffer overflows:

Array overflow (provides arbitrary write)

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    long array[8];
    long index = strtol(argv[1], NULL, 10);
    long value = strtoul(argv[2], NULL, 16);
    array[index] = value;
    return 0;
}

You can load shellcode into environment, then write to this array to overwrite the return address.

Off-by-one errors

Data/BSS overflows

Data and BSS store global variables No return address reachable for contiguous overflows. What can you do?

Heap overflows

explicit allocation functions return memory on heap, which survives function return but needs explicit deallocation. harder to exploit: no return addresses, relative locations depend on order and malloc implementation instead you target e.g. metadata

heap organisation:

dlmalloc (used in glibc) implementation:

  1. find free chunk from free list
    • if not found, allocate more memory from OS and add to free list
  2. if chunk too large, split in two and add new chunk to free list
  3. Remove chunk from free list
  4. Mark chunk as used in metadata
  5. Return pointer to data area in chunk

dlmalloc’s free:

  1. Locate chunk with data pointer
  2. Mark chunk as free in metadata
  3. If next chunk also free, merge with next chnk
  4. If previous chunk also free, merge with previous chunk
  5. Add chunk to free list

Metadata at start of every chunk:

struct malloc_chunk {
    size_t prev_size;
    size_t size;
    struct malloc_chunk* fd; // used only if free, otherwise data pointer starts here
    struct malloc_chunk* bk;
};

Chunk size:

Free list:

Exploiting dlmalloc:

In stack buffer overflows, return address is at fixed offset (so it’s easy to reach) Heap overflow/format string write to an absolute address Alternative target is Global Offset Table

Integer overflow

Integers have a fixed size, each integer type has limited range. If result does not fit in range of integer, CPU still computes result but discards bits that don’t fit Classification:

Format strings

printf and related take format string and parameters careless programmers might let user specify format string

parameter passing is just like for other functions (registers, then stack) missing parameters filled with whatever happened to be there – information leaks, or position to reach all of stack %n - writes to memory, stores number of output characters so far to pointer passed as parameter. so controlling format strings implies arbitrary write.

int main(int argc, char **argv) {
    char buf[256];
    int y = 1;
    snprintf(buf, sizeof(buf), argv[1]); // missing parameter! so format string is attacker-controlled
    printf("buffer (%d): %s\n", strlen(buf), buf);
    printf("y is %d/0x%x (@ %p)\n", y, y, &y);
    return 0;
}

Temporal errors

Spatial errors let attacker access outside space allocated for buffer. Temporal errors let attacker access buffer before/after intended time frame Main types;

Use after free:

Uninitialized variables

Type confusion

C++ provides classes (basically structs tying data to functions) Instance of class is object, can be on stack or on heap Classes can inherit from one or more classes, can call all functions available from parent. Object pointer can be cast from child to parent.

C++ typecasts:

static_cast is common but unsafe: