메모리와 스택구조 펌.
2005/11/25
ubject 메모리와 스택 구조 -H41d35(H41d35@RealSkulls.Team)
--------------------------------------------------------------------------------
제목 : 메모리와 스택 구조
작성자 : H41d35(H41d35@RealSkulls.Team)
참고자료 : http://litdemon.dnip.net/
http://www.null2root.org/
Securuty PLUS for Unix 저)포항공대 보안 연구회
--------------------------------------------------------------------------------
1. 메모리 와 스택 구조
버퍼 오버 플로우 공격을 이해하려면 우선 메모리 구조와 스택의 구조에 대해 서 알아
야 한다. 메모리와 스택의 구조는 OS에 따라 다르고 또 CPU에 따라 다르다.다음에
설명할 OS환경은 인텔(intel) x86계열 CPU를 사용하는 리눅스를 기본으로 하고 설명
하겠다.
1) 프로그램 실행시 메모리의 생김새
|--------------| 0x08048000(임의주소)
| Text 부분 |: 프로그램의 코드와 상수가 위치 Read Only 메모리 영역으로
| | 데이터를 쓰려고 시도 하면 Segmentation 오류를 일으킨다.
|--------------|
| Data 부분 |: 정적 변수(static vaiable)가 저장 되어 있다
|--------------|
| free |:
| |:
|--------------| *ESP
| ※ Stack부분 |: 동적으로 할당되는 데이터, 함수내의 변수, ※함수의 리턴
| | 어드레스 등이 저장되는 영역이다.
|--------------|
| agrc, argv |: 아규먼트 변수들이 위치한다. stact과 구분 되지는 않지만..
|--------------|
| environment |: UNIX(linux)의 환경 변수가 위치한다.
|--------------|
| etc : 그외의 NULL과 프로그램 실행 코드가 위치한다.
|--------------| 0xbfffffff(임의주소)
프로그램이 실행 되면 임의의 주소는 계속 변경 되어진다..그 이유는 운영체제상에서
하나의 프로그램만이 메모리를 독점 하는것 아니면. 또한 여러 프로그램이 실행 되며
메모리를 사용할 데이타크기가 가변적이기 때문이다.
2) Stack의 이해
우선 스택은 LIFO(Last In, First Out)이라 불린다 즉, 가장 나중에 스택에 들어간
데이터가 가장 먼저 나오도록 운영된다. 바꾸어 표현하면, 스택으로 확보된 기억장소에
대하여는 기억장소의 어느한쪽에서만 데이터의 삽입(insert)과 삭제(delete)가 이루어진다.
PUSH>--->┐ ┌>---->POP
│ │
n | |
n-1|--------------| PUSH는 Stack에 데이터의 삽입동작
| | POP은 Stack 에 대한 데이터의 삭제동작을 의미
|--------------|
| |
| . |
|--------------| <---- TOP (Stack Point)
| Data2 | TOP은 Stack에 대한 Push와 Pop이 이루어질 위치를 알려주며
3 |--------------| TOP은 가장 위쪽에 있는 자료 즉, 가장 늦게 들어온 데이터의
2 | Data1 | 위치를 알려 준다.
1 |______________|
※참고: Offset 오프셋이란, 두 번째 주소를 만들기 위해 기준이 되는 주소에 더해진 값을
의미한다. 예를 들어, 만약 아래의 수식에서 C가 100번지의 주소를 가리키고 있다면, 그
수식의 결과는 107번지를 의미할 것이다.
C + 7
여기서 이 수식내의 "7"이, 바로 오프셋이다.
오프셋을 이용하여 주소를 나타내는 것을 상대주소 지정방식이라고 부르는데,
그 이유는 결과 주소가 다른 지점의 상대적인 위치가 되기 때문이다.
프로그램실행시 스택 영역에는 동적으로 할당되는 데이터, 함수내의 변수, 함수의 리턴
어드레스 등이 저장되는 영역이다
여기서 중요한 것이 스택영역의 리턴어드레스 부분이다.
이 리턴어드레스를 변경 가능 하다면.... 프로그램의 흐름을 변경 할수 있다.
어떻게 리턴어드레스를 변경 할 것인가??
바로 스택영역에 입력되어질 데이터를 한계이상으로 입력 가능 하다면..ㅡ.ㅡ
바로 입력 데이타가 리턴어드레스가 들어 있는 위치까지 덮어 쓰여져 프로그램이
엉뚱하게 동작하게 된다..
한번더 생각하면 덮어 쓰여질 데이타를 우리가 원하는 동작을 하는 프로그램의
어드레스로 바꿀수 도 있다..
§리턴어드레스(Return Address)란?
C언어의 예를 들어 프로그램 실행시 코드내 함수를 부를 때 불러진 함수의 실행이
끝나고 돌아올 주소를 리턴 어드레스라고 한다.
그래서 함수의 실행이 끝나면 리턴 어드레스를 참조해 돌아온후 그 다음 프로그램
코드를 실행한다.
이것이 바로 BOF(Buffer overFlow)어택의 요점이다....^^
3) 프로그램 실행시 메모리 캡쳐
아래는 간단한 BOF버그가 있는 예제 프로그램이다..
//over.c
#include <stdio.h>
#include "dumpcode.h" //Lecture 보드에 있습니다....^^
// 스택의 Top은 레지스터 ESP에서 관리 되는데
// unsigned long get_esp(){
// __asm__("movl %esp, %eax");
// }
// 위와 같은 간단한 코딩으로 얻어 낼수 있다. eax에 값을 넣고 끝내면
// eax레지스터 값이 리턴 값이 된다.
// ※ 레지스터란 CPU가 컴퓨터를 작동시키는데 필요한 정보를 임시로 저장하
// 는 곳이다.
unsigned long get_esp(){
__asm__("movl %esp, %eax");
}
void function(char buffer[]){
char ch[16]="################"; // 위치 확인을 위해...
char buff[20]="))))))))))))))))))))";
unsigned long sp;
sp=get_esp(); // 스택의 top 번지를 얻어 낸다.
sp-=(unsigned long)(sp%16); // 프린트를 위한 코드
strcpy(buff,buffer); // buff[20]의 사이즈보다 buffer[]에 더큰사이즈의
// 데이타를 인수로 전달하면 Buffer OverFlow가 생긴다.
dumpcode((char *)sp,0xbfffffff-sp); //top에서 스택의 바닥까지 출력
printf("이런 제길 %s \n",buffer);
}
int main(int argc, char *argv[]){
char a='A';
int d=11;
int e=10;
function(argv[1]);
return 1;
}
============출력 결과===============================================
[litdemon@mos Hacking]$ ./over 12
0xbffff8a0 a0 f8 ff bf 5f 07 00 00 e8 f8 ff bf 79 89 04 08 ...._.......y...
0xbffff8b0 70 2e 01 40 f3 59 0e 40 17 f9 ff bf 20 00 00 00 p..@.Y.@.... ...
0xbffff8c0 a0 f8 ff bf 31 32 00 29 29 29 29 29 29 29 29 29 ....12.)))))))))
0xbffff8d0 29 29 29 29 29 29 29 29 23 23 23 23 23 23 23 23 ))))))))########
0xbffff8e0 23 23 23 23 23 23 23 23 18 f9 ff bf fd 89 04 08 ########........
0xbffff8f0 9a fa ff bf cd 03 00 00 27 a0 02 40 4c 9a 04 08 ........'..@L...
0xbffff900 0c b0 04 08 70 2e 01 40 f3 59 0e 40 0a 00 00 00 ....p..@.Y.@....
0xbffff910 0b 00 00 00 0c b0 04 41 98 43 0f 40 c2 46 03 40 .......A.C.@.F.@
0xbffff920 02 00 00 00 64 f9 ff bf 70 f9 ff bf 84 28 01 40 ....d...p....(.@
0xbffff930 02 00 00 00 90 86 04 08 00 00 00 00 b1 86 04 08 ................
0xbffff940 d4 89 04 08 02 00 00 00 64 f9 ff bf a8 85 04 08 ........d.......
0xbffff950 54 9c 04 08 44 a0 00 40 5c f9 ff bf d0 2e 01 40 T...D..@\......@
위의 출력 결과들은 밑으로 환경 변수와 다른 잡다한 정보들이 있지만 생략한다.
주위깊게 봐야 할 부분은 입력된 값들이 있는 위치이다.
우선 위의 출력 결과를 보고 변수들이 어떻게 위치하고 있는지 분석해 보자.
===================================================================
변수들의 값
function : 0xbffff8c0 ~ 0xbffff8c3 : sp
: 0xbffff8c4 ~ 0xbffff8d7 : buff[20] buffer의 문자열을 복사한 값
: 0xbffff8d8 ~ 0xbffff8e7 : ch[16]
: 0xbffff8e8 ~ 0xbffff8eb : 프래임 포인터
: 0xbffff8ec ~ 0xbffff8ef : 리턴 어드레스
main : 0xbffff8f0 ~ 0xbffff8f3 : argv[1]
: 0xbffff910 ~ 0xbffff913 : d
: 0xbffff90c ~ 0xbffff90f : e
위의 결과를 토대로 Function이 호출 될때의 스택의 일부분을 그려보면
0xbffff8c0 a0 f8 ff bf 31 32 00 29 29 29 29 29 29 29 29 29 ....12.)))))))))
----------- -----------------------------------
sp변수 4byte buff[20] 20byte
unsigned long :
4byte할당 C언어 참조
0xbffff8d0 29 29 29 29 29 29 29 29 23 23 23 23 23 23 23 23 ))))))))########
----------------------- -----------------------
ch[16] 16yte 할당
0xbffff8e0 23 23 23 23 23 23 23 23 18 f9 ff bf fd 89 04 08 ########........
----------------------- ----------- -----------
SFP 프래임 RET(리턴 어드레스)
포인터 Ox080489fd이다.. 스택구조상
※ Stack 구조
주소
|------------------| 0xbffff8ef
|RET(리턴 어드레스)| .
|------------------| .
| SFP 프래임 포인터| .
|------------------| .
| ch[16] | .
|------------------| .
| buff[20] | .
|------------------| .
|unsigned long sp | .
|------------------| 0xbffff8c0
이것을 보면 스택은 거꾸로(아래부터 위로)샇여 간다는 것을 알수 있다..
SFP(save frame pointer) : 변수에 접근을 용이하게 위해 사용하는 포인터이다.
※Frame Pointer Attack(1byte만 오버플로가 발생 할때 SFP를 이용한 공격법)
Pharck 몇호인지는 지금 생각이 나지 않네여.. 관심 있으시면 참조 하세요.
아래는 리턴 어드레스를 덮어 쓸수 있다는 예이다..
위의 소스를 보면 buff[20]가 20바이트인데 반해 입력인수가.. 33바이트이다..
그러므로.. buff[20]+ch[16]까지 덮어 쓴 모습이다.
여기서.. 36바이트+변경할 4바이트 어드레스를 인수로 입력하면 우리가 원하는
어드레스로 리턴어드레스를 변경할수 있다..^^
[litdemon@mos Hacking]$ ./over 123456789012345678901234567890123
0xbffff880 80 f8 ff bf 7f 07 00 00 c8 f8 ff bf 79 89 04 08 ............y...
0xbffff890 70 2e 01 40 f3 59 0e 40 f7 f8 ff bf 20 00 00 00 p..@.Y.@.... ...
0xbffff8a0 80 f8 ff bf 31 32 33 34 35 36 37 38 39 30 31 32 ....123456789012
0xbffff8b0 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 3456789012345678
0xbffff8c0 39 30 31 32 33 00 23 23 f8 f8 ff bf fd 89 04 08 90123.##........
0xbffff8d0 7b fa ff bf cd 03 00 00 27 a0 02 40 4c 9a 04 08 {.......'..@L...
0xbffff8e0 0c b0 04 08 70 2e 01 40 f3 59 0e 40 0a 00 00 00 ....p..@.Y.@....
0xbffff8f0 0b 00 00 00 0c b0 04 41 98 43 0f 40 c2 46 03 40 .......A.C.@.F.@
예를 들어 BOF버그가 있는 프로그램이 SetUID가 설정된 프로그램일 경우 메모리상에 쉘을
띄워주는 프로그램을 상주시키고 BOF버그가 있는 프로그램의 리턴 어드레스를 그 실행코드
주소로 변경하면... 그 파일소유자 계정의 쉘을 띄울수 있다..^^
------------------------------------------
[t:/] is not "technology - root". dawnsea, rss