Chunk Extend and Overlapping

[TOC]

Chunk Extend and Overlapping

介绍

chunk extend 是堆漏洞的一种常见利用手法,通过extend可以实现chunk overlapping(块重叠)的效果。这种利用的方法需要以下的条件:

  • 程序中存在堆的漏洞
  • 漏洞可以控制chunk header中的数据

原理

这种利用的技术能够产生在于ptmalloc在对堆chunk进行操作时使用的各种宏。

在ptmalloc中,获取chunk块大小的宏:

/* Get size, ignoring use bits */
##define chunksize(p) (chunksize_nomask(p) & ~(SIZE_BITS))

/* Like chunksize, but do not mask SIZE_BITS.  */
##define chunksize_nomask(p) ((p)->mchunk_size)

一种是直接获取,不忽略掩码部分,另外一种是忽略掩码部分。

在 ptmalloc 中,获取下一 chunk 块地址的宏:

/* Ptr to next physical malloc_chunk. */ 
##define next_chunk(p) ((mchunkptr)(((char *) (p)) + chunksize(p)))

在 ptmalloc 中,获取前一个 chunk 信息的宏:

/* Size of the chunk below P.  Only valid if prev_inuse (P).  */
##define prev_size(p) ((p)->mchunk_prev_size)

/* Ptr to previous physical malloc_chunk.  Only valid if prev_inuse (P).  */
##define prev_chunk(p) ((mchunkptr)(((char *) (p)) - prev_size(p)))

在 ptmalloc 中,判断当前 chunk 是否是 use 状态的宏:

##define inuse(p)
    ((((mchunkptr)(((char *) (p)) + chunksize(p)))->mchunk_size) & PREV_INUSE)

chunk extend 就是通过控制 size 、prev_size 、prev_inuse域来实现跨越块操作从而导致 overlapping 的。

基本示例

示例1:对inuse的fastbin进行extend

示例代码:

##include<stdio.h>
##include<stdlib.h>
int main()
{
    void *p, *q;
    p = malloc(0x10);//分配第一个0x10的chunk
    malloc(0x10);//分配第二个0x10的chunk
    *(long long *)((long long)p - 0x8) = 0x41;// 修改第一个块的size域
    free(p);
    q = malloc(0x30);// 实现extend,控制了第二个块的内容
    return 0;
}

这里编译的时候使用了-g参数,可以在gdb调试的时候在任意行下断点。方法:b + 行号

pwndbg> n
8	    malloc(0x10);//分配第二个0x10的chunk
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────────────
 RAX  0x602010 ◂— 0x0
 RBX  0x0
 RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RDX  0x602010 ◂— 0x0
 RDI  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RSI  0x602020 ◂— 0x0
 R8   0x602000 ◂— 0x0
 R9   0xd
 R10  0x7ffff7dd1b78 (main_arena+88) —▸ 0x602020 ◂— 0x0
 R11  0x0
 R12  0x400470 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffdf90 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdeb0 —▸ 0x4005c0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffdea0 —▸ 0x602010 ◂— 0x0
 RIP  0x40057c (main+22) ◂— mov    edi, 0x10
──────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────
   0x40056e <main+8>     mov    edi, 0x10
   0x400573 <main+13>    call   malloc@plt <0x400450>
 
   0x400578 <main+18>    mov    qword ptr [rbp - 0x10], rax
 ► 0x40057c <main+22>    mov    edi, 0x10
   0x400581 <main+27>    call   malloc@plt <0x400450>
 
   0x400586 <main+32>    mov    rax, qword ptr [rbp - 0x10]
   0x40058a <main+36>    sub    rax, 8
   0x40058e <main+40>    mov    qword ptr [rax], 0x41
   0x400595 <main+47>    mov    rax, qword ptr [rbp - 0x10]
   0x400599 <main+51>    mov    rdi, rax
   0x40059c <main+54>    call   free@plt <0x400430>
───────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────
In file: /home/gwt/Desktop/1.c
    3 #include<stdlib.h>
    4 int main()
    5 {
    6     void *p, *q;
    7     p = malloc(0x10);//分配第一个0x10的chunk
 ►  8     malloc(0x10);//分配第二个0x10的chunk
    9     *(long long *)((long long)p - 0x8) = 0x41;// 修改第一个块的size域
   10     free(p);
   11     q = malloc(0x30);// 实现extend,控制了第二个块的内容
   12     return 0;
   13 }
───────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffdea0 —▸ 0x602010 ◂— 0x0
01:0008│      0x7fffffffdea8 ◂— 0x0
02:0010│ rbp  0x7fffffffdeb0 —▸ 0x4005c0 (__libc_csu_init) ◂— push   r15
03:0018│      0x7fffffffdeb8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
04:0020│      0x7fffffffdec0 ◂— 0x0
05:0028│      0x7fffffffdec8 —▸ 0x7fffffffdf98 —▸ 0x7fffffffe30e ◂— 0x77672f656d6f682f ('/home/gw')
06:0030│      0x7fffffffded0 ◂— 0x100000000
07:0038│      0x7fffffffded8 —▸ 0x400566 (main) ◂— push   rbp
─────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────
 ► f 0           40057c main+22
   f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
          0x400000           0x401000 r-xp     1000 0      /home/gwt/Desktop/a.out
          0x600000           0x601000 r--p     1000 0      /home/gwt/Desktop/a.out
          0x601000           0x602000 rw-p     1000 1000   /home/gwt/Desktop/a.out
          0x602000           0x623000 rw-p    21000 0      [heap]
    0x7ffff7a0d000     0x7ffff7bcd000 r-xp   1c0000 0      /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7bcd000     0x7ffff7dcd000 ---p   200000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7dcd000     0x7ffff7dd1000 r--p     4000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7dd1000     0x7ffff7dd3000 rw-p     2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7dd3000     0x7ffff7dd7000 rw-p     4000 0      
    0x7ffff7dd7000     0x7ffff7dfd000 r-xp    26000 0      /lib/x86_64-linux-gnu/ld-2.23.so
    0x7ffff7fdc000     0x7ffff7fdf000 rw-p     3000 0      
    0x7ffff7ff7000     0x7ffff7ffa000 r--p     3000 0      [vvar]
    0x7ffff7ffa000     0x7ffff7ffc000 r-xp     2000 0      [vdso]
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000 25000  /lib/x86_64-linux-gnu/ld-2.23.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000 26000  /lib/x86_64-linux-gnu/ld-2.23.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000 0      
    0x7ffffffde000     0x7ffffffff000 rw-p    21000 0      [stack]
0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]
pwndbg> info locals 
p = 0x602010
q = 0x0
pwndbg> x/10gx 0x602020
0x602020:	0x0000000000000000	0x0000000000000021 <=chunk1
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000020fc1 <=top chunk
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000

info local可以查看指针指向的地址,即user_data的起始地址

继续执行

pwndbg> x/32gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000021 <=chunk1
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000021 <=chunk2
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000020fc1 <=top chunk
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
pwndbg> heap
0x602000 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x602020 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20fc1
}
0x602040 PREV_INUSE {
  prev_size = 0, 
  size = 135105, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

size = 33 = 0x21 = 0x8(prev_size) + 0x8(size) + 0x1(内容) + 0x1(标志位)

继续执行:*(long long *)((long long)p - 0x8) = 0x41

pwndbg> x/32gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000021
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000020fc1
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000

可以看到chunk1的size 已经变为了0x41,也就是说chunk1的现在大小包含了原来的chunk1和chunk2的大小。

继续执行:free后

pwndbg> x/32gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000021
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000020fc1
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x602000 ◂— 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> info locals 
p = 0x602010
q = 0x0

这里虽然free了chunk1,但是内容并没有清空。

之后将chunk1(也就是合并之后的)放进了fastbin中。

继续执行:malloc

pwndbg> x/32gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000021
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000020fc1
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
pwndbg> info bin
Undefined info command: "bin".  Try "help info".
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> info locals 
p = 0x602010
q = 0x602010

malloc后的空间给了q,这样就可以通过新分配的chunk来对chunk2中的内容进行操作了,将这种状态称为overlapping chunk。

示例2:对inuse的smallbin进行extend

示例代码:

##include<stdio.h>
##include<stdlib.h>
int main()
{
    void *p, *q;
    p = malloc(0x80);//分配第一个 0x80 的chunk1
    malloc(0x10); //分配第二个 0x10 的chunk2
    malloc(0x10); //防止与top chunk合并
    *(long *)((long)p-0x8) = 0xb1;
    free(p);
    q = malloc(0xa0);
}
pwndbg> r
Starting program: /home/gwt/Desktop/a.out 

Breakpoint 1, main () at 1.c:9
9	    *(long *)((long)p-0x8) = 0xb1;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────────────
 RAX  0x6020c0 ◂— 0x0
 RBX  0x0
 RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RDX  0x6020c0 ◂— 0x0
 RDI  0x0
 RSI  0x6020d0 ◂— 0x0
 R8   0x602000 ◂— 0x0
 R9   0xd
 R10  0x7ffff7dd1b78 (main_arena+88) —▸ 0x6020d0 ◂— 0x0
 R11  0x0
 R12  0x400470 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffdf90 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdeb0 —▸ 0x4005c0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffdea0 —▸ 0x602010 ◂— 0x0
 RIP  0x400590 (main+42) ◂— mov    rax, qword ptr [rbp - 0x10]
──────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────
 ► 0x400590 <main+42>    mov    rax, qword ptr [rbp - 0x10]
   0x400594 <main+46>    sub    rax, 8
   0x400598 <main+50>    mov    qword ptr [rax], 0xb1
   0x40059f <main+57>    mov    rax, qword ptr [rbp - 0x10]
   0x4005a3 <main+61>    mov    rdi, rax
   0x4005a6 <main+64>    call   free@plt <0x400430>
 
   0x4005ab <main+69>    mov    edi, 0xa0
   0x4005b0 <main+74>    call   malloc@plt <0x400450>
 
   0x4005b5 <main+79>    mov    qword ptr [rbp - 8], rax
   0x4005b9 <main+83>    mov    eax, 0
   0x4005be <main+88>    leave  
───────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────
In file: /home/gwt/Desktop/1.c
    4 {
    5     void *p, *q;
    6     p = malloc(0x80);//分配第一个 0x80 的chunk1
    7     malloc(0x10); //分配第二个 0x10 的chunk2
    8     malloc(0x10); //防止与top chunk合并
 ►  9     *(long *)((long)p-0x8) = 0xb1;
   10     free(p);
   11     q = malloc(0xa0);
   12 }
───────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffdea0 —▸ 0x602010 ◂— 0x0
01:0008│      0x7fffffffdea8 ◂— 0x0
02:0010│ rbp  0x7fffffffdeb0 —▸ 0x4005c0 (__libc_csu_init) ◂— push   r15
03:0018│      0x7fffffffdeb8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
04:0020│      0x7fffffffdec0 ◂— 0x0
05:0028│      0x7fffffffdec8 —▸ 0x7fffffffdf98 —▸ 0x7fffffffe30e ◂— 0x77672f656d6f682f ('/home/gw')
06:0030│      0x7fffffffded0 ◂— 0x100000000
07:0038│      0x7fffffffded8 —▸ 0x400566 (main) ◂— push   rbp
─────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────
 ► f 0           400590 main+42
   f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /home/gwt/Desktop/1.c:9
pwndbg> x/50gx 0x602000 
0x602000:	0x0000000000000000	0x0000000000000091 <=chunk1
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000 <=chunk1_end
0x602090:	0x0000000000000000	0x0000000000000021 <=chunk2
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000021 <=chunk3
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000020f31 <=top_chunk
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000000	0x0000000000000000
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000

继续执行后和上一个示例一样,chunk1的大小变为了原来的chunk1+chunk2。

执行free:

pwndbg> x/50gx 0x602000 
0x602000:	0x0000000000000000	0x00000000000000b1
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000021
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x00000000000000b0	0x0000000000000020
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000020f31
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000000	0x0000000000000000
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty

可以看到chunk3 的size变为了0x20。free后的chunk1进入了unsortedbin,有两种情况下进入unsortedbin:

  • 当一个较大的chunk被分割为两部分后,如果剩下的部分大于minsize,就会放入unsortedbin中。
  • 释放一个不属于fastbin的chunk,并且这个chunk不和top chunk紧邻时,这个chunk就会授信啊被放到unsortedbin中。

这个例子就是上面的第二种情况,不属于fastbin,且不和top chunk紧邻。同样,之后的malloc后也可以达到对chunk2进行操作的目的。

示例3:对 free 的 smallbin 进行 extend

示例代码:

##include<stdio.h>
##include<stdlib.h>
int main()
{
    void *p, *q;
    p = malloc(0x80);//分配第一个0x80的chunk1
    malloc(0x10);//分配第二个0x10的chunk2
    free(p);//首先进行释放,使得chunk1进入unsorted bin
    *(long *)((long)p - 0x8) = 0xb1;
    q = malloc(0xa0);
}

执行free后:

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty
pwndbg> x/40gx  0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000090	0x0000000000000020
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000020f51
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000

接下来执行:*(long *)((long)p - 0x8) = 0xb1;

pwndbg> x/40gx  0x602000
0x602000:	0x0000000000000000	0x00000000000000b1
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000090	0x0000000000000020
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000020f51
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty

继续malloc:

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> info locals 
p = 0x602010
q = 0x602010

依然可以达到对chunk2进行控制。

示例4:通过extend后向overlapping

示例代码:

##include<stdio.h>
int main()
{
    void *p, *q;
    p = malloc(0x10);//分配第1个 0x10 的chunk1
    malloc(0x10); //分配第2个 0x10 的chunk2
    malloc(0x10); //分配第3个 0x10 的chunk3
    malloc(0x10); //分配第4个 0x10 的chunk4    
    *(long *)((long)p - 0x8) = 0x61;
    free(p);
    q = malloc(0x50);
}

free:

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x602000 ◂— 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

在 malloc(0x50) 后,其中 0x10 的 fastbin 块依然可以正常的分配和释放,此时已经构成 overlapping,通过对 overlapping 的进行操作可以实现 fastbin attack

示例5:通过 extend 前向 overlapping

这里展示通过修改 pre_inuse 域和 pre_size 域实现合并前面的块。

示例代码:

##include<stdlib.h>
##include<stdio.h>
int main(void)
{
    void *p, *q, *r, *t;
    p = malloc(128);//smallbin1
    q = malloc(0x10);//fastbin1
    r = malloc(0x10);//fastbin2
    t = malloc(128);//smallbin2
    malloc(0x10);//防止与top合并
    free(p);
    *(int *)((long long)t - 0x8) = 0x90;//修改prev_inuse域
    *(int *)((long long)t - 0x10) = 0xd0;//修改prev_size域
    free(t);//unlink进行前向extend
    malloc(0x150);//占位块
}

前面的几个malloc后:

pwndbg> x/80gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091 <=chunk1
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000 <=chunk1_end
0x602090:	0x0000000000000000	0x0000000000000021 <=chunk2
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000021 <=chunk3
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000091 <=chunk4
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000000	0x0000000000000000
0x602150:	0x0000000000000000	0x0000000000000000 <=chunk4_end
0x602160:	0x0000000000000000	0x0000000000000021
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000020e81
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000000	0x0000000000000000
0x6021c0:	0x0000000000000000	0x0000000000000000
0x6021d0:	0x0000000000000000	0x0000000000000000
0x6021e0:	0x0000000000000000	0x0000000000000000
0x6021f0:	0x0000000000000000	0x0000000000000000
0x602200:	0x0000000000000000	0x0000000000000000
0x602210:	0x0000000000000000	0x0000000000000000
0x602220:	0x0000000000000000	0x0000000000000000
0x602230:	0x0000000000000000	0x0000000000000000
0x602240:	0x0000000000000000	0x0000000000000000
0x602250:	0x0000000000000000	0x0000000000000000
0x602260:	0x0000000000000000	0x0000000000000000
0x602270:	0x0000000000000000	0x0000000000000000

修改prev_inuse域和prev_size后:

pwndbg> x/60gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000090	0x0000000000000020
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000021
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x00000000000000d0	0x0000000000000090
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000000	0x0000000000000000
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000021
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000020e81
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000000	0x0000000000000000
0x6021c0:	0x0000000000000000	0x0000000000000000
0x6021d0:	0x0000000000000000	0x0000000000000000

注意0x602097和0x6020d7。此时chunk1为之前malloc的4个大小之和。

通过修改prev_size域和prev_inuse域可以跨越多个chunk进行合并。

0%