ROP

Stack pivoting

  • Commonly used in places where you can only execute 1 or 2 gadgets (basically limited gadget execution) mainly because there is some metadata on stack you can’t corrupt (in cases like FSOP) or stack size is small.

One gadget

  • one_gadget to pop shell GitHub

angrop

  • easilly find rop chain

GitHub


Heap

  • malloc never clears the user data unless calloc is used
  • glibc-2.32 onwards have safe-linking.

safe-linking

  • fd pointers in tcache and fastbins are mangled to make exploitation harder.
  • straight-forward principle: use randomness from ASLR to mangle ptrs.
  • heap leak is needed to break safe-linking.
  • target address should be 0x10 byte aligned
def mangle(pos, ptr):
    """
    pos: int = position of heap chunk
    ptr: int = ptr we need. This should be 0x10 byte aligned
    """
    return (pos >> 12) ^ ptr

tcache

  • The free bin is a single linked list (LIFO based).
  • Used to store small freed allocations .
  • 7 allocations per bin.
  • ptr = malloc(size); free(ptr) with size <= 0x408 will go in tcache.
  • “thread” cache. So one tcache per thread.

NOTE-1: >= glibc-2.32 requires heap leak for breaking safe-linking.


NOTE-2: malloc clears out key field (address+8) for tcache


tcache bin struct:

typedef struct tcache_perthread_struct {
    char counts[TCACHE_MAX_BINS];
    tcache_entry* entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

tcache entry struct:

typedef struct tcache_entry {
    struct tcache_entry* next;
    uintptr_t *key;
} tcache_entry;

key field prevents double-free.

https://elixir.bootlin.com/glibc/glibc-2.35/source/malloc/malloc.c#L312

Arbitrary Access Read/Write (AAW / AAR)

  • UAF write is required.
  • heap leak to break safe-linking
a = malloc(0x10);
b = malloc(0x10);
free(a);
free(b);

// tcache freelist: [b -> a -> NULL]
// write to b, to overwrite next ptr
// take care of safelinking if needed

b = malloc(0x10); // freelist [ mangled_target -> NULL]
target = malloc(0x10); // get target

// write/read from target ... 

Double-free protection bypass

  • UAF write is required.
a = malloc(0x10);
free(a);

write(a, "abcdefghijklmnop", 0x10); // overwrite the key(+8) field

free(a); // double free

House of spirit

The main principle: free(ptr) doesn’t check if the ptr points to valid heap memory, so if we can craft a fake “malloc” like chunk (with chunk size <= 0x410 and malloc arg <= 0x408) then freeing this ptr will add the address pointed by chunk on tcache.

Requirments:

  • Free on near arbitrary ptr (ptr needs to be 0x10 byte aligned).

pseudocode rough sketch:

uint64_t fake_chunks[10];
fake_chunks[1] = 0x40; // chunk size
a = &fake_chunks[2];
free(a);

void* b = malloc(0x35); // get chunk of size 0x40

// b == &fake_chunks[2] (user controlled address)

how2heap poc

Fastbins

TODO

House of spirit

TODO

Largebins

TODO

Largebin attack

TODO

Unsorted bins

TODO

Unsafe unlinking

TODO


FSOP

TODO

AAW

TODO

AAR

TODO

Control Flow Hijacking

TODO

Random notes


Format String

AAR

TODO

AAW

TODO

Control Flow Hijacking

TODO


memory “hopping”

TODO

environ

Breaking ASLR

Breaking PIE

Breaking canary

Timing side channel