ii4gsp

[1] 버퍼 오버플로우 (Buffer Overflow) 개념 본문

시스템 해킹/Technique

[1] 버퍼 오버플로우 (Buffer Overflow) 개념

ii4gsp 2019. 11. 16. 15:48

1.버퍼 오버플로우(Buffer Overflow)란?

 

버퍼 오버플로우(Buffer Overflow) 줄여서 BOF라고도 한다.

시스템 해킹의 대표적인 공격 방법 중 하나이며, 버퍼(Buffer)라는 것은 보통 데이터가 저장되는 메모리 공간을 일컫는데 단순히 메인 메모리만이 아닌 다른 하드웨어에서 사용하는 임시 저장 공간 역시 버퍼(Buffer)라고 부른다.

 

컴퓨터 시스템 내에서 프로그램이 사용하는 메모리 영역을 정해진 범위 밖까지 메모리가 넘치게하여 프로그램의 실행 흐름을 바꾸거나 특정 데이터를 변조하는 방식의 공격 방법을 의미한다.

 

버퍼 오버플로우(Buffer Overflow) 공격 기법을 이해하기 위해서는 무엇보다 컴퓨터에서 실행되는 프로세스의 구조와 자료 저장 방식, 함수 호출 과정 및 리턴 과정, 함수 실행 과정에 대한 정확한 이해가 필요하다.

 

 

2. 8086 Memory Architecture

 

다음BOF공격을 하기위해서는 메모리구조를 필수적으로 알아야한다.

 

8086 시스템의 기본적인 시스템 메모리 구조는 <그림 1>과 같다.

 

출처: 달고나 문서

시스템이 초기화 되기 시작하면 시스템은 커널을 메모리에 적재시키고 가용 메모리 영역을 확인하게 된다.

시스템은 운영에 필요한 기본적인 명령어 집합을 커널에서 찾기 때문에 커널 영역은 반드시 하위 주소에 위치한다.

 

출처: 달고나 문서

다음으로 알아야 할 것은 하나의 프로그램이 실행되기 위한 메모리 구조이다.

운영체제는 하나의 프로세스를 실행시키면 이 프로세스를 segment라는 단위로 묶어서 가용 메모리 영역에 저장한다.

하나의 segment는 <그림 2>의 오른쪽에 나와있는 구조를 가지고있다.

각각을 code segment, data segment, stack segment라고 한다.

시스템에는 최대 16,383개의 segment가 생성될 수 있고 그 크기와 타입은 모두 다양하게 생성 될 수 있다.

 

Code Segment

code segment에는 시스템이 알아들을 수 있는 명령어 즉 instruction들이 들어 있다. (기계어 코드로써 컴파일러가 만들어낸 코드) instruction들은 명령을 수행하면서 많은 분기 과정과 점프, 시스템 호출 등을 수행하게 되는데 분기와 점프의 경우 메모리 상의 특정 위치에 있는 명령을 지정해 주어야 한다.

 

하지만 segment는 자신이 현재 메모리 상에 어느 위치에 저장될지 컴파일 과정에서는 알 수 없다.

그러므로 정확한 주소를 지정할 수 없다.

segment에서는 Logical address를 사용한다. Logical address는 실제 메모리 주소는 아니지만 실제 메모리 상의 주소 (physical address)와 매핑되어 있다. 즉 segment는 segment selector에 의해서 자신의 시작 위치(offset)를 찾을 수 있고 자신의 시작 위치로부터의 위치(logical address)에 있는 명령을 수행할 지를 결정하게 되는 것이다.

 

따라서 실제 메모리 주소 physical address는 offset + logical address라고 할 수 있다.

 

출처: 달고나 문서

<그림 3>에서 보이는 것과 같이 segment0x80010000에 할당받았다고 되있다.

segment는 자신의 시작위치(offset)0x80010000인것을 알수있다.

code segment 내에 들어 있는 하나의 instruction IS 1를 가르키는 주소는 0x00000100 이다.

이것은 logical address이고 실제 메모리 상의 주소는 segment offset0x80010000segment내의 주소 0x00000100을 더한 0x80010100이 된다. segment가 메모리상의 어느 위치에 있더라도 이런방식으로 instruction의 정확한 위치를 찾아낼 수 있게 된다.

 

Data Segment

data segment에는 프로그램이 실행시에 사용되는 데이터가 들어간다. 여기서 말하는 데이터는 전역 변수들이다.

프로그램 내에서 전역 변수를 선언하면 그 변수가 data segment에 자리잡게 된다. data segment는 다시 네 개의 data segment로 나뉘는데 각각 현재 모듈의 data structure, 상위 레벨로부터 받아들이는 데이터 모듈, 동적 생성 데이터, 다른 프로그램과 공유하는 공유 데이터 부분이다.

 

Stack Segment

stack segment지역 변수들이 자리잡는 공간이며, 현재 수행되고 있는 handler, task, program이 저장하는 데이터 영역으로 우리가 사용하는 버퍼가 바로 이 stack segment에 자리잡게 된다. 또한 프로그램이 사용하는 mutiple 스텍을 생성할 수 있고 각 스텍들간의 switch가 가능하다.

 

3. 8086 CPU Register Structure

위에서 하나의 Segment가 세가지 Segment로 나누어지는 구조를 알아보았다.

그러면 이제 CPU가 프로세스를 실행하기 위해 프로세스를 CPU에 적재시켜야 한다.

CPU가 재빨리 읽고 쓰기를 해야 하는 데이터들이므로 CPU내부에 존재하는 메모리를 사용하는데 이 저장공간을 레지스터(register) 라고한다. 레지스터(register)는 속도가 매우빠르다.

 

레지스터(register)는 목적에 따라서 범용 레지스터(General-Purpose Register), 세그먼트 레지스터(Segment Register), 플레그 레지스터(Program status and control Register), 인스트럭션 포인터(Instruction Pointer)로 구성된다.

 

범용 레지스터(General-Purpose Register)

 

논리 연산, 수리 연산에 사용되는 피연산자, 주소를 계산하는데 사용되는 피연산자, 그리고 메모리 포인터가 저장된다.

 

출처: 달고나 문서

범용 레지스터에는 EAX, EBX...ESP 레지스터로 구성되어 있으며 각 레지스터는 목적을 가지고 있다.

 

EAX - 피연산자와 연산 결과의 저장소

 

EBX - DS Segment안의 데이터를 가리키는 포인터

 

ECX - 문자열 처리나 루프를 위한 카운터

 

EDX - I/O 포인터

 

ESP - SS 레지스터가 가리키는 Stack Segment의 맨 꼭대기를 가리키는 포인터

 

EBP - SS 레지스터가 가리키는 스택 상의 한 데이터를 가리키는 포인터

 

세그먼트 레지스터(Segment Register)

 

Code Segment, Data Segment, Stack Segment 를 가르키는 주소가 들어있는 레지스터이다.

 

출처: 달고나 문서

CS레지스터 - Code Segment를 가리킨다

 

(DS, ES, FS, GS)레지스터 - Data Segment를 가리킨다

 

SS레지스터 - Stack Segment를 가리킨다

 

플래그 레지스터(Program status and control Register)

 

출처: 달고나 문서

프로그램의 현재 상태나 조건 등을 검사하는데 사용되는 플래그들이 있는 레지스터이다

 

인스트럭션 포인터(Instruction Pointer)

출처: 달고나 문서

다음 수행해야하는 명령(Instruction)이 있는 메모리 상의 주소가 들어가 있는 레지스터이다

 

 

Comments