-Buffer Overflow의 개념-
Buffer Overflow는 말 그대로 메모리 상의 저장공간인 버퍼가 흘러 넘친다는 뜻이다. 사용자의 입력을 받을 때 취약한 함수나 길이 제한을 두지 않아 발생하는 취약점으로, 입력 값보다 입력 값을 저장하는 변수의 크기가 작을 때 오버플로우가 일어난다.
예를들어 500ml를 담을 수 있는 페트병에 1L의 물을 담을 시 물이 넘치게(overflow!) 되는데, buffer overflow도 이와 비슷하다. 메모리 상에서는 입력 값을 저장하는 변수 뿐 아니라, 다른 변수들도(해당 함수에서 쓰이는) 저장돼 있고 sfp(stack frame pointer)와 복귀 주소인 ret도 존재하기 때문에, 500byte를 저장할 수 있는 변수에 1000byte의 입력 값을 저장한다면 나머지 500byte가 다른 변수들이나 sfp, ret에 영향을 끼치게 되는 것이다.
이를 이용해 다른 변수의 값을 변조하거나 fake frame pointer, ret overwrite 등의 공격을 할 수 있게 된다.
-Buffer Overflow-
#include <stdio.h>
int main()
{
char buffer[10];
int flag = 0;
scanf("%s", buffer);
if(flag != 0)
printf("success!\n");
else
printf("fail..\n");
}
위는 bof에 취약한 함수인 scanf로 사용자의 입력을 받는 코드다. 입력을 받은 뒤 선언된 flag 변수가 0이 아닐 시 success라는 문구를 출력해주는데, 정상적인 방법으로는 flag 값을 바꿀 수 없기 때문에 success를 띄울 수 없다.
하지만 공격의 관점에서 생각해보면 충분히 success 문구를 띄울 수 있다. 그 이유는 아래 사진에서 나온다.
지역 변수들은 stack 메모리에 공간이 할당되는데, 위 코드는 위와 같은 stack을 형성한다. buffer는 10 크기의 char형 배열이기 때문에 스택에서 10byte의 공간을 차지하고, flag는 int형이기 때문에 4byte 공간을 차지한다. sfp와 ret는 각각 ㅡmain 함수 호출전 ebp(rbp), eip(rip) 레지스터의 값을 백업해둔 공간인데 주소의 크기는 32bit 기준으로 4byte기 때문에 4byte의 공간을 차지한다.(64bit라면 8byte의 크기를 가진다.)
어쨌든 여기서 포인트는 Buffer와 flag가 스택상에서 붙어 있다는 것인데, 만약 10byte가 아닌 11byte의 값이 입력된다면 입력 값의 끝 1byte가 flag의 공간에 침입해 값을 바꿀 수 있는 것이다.
그렇다면 flag의 값은 더 이상 0이 아니게 되므로 if문을 통해 success 문구를 띄우게 되는 것이다.
(사실 10byte만 입력해도 overflow가 일어나는데, 그 이유는 c언어에서 문자열 입력 값을 저장할 때 입력 값의 맨 끝에 문자열의 끝을 의미하는 \x00을 자동으로 붙여주기 때문이다. 따라서 10byte를 입력하면 \x00이 flag의 공간을 침입하게 되지만, 결국 \x00은 0이므로 flag 값의 변화는 일어나지 않는다.)
아래는 위 소스 코드를 컴파일한 뒤 입력 값을 바꿔보면 테스트한 모습이다. 1234, 1234567890을 넣었을 때는 fail 문구가 출력되지만 12345678901을 넣었을 때는 flag 값이 변조돼 success 문구가 출력된 것을 볼 수 있다.
gdb로 중요 부분에 bp를 걸고 실행해 확인해보면 flag 공간에 1의 아스키 코드 값인 0x31이 들어가 있는 것을 알 수 있다.
(gdb 사용법은 다음 링크에 정리해 두었다. 우리 집에 gdb 있는데 메모리 보고 갈래?(2))
-마무리-
예제로는 scanf 함수를 사용했지만, 이 외로도 길이 제한을 두지 않아 bof 취약한 함수들은 gets, strcpy, sscanf, strcat 등 여러가지 있다.
또한 취약점을 예방하고자 길이 제한을 인자로 받는 입력, 복사 함수들도 있는데(fgets, strncpy, scanf_s 등) 여기서 길이 제한을 제대로 두지 않는다면 취약점이 발생한다. 예를들어 10 크기의 buffer에 입력을 받는데 길이 제한 값으로 100을 입력한다면 당연하게도 취약점이 발생하는 것이다.
'Old (2021.01 ~ 2021.12) > Pwnable' 카테고리의 다른 글
[Linux-x64] main 함수 호출, 종료 과정 (0) | 2021.07.17 |
---|---|
Return Address Overwrite (0) | 2021.07.11 |
[Linux-x86] shellcode 제작 (0) | 2021.06.26 |
우리 집에 GDB 있는데 메모리 보고 갈래? (3) (0) | 2021.03.13 |
우리 집에 GDB 있는데 메모리 보고 갈래? (2) (0) | 2021.03.13 |