1 of 91

More Vulnerabilities�(buffer overreads, format string, integer overflow, heap overflows)

Chester Rebeiro

Indian Institute of Technology Madras

CR

2 of 91

2

CR

3 of 91

Buffer Overreads

3

CR

4 of 91

4

Buffer Overread Example

CR

5 of 91

Buffer Overread Example

5

len read from command line

len used to specify how much�needs to be read.

Can lead to an overread

CR

6 of 91

Buffer Overreads

  • Cannot be prevented by canaries� canaries only look for changes
  • Cannot be prevented by the W^X bit

we are not executing any code

  • Cannot be prevented by ASLR

not moving out of the segment

  • Can be prevented by compiler and hardware level changes

6

CR

7 of 91

Heartbleed : A buffer overread malware

  • 2012 – 2014
    • Introduced in 2012; disclosed in 2014
  • CVE-2014-0160
  • Target : OpenSSL implementation of �TLS – transport layer security
    • TLS defines crypto-protocols for secure communication
    • Used in applications such as email, web-browsing, VoIP, instant messaging,
    • Provide privacy and data integrity

7

CR

8 of 91

Heartbeat

  • A component of TLS that provides a means to keep alive secure communication links
    • This avoids closure of connections due to some firewalls
    • Also ensures that the peer is still alive

8

Hello World; 12

Hello World; 12

Heartbeat Message

type

length

payload

padding

CR

9 of 91

Heartbeat

  • Client sends a heart beat message with some payload
  • Server replies with the same payload to signal that everything is OK

9

Hello World; 12

Hello World; 12

Heartbeat Message

type

length

payload

padding

CR

10 of 91

SSL3 struct and Heartbeat

  • Heartbeat message arrives via an SSL3 structure, which is defined as follows

length : length of the heartbeat message

data : pointer to the entire heartbeat message

10

struct ssl3_record_st

{

unsigned int D_length; /* How many bytes available */

[...]

unsigned char *data; /* pointer to the record data */

[...]

} SSL3_RECORD;

type

Length (pl)

payload

Format of data (Heartbeat Message)

CR

11 of 91

Payload and Heartbeat length

  • payload_length: controlled by the heartbeat message creator
    • Can never be larger than D_length
    • However, this check was never done!!!
      • Thus allowing the heartbeat message creator to place some arbitrary large number in the payload_length
      • Resulting in overread

11

type

Length (pl)

payload

Heartbeat Message

payload length (pl)

D_length (pl)

CR

12 of 91

Overread Example

12

Attacker sends a heartbeat message with�a single byte payload to the server.

However, the pl_length is set to 65535�(the max permissible pl_length)

Victim ignores the SSL3 length (of 4 bytes),

Looks only at the pl_length and returns �a payload of 65535 bytes. In the payload, only

1 byte is victim’s data remaining 65534 from�its own memory space.

CR

13 of 91

Broken OpenSSL �code@victim

13

p points to the attackers heart

beat packet which the victim�just received.

get the heartbeat type;�fill payload with size of payload�(pl in our notation)

This is picked up from the

attackers payload and contains�65535

Allocate buffer of 3 + 65535 + 16 bytes

memcpy grossly overreads from the victim’s heap

1

2

3

4

CR

14 of 91

Broken OpenSSL �code@victim

14

Add padding and send the�response heartbeat message�back to the attacker

5

CR

15 of 91

65534 byte return payload may contain sensitive data

15

Further, invocations of similar false heartbleed will result in another 64KB of the�heap to be read.

In this way, the attacker can scrape through the victim’s heap.

CR

16 of 91

The patch in OpenSSL

16

Discard the heartbeat response if it happens to be greater than �the length in the SSL3 structure (i.e. D_length)

CR

17 of 91

Format String Vulnerabilities

17

CR

18 of 91

Format Strings

18

printf ("The magic number is: %d\n", 1911);

format string

Format specifier

arguments

void printf (char **fmt, . . .);

variable arguments

Function declaration of printf

CR

19 of 91

printf invocation

19

void main(){

printf (“%d %d %d\n", a, b, c);

}

b

return Address

Locals of function

prev frame pointer

stack

a

ptr to fmt string

c

CR

20 of 91

20

void printf(char *fmt, ...){

va_list ap; /* points to each unnamed arg in turn */

char *p, *sval;

int ival;

double dval;

va_start(ap, fmt); /*make ap point to 1st unnamed arg */

for (p = fmt; *p; p++) {

if (*p != '%’) {

putchar(*p);

continue;

}

switch (*++p) {

case 'd':

ival = va_arg(ap, int);

print_int(ival);

break;

| | | | |

case 's':

for (sval = va_arg(ap, char *); *sval; sval++)

putchar(*sval);

break;

default:

putchar(*p);

break;

}

}

va_end(ap); /* clean up when done */

}

b

return Address

Locals of function

prev frame pointer

stack

a

ptr to fmt string

c

CR

21 of 91

Insufficient Arguments to printf

21

void main(){

printf (“%d %d %d\n", a, b);

}

b

return Address

Locals of function

prev frame pointer

stack

a

ptr to fmt string

Can the compiler detect this inconsistency

  • Generally does not
  • Would need internal details of printf, making the compiler�library dependent.
  • Format string may be created at runtime�

3 format�specifiers

But only 2�arguments

Can the printf function detect this inconsistency

  • Not easy
  • Just picks out arguments from the stack, whenever it sees a format specifier

CR

22 of 91

Exploiting inconsistent printf

  • Crashing a program

  • Printing contents of the stack

22

printf ("%s%s%s%s%s%s%s%s%s%s%s%s");

printf ("%x %x %x %x");

CR

23 of 91

Exploiting inconsistent printf

  • Printing any memory location

23

This should have the contents of s

user_string has to be local

CR

24 of 91

Exploiting inconsistent printf

  • Printing any memory location

24

This should have the contents of s

user_string has to be local

contents of the stack printed�by the 6 %x

string pointed to by 0x080496c0.�this happens to be ‘s’

%s, picks pointer�from the stack

and prints from the

pointer till \0

CR

25 of 91

Digging deeper

25

0x0000001a

0xbffe72d8

b776a54

0

0xb7fe1b48

0x08096c0

%x

%x

0x8048566

%x

%x

%x

%x

%s

user_string

stack

esp

printf(user_string);

  • printf will start to read user_string
  • Whenever it finds a format specifier (%x here)
    • It reads the argument from the stack
    • and increments the va_arg pointer
  • If we have sufficient %x’s, the va_arg pointer �will eventually reach user_string[0], which is filled�with the desired target address.
  • At this point we have a %s in user string, �thus printf would print from the target address till \0

CR

26 of 91

More Format Specifiers

  • Reduce the number of %x with %N$s

26

Pick the 7th argument from the stack.

0x0000001a

0xbffe72d8

b776a54

0

0xb7fe1b48

0x08096c0

%7$s

0x8048566

user_string

stack

esp

+7

CR

27 of 91

Overwrite �an arbitrary location

%n format specifier : returns the number of characters printed so far.

  • ‘i’ is filled with 5 here

Using the same approach to read data from any location, printf can be used to modify a location as well

Can be used to change function pointers as well as return addresses

27

int i;

printf(“12345%n”, &i);

CR

28 of 91

Overwrite Arbitrary Location�with some number

28

CR

29 of 91

Overwrite Arbitrary Location with Arbitrary Number

29

An arbitrary number

CR

30 of 91

Another useful format specifier

  • %hn : will use only 16 bits .. Can be used to store large numbers

30

address of�s to store the�lower 16bits

address of�s to store the�higher 16bits

Store the number�of characters printed.

Both 16 bit lower and�16 bit higher will be�stored separately

CR

31 of 91

Integer Overflow Vulnerability

31

CR

32 of 91

What’s wrong with this code?

32

Expected behavior

CR

33 of 91

What’s wrong with this code?

33

Defined as short. Can hold

a max value of 65535

If i > 65535, s overflows, therefore is truncated. So, the condition check is likely to be bypassed.

Will result in an overflow of buf, �which can be used to perform nefarious activities

CR

34 of 91

Integer Overflow Vulnerability

  • Due to widthness overflow
  • Due to arithmetic overflow
  • Due to sign/unsigned problems

34

CR

35 of 91

Widthness Overflows

Occurs when code tries to store a value in a variable that is too small (in the number of bits) to handle it.

For example: a cast from int to short

35

int a1 = 0x11223344;

char a2;�short a3;��a2 = (char) a1;

a3 = (short) a1;

a1 = 0x11223344

a2 = 0x44

a3 = 0x3344

CR

36 of 91

Arithmetic Overflows

36

CR

37 of 91

Exploit 1�(manipulate space allocated by malloc)

37

Space allocated by malloc�depends on len. If we choose a suitable value of len such that len*sizeof(int) overflows,

then,

  1. myarray would be smaller than expected
  2. thus leading to a heap overflow
  3. which can be exploited

CR

38 of 91

(Un)signed Integers

  • Sign interpreted using the most significant bit.
  • This can lead to unexpected results in comparisons and arithmetic

38

l is initialized with the highest positive value that a signed 32 bit integer can take.

When incremented, the MSB is set, and the number is interpreted as negative.

CR

39 of 91

Sign Interpretations in compare

39

This test is with signed numbers.

Therefore a negative len will pass the�‘if’ test.

In memcpy, len is interpreted as unsigned.

Therefore a negative len will be treated

as positive.

This could be used to overflow kbuf.

void *memcpy(void *restrict dst, const void *restrict src, size_t n);

From the man pages

CR

40 of 91

Sign interpretations in arithmetic

40

table + pos is expected to be a value greater than table.

If pos is negative, this is not the case.

Causing val to be written to a location beyond the table

This arithmetic done considering unsigned

CR

41 of 91

exploiting overflow due to sign�in a network deamon

41

if size1 and size2 are large enough,

size may end up being negative.

size1 and size2 are unsigned

Size is signed.

Size is returned, which may�cause an out to overflow in the�callee function

CR

42 of 91

Sign could lead to �memory overreads.

42

#define MAX_BUF_SIZE 64 * 1024

void store_into_buffer(const void *src, int num)

{

char global_buffer[MAX_BUF_SIZE];

if (num > MAX_BUF_SIZE)

return;

memcpy(global_buffer, src, num);

[...]

}

  • num is a signed int�
  • If num is negative, then it will pass the `if’ test

  • memcpy’s 3rd parameter is unsigned. So, the negative number is interpreted as positive. Resulting in memory overreads.

CR

43 of 91

Stagefright Bug

  • Discovered by Joshua Drake and disclosed on July 27th, 2015
  • Stagefright is a software library implemented in C++ for Android
  • Stagefright attacks uses several integer based bugs to
    • execute remote code in phone
    • Achieve privilege escalation
  • Attack is based on a well crafted MP3, MP4 message sent to the remote Android phone
    • Multiple vulnerabilities exploited:
      • One exploit targets MP4 subtitles that uses tx3g for timed text.
      • Another exploit targets covr (cover art) box

  • Could have affected around one thousand million devices
    • Devices affected inspite of ASLR

43

CR

44 of 91

MPEG4 Format

44

CR

45 of 91

tx3g exploit

45

status_t MPEG4Source::parseChunk(off64_t *offset) {

[...]

uint64_t chunk_size = ntohl(hdr[0]);

uint32_t chunk_type = ntohl(hdr[1]);

off64_t data_offset = *offset + 8;

if (chunk_size == 1) {

if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {

return ERROR_IO;

}

chunk_size = ntoh64(chunk_size);

[...]

switch(chunk_type) {

[...]

case FOURCC('t', 'x', '3', 'g'):

{

uint32_t type;

const void *data;

size_t size = 0;

if (!mLastTrack->meta->findData(

kKeyTextFormatData, &type, &data, &size)) {

size = 0;

}

uint8_t *buffer = new (std::nothrow) uint8_t[size + chunk_size];

if (buffer == NULL) {

return ERROR_MALFORMED;

}

if (size > 0) {

memcpy(buffer, data, size);

}

offset into file

int hdr[2] is the first two�words read from offset

chunksize of 1 has a �special meaning.

  1. chunk_size is uint64_t,
  2. it is read from a file
  3. it is used to allocate a buffer in heap.

All ingredients for an integer overflow vulnerability

Buffer could be made to overflow here. Resulting in a heap based exploit.

This can be used to control …�... Size written

... What is written

... Predict where objects are allocated

CR

46 of 91

Integer Overflows

On 32 bit platforms

widthness overflow� (chunk_size + size) is uint64_t however new takes a 32 bit

value

On 64 bit platforms

arithmetic overflow� (chunk_size + size) can overflow by setting large values for

chunk_size

46

uint64_t chunk_size = ntohl(hdr[0]);

uint8_t *buffer = new (std::nothrow) uint8_t[size + chunk_size];

CR

47 of 91

Attack Vectors

47

CR

48 of 91

Heap exploits

48

CR

49 of 91

Heap

  • Just a pool of memory used for dynamic memory allocation

49

Text

Data

Heap

Stack

CR

50 of 91

Heap vs Stack

  • Heap

    • Slow
    • Manually done by free and malloc
    • Used for objects, large arrays, persistent data (across function calls)
  • Stack

    • Fast
    • Automatically done by compiler
    • Temporary data store

50

CR

51 of 91

Heap Management

  • Several different types of implementations
    • Doug Lea’s forms the base for many
    • glibc uses ptmalloc2 or ptmalloc3
    • Others include

tcmalloc (from Google)

jemalloc (used in Android)

nedmalloc

Hoard

    • Trade off between speed of memory management vs fragmented memory
    • Other aspects include scalability, multi-threaded support

51

CR

52 of 91

ptmalloc 2

  • Used in glibc
  • Internally uses brk and mmap syscalls to obtain memory from the OS
  • Arena:
    • main arena
    • Per-thread arena (dynamic arena)
    • Each arena can have multiple heaps (each heap is of 132 KB)
  • Heaps
    • Split into memory chunks of different sizes and used depending on how malloc and free are invoked
  • Memory chunks
    • Of two types: free chunk and allocated chunk
    • Free chunks stored in a linked list

52

https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/

CR

53 of 91

Ptmalloc: the whole structure

53

CR

54 of 91

Creating the Arena and Heap

void* threadFunc(void* arg)

{

char* addr = (char*) malloc(1000);

free(addr);

}

int main()

{

pthread_t t1;

void* s;

int ret;

char* addr;

addr = (char*) malloc(1000);

free(addr);

ret = pthread_create(&t1, NULL,

threadFunc, NULL);

ret = pthread_join(t1, &s);

return 0;

}

54

Process starts with no heap segment

CR

55 of 91

Creating the Arena and Heap

void* threadFunc(void* arg)

{

char* addr = (char*) malloc(1000);

free(addr);

}

int main()

{

pthread_t t1;

void* s;

int ret;

char* addr;

addr = (char*) malloc(1000);

free(addr);

ret = pthread_create(&t1, NULL,

threadFunc, NULL);

ret = pthread_join(t1, &s);

return 0;

}

55

Heap of size 132 KB created on the first malloc invocation.

The arena is created by invoking the

system call brk.

Future allocations use this arena until it gets completely used up. In which case the arena can grow or shrink.

chester@optiplex:~$ cat /proc/1897/maps

00400000-00401000 r-xp 00000000 08:07 2490714 ..a.out

00600000-00601000 r--p 00000000 08:07 2490714 ..a.out

00601000-00602000 rw-p 00001000 08:07 2490714 ..a.out

00602000-00623000 rw-p 00000000 00:00 0 [heap]

7ffff77f3000-7ffff79b1000 r-xp 00000000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff79b1000-7ffff7bb1000 ---p 001be000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff7bb1000-7ffff7bb5000 r--p 001be000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff7bb5000-7ffff7bb7000 rw-p 001c2000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

CR

56 of 91

Creating the Arena and Heap

void* threadFunc(void* arg)

{

char* addr = (char*) malloc(1000);

free(addr);

}

int main()

{

pthread_t t1;

void* s;

int ret;

char* addr;

addr = (char*) malloc(1000);

free(addr);

ret = pthread_create(&t1, NULL,

threadFunc, NULL);

ret = pthread_join(t1, &s);

return 0;

}

56

Even after free, the arena will still exist.

chester@optiplex:~$ cat /proc/1897/maps

00400000-00401000 r-xp 00000000 08:07 2490714 ..a.out

00600000-00601000 r--p 00000000 08:07 2490714 ..a.out

00601000-00602000 rw-p 00001000 08:07 2490714 ..a.out

00602000-00623000 rw-p 00000000 00:00 0 [heap]

7ffff77f3000-7ffff79b1000 r-xp 00000000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff79b1000-7ffff7bb1000 ---p 001be000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff7bb1000-7ffff7bb5000 r--p 001be000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

7ffff7bb5000-7ffff7bb7000 rw-p 001c2000 08:06 161656 /lib/x86_64-linux-gnu/libc-2.19.so

CR

57 of 91

Creating the Arena and Heap

void* threadFunc(void* arg)

{

char* addr = (char*) malloc(1000);

free(addr);

}

int main()

{

pthread_t t1;

void* s;

int ret;

char* addr;

addr = (char*) malloc(1000);

free(addr);

ret = pthread_create(&t1, NULL,

threadFunc, NULL);

ret = pthread_join(t1, &s);

return 0;

}

57

When threads are created, it may lead to new arenas being created. These new arenas are also of 132 KB and obtained by invoking mmap on the OS.

chester@optiplex:~$ cat /proc/2283/maps

00400000-00401000 r-xp 00000000 08:07 a.out

00600000-00601000 r--p 00000000 08:07 2490714 a.out

00601000-00602000 rw-p 00001000 08:07 2490714 a.out

00602000-00623000 rw-p 00000000 00:00 0 [heap]

7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0

7ffff0021000-7ffff4000000 ---p 00000000 00:00 0

7ffff6ff2000-7ffff6ff3000 ---p 00000000 00:00 0

7ffff6ff3000-7ffff77f3000 rw-p 00000000 00:00 0 [stack:2330]

CR

58 of 91

The Whole Structure

  • Each arena can have multiple heaps (possibly non-contiguous)
    • One or more arenas present in a process.
    • struct malloc_state : manages the arena. aka. Arena header
    • struct heap_info: manages specific heaps within the arena
  • Each heap can have multiple memory chunks
    • These chunks store data and allocated up on user request
    • struct malloc_chunk : manages a chunk of memory
  • Types of memory chunks
    • Allocated chunk
    • Free chunk
    • Top chunk : contains the unused memory allocated to the heap by the OS but not yet allocated to hold any data.
    • Last remainder chunk : last chunk that was split

58

CR

59 of 91

More about Arenas

  • Maximum number of Arenas restricted by the number of cores in the system:
    • 32 bit: #MaxArenas = 2 x Num.ofCores
    • 64 bit: #MaxArenas = 8 x Num.ofCores
    • If num. of threads is less than #MaxArenas, then we get quick mallocs and frees as there is no contention
  • One arena can service one memory request at a time (i.e. one malloc / free)
  • If more threads are present than MaxArenas then multiple threads need to share one arena.
    • This leads to contention and hence slower mallocs and frees
    • Structure malloc_state, contains all the management information for an arena

59

CR

60 of 91

Allocated Chunk

60

P : previous chunk in use (PREV_INUSE bit)

If P=0, then the word before this contains�the size of the previous chunk.

The very first chunk always has this bit set

Preventing access to non-existent memory.

M : set if chunk was obtained with mmap

N : set if chunk belongs to thread arena

Allocated chunk

mem. Is the pointer returned by malloc.

chunk. Is the pointer to metadata for�malloc

User data size for malloc(n) is �N = 8 + (n/8)*8.

Total size of chunk is N+8 bytes

CR

61 of 91

Free Chunk

61

P : previous chunk in use (PREV_INUSE bit)

If P=0, then the word before this contains�the size of the previous chunk.

The very first chunk always has this bit set

Preventing access to non-existent memory.

M : set if chunk was obtained with mmap

N : set if chunk belongs to thread arena

Free chunk

mem. Is the pointer returned by malloc.

chunk. Is the pointer to metadata for�malloc

On 32 bit machine,

User data size for malloc(n) is �N = 8 + (n/8)*8.

Total size of chunk is N+8 bytes

CR

62 of 91

List of Free Chunks

Free chunks (blue) are maintained in a linked list.

The linked list is called bins and can vary in size and characteristic

62

Allocated Chunk

Free Chunk

CR

63 of 91

Binning

63

16

24

32.

512

576

640

---

231

sorted

Different list maintained to trade off between fragmentation

and speed of malloc / free.

CR

64 of 91

Types of Bins

64

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks; defined by NFASTBINS in malloc.c (12 of them)

each list has one of these sizes: 16, 24, 32, …., 80

No coalescing (could result in fragmentation; but speeds up free)

LIFO

Pointer to list maintained in the arena (malloc_info)

CR

65 of 91

Fastbin Example

65

CR

66 of 91

Example of Fast Binning

66

x and y end up in the same bin.

x and y end up in different bins.

CR

67 of 91

Types of Bins

67

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

127 bins

CR

68 of 91

Bins

68

CR

69 of 91

Types of Bins

69

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks

(16, 24, 32, …., 128)

No coalescing (could result in fragmentation; but speeds up free)

LIFO

1 bin

Doubly link list

Chunks of any size

Helps reuse recently used chunks

62 bins ; less than 512 bytes

Chunks of 8 bytes : 16, 24, …. 504

Circular doubly linked list – because chunks are unlinked from�the middle of the list

Coalescing – join to free chunks which are adjacent to each �other

FIFO

CR

70 of 91

Types of Bins

70

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks

(16, 24, 32, …., 128)

No coalescing (could result in fragmentation; but speeds up free)

LIFO

1 bin

Doubly link list

Chunks of any size

Helps reuse recently used chunks

62 bins ; less than 512 bytes

Chunks of 8 bytes

Circular doubly linked list – because chunks are unlinked from�the middle of the list

Coalescing – join to free chunks which are adjacent to each �other

FIFO

63 bins ;

First 32 bins are 64 bytes apart

Next 16 bins are 512 bytes apart

Next 8 bins are 4096 bytes apart

Next 4 bins are 32768 bytes apart

Next 2 bins are 262144 bytes apart

1 bin of remaining size

Each bin is circular doubly linked list

Since contents of bin are not of same size; they are stored in �decreasing order of size

Coalescing – join to free chunks which are adjacent to each �other

CR

71 of 91

Types of Bins

71

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks

(16, 24, 32, …., 128)

No coalescing (could result in fragmentation; but speeds up free)

LIFO

1 bin

Doubly link list

Chunks of any size

Helps reuse recently used chunks

62 bins ; less than 512 bytes

Chunks of 8 bytes

Circular doubly linked list – because chunks are unlinked from�the middle of the list

Coalescing – join to free chunks which are adjacent to each �other

FIFO

63 bins ;

First 32 bins are 64 bytes apart

Next 16 bins are 512 bytes apart

Next 8 bins are 4096 bytes apart

Next 4 bins are 32768 bytes apart

Next 2 bins are 262144 bytes apart

1 bin of remaining size

Each bin is circular doubly linked list

Since contents of bin are not of same size; they are stored in �decreasing order of size

Coalescing – join to free chunks which are adjacent to each �other

CR

72 of 91

free(ptr)

  1. If the next chunk is allocated then
    • Set size to zero
    • Set p bit to 0

72

00000000

ptr

prev_chunk

ptr_chunk

next_chunk

p

0

CR

73 of 91

free(ptr)

2. If the previous chunk is free then

    • Coalesce the two to create a new free chunk
    • This will also require unlinking from �the current bin and placing the larger�chunk in the appropriate bin

Similar is done if the next chuck is free as well.

73

00000000

prev_chunk

next_chunk

p

is 0

CR

74 of 91

Unlinking from a free list

74

void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD){

FD = P->fd;

BK = P->bk;

FD->bk = BK;

BK->fd = FD;

}

CR

75 of 91

Types of Bins

75

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks

(16, 24, 32, …., 128)

No coalescing (could result in fragmentation; but speeds up free)

LIFO

1 bin

Doubly link list

Chunks of any size

Uses the first chunk that fits.

When a chunk is freed, it is first added here.

Helps reuse recently used chunks

CR

76 of 91

Glib’s first fit allocator

76

First Fit scheme used for allocating chunk

Allocating a memory chunk of 512 bytes

Now freeing it

Now allocating another chunk < 512 bytes.

The first free chunk available corresponds to the freed ‘a’. So, ‘c’ gets allocated the same address as ‘a’

CR

77 of 91

Types of Bins

77

Fast Bins

Unsorted Bins

Small Bins

Large Bins

Top Chunk

Last Reminder

Chunk

Single link list

8 byte chunks

(16, 24, 32, …., 128)

No coalescing (could result in fragmentation; but speeds up free)

LIFO

1 bin

Doubly link list

Chunks of any size

Helps reuse recently used chunks

62 bins ; less than 512 bytes

Chunks of 8 bytes

Circular doubly linked list – because chunks are unlinked from�the middle of the list

Coalescing – join to free chunks which are adjacent to each �other

FIFO

63 bins ;

First 32 bins are 64 bytes apart

Next 16 bins are 512 bytes apart

Next 8 bins are 4096 bytes apart

Next 4 bins are 32768 bytes apart

Next 2 bins are 262144 bytes apart

1 bin of remaining size

Each bin is circular doubly linked list

Since contents of bin are not of same size; they are stored in �decreasing order of size

Coalescing – join to free chunks which are adjacent to each �other

Top of the arena;

Does not belong to any bin;

Used to service requests when there is no free �chunk available.

If the top chunk is larger than the requested memory�it is split into two: user chunk (used for the requests�memory and last reminder chunk which becomes�the new top chunk)

If the top chunk is smaller than the requested chunk

It grows by invoking the brk() or sbrk() system call

Which defines the end of the process’ data segment

CR

78 of 91

Unlinking from a free list

78

void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD){

FD = P->fd;

BK = P->bk;

FD->bk = BK;

BK->fd = FD;

}

CR

79 of 91

Unlinking in ptmalloc2

79

/* Take a chunk off a bin list */

void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD)

{

FD = P->fd;

BK = P->bk;

if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr(check_action,"corrupted double-linked list",P);

else {

FD->bk = BK;

BK->fd = FD;

}

}

Detects cases such as these

FD pointer

BK pointer

void main()

{

char *a = malloc(10);

free(a);

free(a);

}

Causing programs like this to�crash

CR

80 of 91

Some double frees are detected

80

/* Take a chunk off a bin list */

void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD)

{

FD = P->fd;

BK = P->bk;

if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr(check_action,"corrupted double-linked list",P);

else {

FD->bk = BK;

BK->fd = FD;

}

}

Detects cases such as these

FD pointer

BK pointer

FD pointer

BK pointer

void main()

{

char *a = malloc(10);

free(a);

free(a);

}

Causing programs like this to�crash

CR

81 of 91

Most double frees are not detected

81

void main()

{

char *a = malloc(10);

char *b = malloc(10);

free(a);

free(b);

free(a);

printf(“The end!\n”);

}

FD pointer

BK pointer

FD pointer

BK pointer

a

b

After the second free

CR

82 of 91

Most double frees are not detected

82

void main()

{

char *a = malloc(10);

char *b = malloc(10);

free(a);

free(b);

free(a);

printf(“The end!\n”);

}

FD pointer

BK pointer

FD pointer

BK pointer

a

b

After the third free

FD pointer

BK pointer

a

CR

83 of 91

Another malloc

83

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

free(a);

free(b);

free(a);

c = malloc(10);

}

Another malloc�c gets allocated the same address as a

FD pointer (a)

BK pointer (a)

FD pointer (b)

BK pointer (b)

b

a

CR

84 of 91

Two views of the same chunk

84

prev chunk

size

data

prev chunk

size

unused�space

size

FD ptr

BK ptr

Allocated chunk

Free chunk

c

a

*c = 0xdeadbeef;

*(c+4) = 0xdeadbeef;

you can control the FD ptr and BK ptr contents using c

CR

85 of 91

Exploiting

85

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry – 12 for fun1;

*(c + 4) = payload;

some malloc(10);

fun1();

}

Need to lookout for programs that

have (something) like this structure

We hope to execute payload instead of�the 2nd invocation of fun1();

CR

86 of 91

Exploiting

86

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry for fun1;

*(c + 4) = payload;

some malloc(10);

fun1();

}

FD pointer (b)

BK pointer (a)

FD pointer (a)

BK pointer (a)

a

b

FD pointer

BK pointer

a

CR

87 of 91

Exploiting

87

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry for fun1;

*(c + 4) = payload;

some malloc(10);

fun1();

}

FD ptr (b)

BK pointer (b)

FD pointer (a)

BK pointer (a)

a alias c

b

CR

88 of 91

Exploiting

88

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry for fun1 - 12;

*(c + 4) = payload;

some malloc(10);

fun1();

}

GOT entry

ptr payload

FD pointer (a)

BK pointer (a)

a alias c

b

CR

89 of 91

Exploiting

89

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry for fun1 - 12;

*(c + 4) = payload;

some malloc(10);

fun1();

}

GOT entry - 12

ptr payload

FD pointer (a)

BK pointer (a)

a alias c

alias FD

alias BK

b

unlink(P){

FD = P->fd;

BK = P->bk;

FD->bk = BK;

BK->fd = FD;

}

CR

90 of 91

Exploiting Heap

90

char payload[] = “\x33\x56\x78\x12\xac\xb4\x67”;

Void fun1(){}

void main()

{

char *a = malloc(10);

char *b = malloc(10);

char *c;

fun1();

free(a);

free(b);

free(a);

c = malloc(10);

*(c + 0) = GOT entry for fun1 - 12;

*(c + 4) = payload;

some malloc(10);

fun1();

}

Payload executes

CR

91 of 91

Other heap based attacks

  • Heap overflows
  • Heap spray
  • Use after free
  • Metadeta exploits

91

CR