이 글은 https://dreamhack.io/lecture/courses/60을 토대로 작성한 글입니다.
1. Introduction
Stack Buffer란, Stack Segment(스택 영역)에서의 지역 변수를 의미 한다.
Stack Buffer Overflow에 대해 예제를 통해서 알아보자.
2. 코드 예제
exbof.c
#include<stdio.h>
int main() {
char hi[10];
char buf[20];
scanf("%s", &buf);
printf("%s\n", hi);
return 0;
}
2.1 코드 확인
buf와 hi를 선언하고 buf에 값을 받고 hi를 출력해준다.
buf에서 값을 받는데 hi를 어떻게 출력을 할까?
buf를 입력 받을 때 bof를 일으킨다면 가능하다.
gdb를 통해서 어떻게 진행되는지 살펴보자.
2.2 gdb 확인
main+4: push rbp를 통해서 stack 안에는 rbp가 들어가게 된다.
여기서 stack에서의 rbp의 값은 이전 SFP(Stack Frame Pointer)이다.
(이전 글 Calling Convention에서 언급했다.)
main+5: mov rbp, rsp를 통해서 rsp값과 rbp값을 같게 해준다.
main+8: 그 후 rsp를 0x20만큼 빼줌으로써 stack의 공간을 확장시킨다.
stack |
---|
rsp(rbp-0x20) |
|
|
|
SFP, rbp |
ret |
현재 스택 상태를 확인해 보자.
위에 설명했던 표와 같음을 알 수 있다.
main+12: [rbp-0x20]의 주소값를 rax에 넘기고
main+16: 그 주소값을 rsi인자에 넣는다.
아하! rbp-0x20는 buf를 할당받는 공간임을 알 수가 있다.
main+43에서 출력함수인 puts를 호출하므로 rbp-0xa에는 hi가 할당되어 있음을 유추 할 수 있다.
hi는 10bytes만큼 할당 했기때문에 쉽게 유추할 수 있다.(0xa = 10bytes)
stack |
---|
buf(rbp-0x20) |
|
|
hi(rbp-0xa) |
SFP, rbp |
ret |
여기서 궁금한점?
왜 buf는 선언했을 때 20bytes만큼 선언을 했는데 왜 rsp(rbp-0x20)만큼 즉, 32bytes만큼 스택을 넓혔을 까?
buf와 hi를 합치면 0x1e 즉, 30bytes만큼 넓혀야 하는 것 아닌가?
이에 대한 답은 시스템에서는 8bytes의 단위만큼씩 읽어들인다.
그렇기 때문에 0x1e는 8의 배수가 아니므로 2bytes만큼의 NULL값을 넣어서 0x20만큼을 만들어 준다.
여기서 2bytes의 NULL값은 padding 값이라고 한다.
stack |
---|
buf(rbp-0x20) |
|
|
hi(rbp-0xa) |
SFP |
ret |
buf는 rbp에서 0x20만큼 떨어져 있습니다. 그리고 hi는 0xa만큼 떨어져 있다.
scanf는 byte에 대한 제한을 두지 않습니다.(scanf의 단점?이라고 생각할 수 있다.)
그렇다면 buf의 값을 0x20 - 0xa = 0x16(22bytes)이상의 값을 넣는다면
hi를 출력이 가능할 것이다.
3. 실행
A를 총 23bytes만큼 넣어보니
당연하게 A가 출력이 되는 모습을 볼 수 있다.
이것을 Buffer OverFlow(BOF)라고 한다.
마무리
여기까지 Stack에서 일어나는 BOF에 대해서 알아보았다.
다음 장에서는 Stack에서 BOF를 일으켜 어떻게 exploit을 하는지 알아보자.
Reference
https://dreamhack.io/lecture/courses/60