'Buffer Overflow Attack'에 해당되는 글 2건

  1. 2008.11.18 Buffer Overflow Attack - Shellcode
  2. 2008.11.18 Buffer Overflow Attack - Buffer Overflow 기본원리
Hacking & Security/System2008. 11. 18. 17:58
사용자 삽입 이미지

2007/05/02(수)
전략마케팅실 기술기획 / 대리 이성열

지난 강좌에서 Buffer Overflows 공격의 원리에 대해서 간단한 샘플코드를 이용하여 살펴보았다. 이번 강좌에서는 주어진 크기의 데이터 공간에 위치하지 못한 데이터가 메모리에 쓰여져 시스템의 임의의 명령을 실행시키도록 하는 코드 즉, 쉘코드(shellcode)를 작성하는 방법을 살펴보도록 한다.

Shellcode란?
Shellcode란 시스템의 특정 명령을 실행하도록 하는 기계어 코드로 기본적으로 어셈블리(Assembly) 언어로 작성된 프로그램을 이진 덤프(binary dump)함으로서 얻을 수 있으며, Buffer Overflow 공격에서 shellcode는 시스템에서 할당한 기억공간(Buffer)보다 큰 데티어로 메모리의 특정 위치에 저장되어 공격자에 의도하는 결과를 이끌어낸다.

Shellcode와 레지스터(Register), 어셈블리(Assembly)
Buffer Overflow 공격 시 공격자가 취약한 시스템으로 전송한 shellcode는 CPU의 레지스터 영역에 쓰여지게(Overwrite) 된다.
시스템의 레지스터는  여러 가지가 있으나 Shellcode는 이중 EAX, EBX, ECX, EDX 레지스터 영역에 쓰여져 시스템의 정상적인 실행 명령대신 shellcode가 의미하는 명령을 실행하게 한다. 이렇게 시스템의 레지스터에 실행명령을 overwrite되는 shellcode는 사람이 이해할 수 없는 기계어로 작성되는데 이를 위해서 Assembly 언어로 작성된 프로그램을 이진 덤프(Binary dump)하여 얻을 수 있다.

여기서 간단하게 Assembly 언어를 이용하여 임의의 명령을 실행하는 방법을 알아보자면, 임의의 명령어가 실행하기 전에 명령어(정확하게 표현하자면 '시스템 호출')를 식별할 수 있는 코드가 eax 레지스터에 기억되고 나머지 abx, ecs, edx 레지스터에는 시스템 호출 시 넘겨지는 매개변수 값이 저장된다.
eax ~ edx 레지스터에 시스템 호출에 필요한 값들을 저장하였으면, 그 다음으로는 0x80 인터럽트를 발생시켜 cpu가 레지스터에 저장된 값들을 가지고 시스템 호출을 실행한다.


Shellcode 예제 1 - exitshell
Shellcode 작성의 첫번째 예제는 프로그램을 종료하는 exit() 함수를 shellcode로 작성하여 shellcode 작성법을 살펴보도록 본다.

Shellcode도 다른 일반 프로그램과 마찬가지로 함수들의 조합으로 작성되는 프로그램으로 함수를 호출하기 위해서는 아래의 두 가지 사항을 알아야 한다.


● 호출하려는 함수의 시스템 호출 방법
   √  Unix Like : 시스템 호출 번호
   √  Windows : 시스템 호출의 메모리 주소
● 시스템 호출의 매개변수 값

먼저 시스템 호출 방법은 Unix 시스템과 Windows 시스템과 차이가 있는데, Linux 등과 같은 Unix like 시스템 호출을 정의한 헤더파일에서 시스템 호출번호를 이용하여, Windows 계열의 운영체제에서는 kernel23.dll을 별도의 도구를 이용하여 호출하려는 시스템의 주소를 이용한다.

사용자 삽입 이미지

 [그림 1 : /usr/include/asm/unistd.h에 정의된 시스템 호출]


사용자 삽입 이미지

 [그림 2 : dumpbin 프로그램을 이용한 kernel32.dll의 메모리 정보]


사용자 삽입 이미지

[그림 3 : dumpbin 프로그램을 이용한 kernel32.dll내 시스템 호출 메모리 정보]

첫 번째 예제로 작성할 exitshell을 Linux 시스템에서 C언어로 작성한다면 다음과 같은 함수가 된다.

사용자 삽입 이미지

위 C언어로 작성된 프로그램과 동일하게 실행하는 프로그램을 어셈블리 언어로 작성하기 위해서는 아래의 사항에 대한 확인이 필요하다.


● exit() 함수의 시스템 호출번호
● exit() 함수 호출시 매개변변수 값

위 두 가지 중 exit() 함수에 대한 호출번호는 /usr/include/asm/unistd.h 파일에서 확인하면 '1'로 정의되어 있으며, 매개변수 값은 오류 없이 실행이 종료되었음을 의미하도록 '0'으로 설정한다.


이렇게 확인한 정보들을 이제는 레지스터에 저장하는데 각 사항을 저장하는 위치는 아래와 같다.


● eax 레지스터 : exit() 함수의 시스템 호출번호
● ebx 레지스터 : exit() 함수 호출시 매개변변수 값

이제까지의 내용을 어셈블리 언어로 작성하여 완성된 코드는 아래와 같다.

사용자 삽입 이미지

 exitshell.s

● Line 03 ~ 04: eax 레지스터에 exit() 시스템 호출 번호 '1' 저장
● Line 05 ~ 06 : ebx exit() 시스템 호출 매개변수 값 '0' 저장
● Line 07 : exit(0) 실행을 위한 인터럽트 발생


작성된 코드를 컴파일 및 링크시키고 정상적인 실행을 확인한 후 생성된 실행 파일을 덤프하면 최종적인 shellcode를 얻을 수 있다.

사용자 삽입 이미지

사용자 삽입 이미지

 
[그림 4 : exitshell.s의 실행 및 이진덤프를 통한 shellcode 작성]

이번 강좌에서는 간단한 함수 호출을 통해서 어셈블리 언어 프로그래밍과 이를 통하여 shellcode를 생성하는 단계까지 소개하였다.

다음 강좌에서는 shellcode 작성 시 유의하여 할 사항 및 shellcode 작성에 대해서 좀더 구체적으로 살펴보는 시간을 갖도록 하자.

- 끝 -

 
출처 : < AHNLAB coconut >
Posted by skensita
Hacking & Security/System2008. 11. 18. 17:51
사용자 삽입 이미지

2007/04/02(월)
전략마케팅실 기술기획 / 대리 이성열

'Buffer Overflow 공격'.. 보안에 대해서 관심있는 사람뿐 아니라 시스템/네트웤, 개발자에 이르기까지 한 번 쯤은 들어봤을 만한 용어이다. 적어도 IT분야에서는 널리 알려진 이 용어에 대해서 인터넷, 보안서적 등을 살펴보면 "지정된 크기의 저장공간(Buffer) 보다 넘치게(overflow) 입력되는 Overflow 현상을 이용하여 Buffer에 입력되지 못한 조작된 데이터를 시스템의 특정 위치에 기록하여 공격하는 기법" 이라는 간략한 설명으로 시작되는 Buffer Overflow에 대해서 그 원리에 대해서 충분히 이해하기란 쉽지않아 이번 Lecture에서는 Overflow 공격의 기본 원리를 Buffer Overflow 공격기법 중 하나인 Stack Overflow를 중심으로 정리한다.


기본 메모리 구조 - Stack, Heap, Code
Overflow 공격을 설명하기에 앞서서 우선은 시스템의 메모리 구조에 대한 이해가 필요하다. 일반적인 시스템에서 메모리는 아래의 그림처럼 3가지로 구분되는데 메모리의 상세구조에 대해서 설명하기 보다는 우선 Stack Overflow 공격과 관련된 Stack 영역과, Code 영역에 대한 이해를 돕기로 한다.

사용자 삽입 이미지

[그림 1] 일반적인 메모리 구조


STACK 영역

Stack 영역은 프로그램안에 함수에 의해서 선언된 변수에 할당되는 영역으로 시스템이 특정 함수를 실행하는 경우 함수내에 선언된 변수와 이들 값을 저장하기 위해서 할당되었다가, 함수의 실행이 종료되면서 해제되는 영역이다.
프로그램의 함수가 실행되면 Stack 영역에 Stack Frame 이라는 영역이 함수에 할당되는데 이 Stack Frame에 해당 함수가 실행하는데 필요한 정보들이 저장되어있다.

사용자 삽입 이미지

[ Stack & Stack Frame ]


CODE 영역
Code 영역은 프로그램이 실질적으로 실행될 명령어가 저장되는 공간으로 기계어로 프로그램(또는 함수)의 실행코드가 기계어 형태로 저장되어있다.



Buffer Overflow에 취약한 프로그램?
Buffer Overflow에 취약한 프로그램에 대해서 설명하기 전에 우선은 아래의 샘플코드를 살펴보자.
먼저 6라인의 char var[10]; 부분에서는 var라는 변수에 최대 10Byte의 자료가 저장될 수 잇는 공간을 할당하였다. 다음 7라인을 보면 strcpy()함수를 실행하는데 6라인에서 선안한 10Byte 크기의 var 변수공간에 32byte 크기의 문자열을 저장하고 있어 이 샘플코드를 컴파일하고 실행하면 Buffer Overflow 현상이 발생하여 프로그램이 정상적으로 실행하지 못할 것을 예상할 수 있다.

사용자 삽입 이미지

위 샘플코드를 컴파일하고 실행하고 로그를 확인한 결과를 다음에 보여주는데 프로그램이 실행한 직후 프로그램상에서 오류가 발생하였으며, 이벤트 로그를 확인한 결과 주소 0x45454545 부분에서 문제가 발생했음을 알 수 있다.

사용자 삽입 이미지

[ 샘플코드 실행결과 ]

 

사용자 삽입 이미지

[ 로그 확인 결과 ]


Buffer Overflow 현상과 Stack Frame
이제 지정한 크기의 저장공간에 큰 값을 입력하였을 경우 시스템 내부적으로 어떻게 동작하여 Overflow가 발생하면서 오류가 발생하는지 살펴보자.

최초 샘플프로그램이 실행되면서 Stack 영역에 하나의 Stack Frame에 할당되며, 이 Stack Frame에 'var' 변수를 위한 공간이 할당된다.

그 다음으로 scrcpy()함수가 실행되면서 'var'변수에 문자열 'AAAABBBBCCCCDDDDEEEEFFFF GGGGHHHH' 문자열이 저장되는데 문제는 12byte 크기의 저장소에 32byte 크기의 문자열이 저장되면서 'var'에 할당된 12byte 까지는(주1) 정상적으로 저장될 것이다.

※ 주1 : 샘플 프로그램에서 'var'에 할당한 메모리 크기는 10byte 이지만 테스트한 시스템은 32bit 시스템으로 실제 'var' 변수에는 12byte의 공간이 할당되며, 문자열도 12byte 크기가 저장된다.)

그렇다면 'var'에 저장되고 남은 문자열은 어디에 있는지 살펴보면, 운영체제가 var에 할당해준 12byte 공간에 이어서 문자열이 저장되는 것을 메모리 맵을 통해서 확인할 수 있다.

사용자 삽입 이미지

[ 문자열 저장확인 ]

이제 주어진 문자열이 지정한 공간의 넘어서 메모리에 쓰여졌을을 확인하였는데, 이렇게 불필요하게 쓰여진 데이터가 프로그램에 미치는 영향을 확인해야 한다.

Strack Frame의 구조를 다시 살펴보면 Stack Frame의 argument영억에 이어서 Instruction 영역이 존재하는데 Instruction 영역은 함수가 종료한 후에 실행될 명령어가 저장된 주소값을 가지고 있다.
따라서 위 그림에서 '45 45 45 45' 문자열에 위치한 곳은 strcpy()함수가 실행되고 다음 실행할 명령어가 있는 위치한 주소값을 저장한 곳이다.

그러나 잘못된 프로그래밍에 의해서 strcpy() 다음 명령어가 저장된 주소값이 지워져 버린것이다.
이를 확인하지 위해서 메모리 주소 '45 45 45 45 '를 확인한 메모리 맵이 아래 그림이다.

사용자 삽입 이미지


메모리 상의 '45 45 45 45' 위치를 확인한 결과 '?' 표기로 되어있어 아무런 기계어 코드가 없는 것을 확인할 수 있으며, 프로그램은 strcpy()를 실행한 후에 '45 45 45 45' 위치의 '????' 명령어를 실행하던 중 오류가 발생한 것이며 프로그램의 각 실행코드와 메모리 동작을 나타내면 아래 그림으로 표현 할 수 있다.
 

사용자 삽입 이미지


지금까지 살펴본 내용은 Buffer Overflow 현상이 발생하는 과정을 메모리 특히 Stack 영역에 국한하여 살펴보았으며, 다음 강좌에서는 Overflow 취약점을 이용하여 임의의 명령어를 실행하는 방법을 설명하면서 메모리 동작을 더욱 자세하게 살펴보겠다.



출처 : http://www.coconut.co.kr/board/seculetter.php?id=seculetter
Posted by skensita