*초보자가 작성한 글이므로 완벽하지 않을 수 도 있습니다 
 부족한 점이 있다면 지적해주시고 고쳐주시면 감사하겠습니다*
----------------------------------------------------------------------------------------------

0xb000000(낮은 주소)                                             0xbffffff(높은 주소)

낮은주소                                                                    높은주소 
 Stack         Heap             Bss                Data                 Text

* 스택은 거꾸로 자랍니다! 변수를 선언하면 선언할수록 메모리의 높은주소 에서 메모리의 낮은 주소로 향합니다! 이 부분은 직접 gdb로 분석 해보시다 보면 이해가 가실겁니다! *

이러한 식으로 메모리 구조가 이루어져있고 이번에 포스팅할 게시글은 
Stack 을 이용한 버퍼 오버플로우를 소개하겠습니다

[ 버퍼 오버플로우 - 버퍼를 초과시켜서 공격자가 원하는 대로 프로그램의 흐름을 만들어 작동시키는 것 입니다!]

Stack은 프로그래밍을 할때 함수 내부에서 선언하는 변수들이 들어가게 됩니다
또 한 스택은 먼저 들어간것은 가장 나중에 뺄 수 있습니다! 
버스기사 님들의 동전을 생각하면 되겠네요 동전을 넣어가면 점점 쌓이게 되고
그 동전을 빼려고 하면 위에서 부터 뺄수 잇겠지요 ?
(너무 진지하게 아래서 나오잖아요! 라곤 생각하지 맙시다! 그냥 저렇게 생각하시라구요!)
아니면 설거지를 하고 접시를 차곡차곡쌓는다 할때 먼저 설거지가 끝난 순서대로 접시를 쌓아 올리겠죠 ? 그 접시를 사용하려면 위에 접시부터 빼야지 아래 접시부터 빼서 쓰지는 않잖아요! 그런겁니다!

스택의 이러한 입출 방식을 기억하고 있으셔야지 좀 더 이해가 쉬우실겁니다!

자 이제 버퍼 오버플로우에서 버퍼란 ? 
데이터를 일시적으로 저장하는 메모리의 영역을 뜻합니다!
또한 스택 안에서 생성이 됩니다! 
또한 버퍼 오버플로우는 C , C++ , 어셈블리어 에서만 주로 발생을 하지
Java , Perl , Python 같은 언어들은 메모리를 자체적으로 관리하기 때문에 버퍼 오버플로우가 발생하지 않는다고 합니다! C#의 경우는 보호 기능을 제공하구요 
자 이제 여기서 버퍼 오버플로우가 어느 상황에서 발생하느냐!

[본 소스는 해커스쿨에서 제공하는 FTZ LEVEL 9 입니다]

버퍼 오버 플로우를 간단하게 이해하고 사용해보기 위하여 만들어진 소스네요!
buf , buf2에 각각 10의 크기가 할당 되어 있습니다!

[*주의* 데이터 영역의 전역 변수는 " 메모리의 낮은 주소 " 에서 " 메모리의 높은 주소 " 로 자라납니다
스택 영역은 " 메모리의 높은 주소 " 에서 "메모리의 낮은 주소" 로 자라납니다!
이번 글에서 다룰 영역은 --스택-- 영역입니다!"

자 그렇다면 아주 간단하게 스택을 만들어보죠 
/---------------------------------------/
|                                      |

|           buf 2  [10]              |

|           buf  [10]                | 

|                                     |

/-----------------------------------------/

이러한 식으로 스택이 들어간다는 소리입니다!

만약에 여기서 1,2,3,4,5  = buf 2 A,B,C,D,E = buf  이렇게 들어간다면 어떻게 될까요 ? 
/---------------------------/ 메모리 높은 주소
|           ret             |
/---------------------------/
|           sfb             |
/---------------------------/
|             5             |
|             4             |
|             3             |
|             2             |
|             1             |
/---------------------------/
|             E             |
|             D             |
|             C             |
|             B             |
|             A             |
/---------------------------/ 메모리 낮은 주소 

높은 주소에서 낮은 주소로 자란다는 것이 어떤것인지 이해 하셨을거라 생각하겠습니다!
자 다시 한번 저 소스의 스택을 보죠!

/---------------------------/ 메모리 높은 주소
|           ret             |
/---------------------------/
|           sfb             |
/---------------------------/
|          buf2 [10]       |
/---------------------------/
|          buf [10]        |
/---------------------------/

ret와 sfb는 각각 4바이트를 가지고있습니다!

근데 소스를 보면

stdin으로 40만큼의 크기를 buf에 넣어버리네요!

근데 지금 buf에는 10의 크기가 할당 되어 있습니다 

여기서 만약 10을 넘는 크기를 넣어주면 어떻게 될까요 ?

좀 더 편히 설명하기 위해서 buf 에는 5의 크기가 할당 되어 있고 5를 넘는 크기를 넣어 준다고 가정 하겠습니다! (단순히 크기만 10에서 5로 바뀌어서 설명하는겁니다!)

buf 에다가 8를 넣어보겠습니다!

/---------------------------/ 메모리 높은 주소
|           ret[4]          |
/---------------------------/
|           sfb[4]          |
/---------------------------/
|             5             |
|             4             |
|             H             |     buf2[5]
|             G             |
|             F             |
/---------------------------/
|             E             |
|             D             |
|             C             |     buf[5]
|             B             |
|             A             |
/---------------------------/ 메모리 낮은 주소

buf 에서만 입력한 영어들이 buf2 까지 올라갔네요! 입력된 것을 모두 저장하기 위해서 buf 에만 할당한 스택을 넘어서 buf2 라는 다음 메모리 영역까지 사용을 해버렸습니다.

근데 위에 sfb 와 ret 라는 친구들이 보이지요 ? 
만약 buf[5] 와 buf2 [5]의 합 크기 10 을 넘어선 값을 입력하게 된다면..?
sfp와 ret 까지 침범하게 될겁니다 .

자 여기서 sfp와 ret가 무엇이냐 ?

sfp - 함수 프롤로그에서 push ebp 에 의해서 저장된 ebp에 값입니다!
[함수에서 지역변수들이 사용될 때 EBP가 기준으로 사용이 됩니다.
그런데 함수를 하나만 사용하는것이 아니잖아요 ? 다른 함수로 넘어갔다가 다시 돌아올 때 함수가 시작햇을 당시 처음의 EBP 주소로 이동하기 위해서 저장해두는 값입니다!] 

ret - 함수가 임무를 수행하고 끝마친뒤 다음에 실행되어야할 " 명령이 위치한 메모리의 주소" 를 뜻합니다 
만약 근데 버퍼 오버플로우가 일어나서 ret 부분에 공격자가 원하는 공격이 위치한 메모리의 주소로 덮어씌어버린다면? 
공격자가 원하는 공격을 하도록 흐름이 바뀌겟지요 ?  


[gcc = GNU에서 만든 C컴파일러 이고 전처리기 , 컴파일러 ,어셈블러, 링커를 호출해주는 역할을 한다]

gcc 2.96 이상 버전으로 업그레이드 되면서 버퍼의 각 변수뒤에 dummy값이 생기게 되었습니다 

아까 와 같은 스택을 gcc2.96 이상에서 컴파일 하게 된다면

/---------------------------/ 메모리 높은 주소
|           ret[4]          |
/---------------------------/
|           sfb[4]          |
/---------------------------/
|             ?             |
|             ?             |
|             ?             |     dummy[?]
|             ?             |
|             ?             |
/---------------------------/
|             5             |
|             4             |
|             3             |     buf2[5]
|             2             |
|             1             |
/---------------------------/

|             ?             |
|             ?             |
|             ?             |     dummy[?]
|             ?             |
|             ?             |
/---------------------------/
|             E             |
|             D             |
|             C             |     buf[5]
|             B             |
|             A             |
/---------------------------/ 메모리 낮은 주소


이러한 식으로 버퍼의 각 변수 뒤에 dummy값이 형성이 됩니다 
그리고 이러한 dummy값 때문에 오버플로우를 일으켜서 ret에 덮어 씌우는 작업이
좀 더 어려워졌습니다

자 이제 여기서 dummy 값을 정확히 파악하기 위해서 gdb를 이용해 분석을 합니다.
[어셈블리와 gdb 사용법에 대해서 공부를 해야합니다 ]

gdb를 분석한 뒤 dummy 값을 찾아낸 뒤에 자신이 공격을 할 주소의 자신이 원하는 흐름대로 프로그램을 이끌어갈 주소를 넣으면 
이것이 바로 버퍼 오버플로우 공격입니다 
여기까지가 스택을 이용한 버퍼 오버플로우의 기본이였습니다 . 감사합니다 

+ Recent posts