본문 바로가기

전공 공부/정보보안개론

ch.5 코드보안 / 연습문제 5장

728x90

01. 시스템과 프로그램

02. 버퍼 오버플로 공격

03. 포맷 스트링 공격

04. 메모리 해킹

 

01. 시스템과 프로그램

 1. 시스템 메모리 구조

  -어떤 프로그램을 동작시키면 프로그램이 동작하기 위한 가상의 공간이 메모리에 생성됨. 이 메모리 공간은 목적에 따라 상위(스택 stack)와 하위(힙(heap))로 나뉜다.

 

  1.1 스택 영역과 힙 영역

   +스택 영역 - 프로그램 로직이 동작하기 위한 인자와 프로세스 상태를 저장하는 데 사용.

     -레지스터의 임시 저장, 서브루틴 사용 시 복귀 주소 저장, 서브루틴에 인자 전달 등에 사용

     -메모리의 상위에서 하위로 사용하며 후입 선출(Last In First Out, LIFO) 원칙에 따라 나중에 저장된 값을 먼저 사용

     

   +힙 역역 -  프로그램이 동작할 때 필요한 데이터 정보를 임시로 저장하는 데 사용.

     - 프로그램이 실행될 때까지 알 수 없는 가변적인 양의 데이터를 저장하기 위해 프로그램 프로세스가 사용할 수 있도록 미리 예약된 메인 메모리의 영역.

     - 프로그램에 의해 할당되었다가 회수되는 작용이 되풀이 됨

 

  1.2 레지스터 : CPU의 임시 메모리로 CPU 연산과 어셈블리어의 동작에 필요하다

이름(80386R) - 용도

 

범용 R

  • 누산기(EAX) - 산술 연산에 사용
  • 베이스 R(EBX) - 특정 주소 저장(주소 지정을 확대하기 위한 인덱스로 사용)
  • 카운트 R(ECX) - 반복적으로 실행되는 특정 명령에 사용(루프의 반복 횟수나 좌우 방향 시프트 비트 수 기억)
  • 데이터 R(EDX) - 일반 데이터 저장(입출력 동작)

 

세그먼트 R

  • 코드 세그먼트 R(CS) - 실행 기계 명령어가 저장된 메모리 주소 지정
  • 데이터 세그먼트 R(DS) - 프로그램에서 정의된 데이터, 상수 직업 영역의 메모리 주소 지정
  • 스택 세그먼트 R(SS) - 프로그램이 임시로 저장할 필요가 있거나 사용자의 피호출 서브루틴이 사용할 데이터와 주소 포함
  • 엑스트라 세그먼트 R(ES, FS, GS) - 문자 연산과 추가 메모리 지정에 사용되는 여분의 R

 

포인터 R

  • 베이스 P(EBP) - SS R와 함께 스택 내의 변숫값을 읽는 데 사용
  • 스택 P(ESP) - SS R와 함께 스택의 가장 끝 주소를 가리킴
  • 명령 P(EIP) - 다음 명령어의 오프셋(상대 위치 주소)을 저장하며 CS R와 합쳐져 다음에 수행될 명령의 주소 형성

 

인덱스 R

  • 목적지 인덱스(EDI) - 목적지 주소의 값 저장
  • 출발지 인덱스(ESI) - 출발지 주소의 값 저장

 

플래그 R

  • (EFLAGS) - 연산 결과 및 시스템 상태와 관련된 여러 가지 플래그 값 저장

 

 2. 프로그램 실행 구조

프롤로그(prolog) : push % ebp와 mov % esp, % ebp는 새로운 함수를 시작할 때 항상 똑같이 수행하는 명령.

 

3. 셸

: OS를 둘러싸고 있으면서 입력받는 명령어를 실행하는 명령어 해석기.

-본(bourne), C, 콘(korn)으로 나뉨

-셸을 공부하는 이유는 버퍼 오버플로나 포맷 스트링 공격을 통해 얻고자 하는 것이

'관리자 권한'의 셸이기 때문!

-/bin/sh 명령으로 실행.

 

 

4. 프로세스 권한과 SetUID

-유닉스에서 rwsr-x-xr-x처럼 x의 자리에 setUID 비트를 설정해주면 소유자인 것 마냥 root 권한을 사용하기 때문에 위험.

 

02. 버퍼 오버플로 공격

: 형태와 길이에 대한 불명확한 정의로 인한 문제로 덮어쓸 수 없는 부분에 임의의 코드를 덮어쓰는 것

 

2. 공격 원리

EX) bugfile.c

1) int main(int argc, char *argv []){

 2) char buffer [10];

 3) strcpy(buffer, argc [1]);

 4) printf("% s\n", &buffer);

} -> bugfile abcd를 입력하면 abcd를 출력하는 프로그램

 

1) argc : 취약한 코드인 bugfile.c가 컴파일되어 실행되는 프로그램의 인수 개수

  *argv [] : 포인트 배열로서 인자로 입력되는 값에 대한 번지수를 차례대로 저장

   argv [0] - 실행파일 이름 / argv [1] - 첫 번째 인자 내용 / argv [2] - 두 번째 인자 내용

 

2) 10바이트 크기의 버퍼를 할당

3) 버퍼에 첫 번째 인자를 복사한다(abcd값을 버퍼에 저장) [여기서 버퍼 오버플로 공격이 일어난다]

4) 출력

 

위의 코드를 gdb파일로 봤을 때

 1 push % ebp

 2 mov  % esp,%ebp -> 스택에 EBP 값을 밀어넣고 현재의 ESP 값을 EBP R에 저장

 3 sub   $0xc, %esp -> 2) 부분을 실행하는 과정 10바이트를 할당했지만 메모리에서는 4바이트 단위로 할당되어

                              실제로 할당되는 메모리는 12바이트 

 4 mov 0xc(% ebp),%eax -> EBP에서 상위 12바이트(0xC) 내용을 EAX R에 저장하면 EAX R는 RET 보다 상위 주소의 값을 읽어 들인다.

 5 add $0x4,%eax -> EAX 값을 4바이트만큼 증가시킨다. argv []에 대한 포인터이므로 argc [1]을 가리킨다.

 6 mov (%eax),% edx -> EAX R가 가리키는 주소의 값을 EDX R에 저장.

 7 push %edx -> 프로그램을 실행할 때 인수에 대한 포인터를 스택에 저장한다. 인수를 넣지 않고 프로그램을                                     실행하면 0X0의 값이 스택에 저장됨

 8 lea 0xfffffff4(%ebp),% eax -> EAX R에 12(%EBP)의 주소 값을 저장

#lea(load effective address) : 왼쪽 피연산자의 주소(메모리)를 오른쪽 피연산자(R)로 전송. 보통 C에서 포인터 변수를

설정하는 데 사용

 9 push %eax -> 스택에 EAX R값을 저장

10 call 0x8048340 <strcpy> -> 3)을 실행하기 위해 관련된 사항을 스택에 모두 상주시키고 strcpy명령 호출

 

3. 대응책

버퍼 오버플로에 취약한 함수를 안 쓰거나 최신 os 쓰기

함수

strcpy(char *dest, const char *src); / strcat / getwd / gets / fscanf / scanf / realpath / sprintf

 

03. 포맷 스트링 공격

 1. 개념

 : 데이터의 형태와 길이에 대한 불명확한 정의 때문에 발생하는 문제점 중 '데이터 형태에 대한 불명확한 정의'로 인한 것. 즉 명확하게 정의되었던 데이터 형태를 불명확하게 바꾸는 것

% s, % d, % u, % o, % x..

ex) main(){

 char *buffer = "wishfree"; //wish free라는 문자열에 대한 주소 값을 포인터로 지정

printf("% s\n", buffer); // 여기서 %s 같은 것들 / 포인터(buffer)가 가리키는 주소에서 % s를 읽어 출력. 

}

 

+포맷 스트링 문자를 이용한 메모리 변조

main(){

 long i=0x00000064, j=1;

printf("i의 주소 : % x \n", &i);

printf("i의 값 : %x \n", &i);

 

printf("% 64d% n\n", j, &i); //j와 i의 주소 값에 64의 16진수 값을 입력

printf("변경된 i값: % x\n", i);

}

->변수에 데이터를 삽입하지 않았지만 변수 i에 0x64이라는 값을 집어넣음

결과 : 

추가로 printf("% 64d% n\n", j, &i);에서 i가 공격하려는 취약 함수의 ret 주소 값인데 %64d 부분에 공격 셸(egg shell)의

주소 값으로 계산해서 넣으면 버퍼 오버 플로와 유사하지만 다른 방식으로 공격 셸을 실행할 수 있다

 

04. 메모리 해킹

 -버퍼 오버플로나 포맷 스트링은 취약점을 이용하지만 시스템 자체를 공격함

: 프로그램의 동작에 관여하지 않고 프로그램이 실행되는 데 필요한 정보를 저장해둔 메모리를 조작하는 것.

ex) 백도어 같은 프로그램을 설치하여 메모리에 있는 패스워드를 빼내거나 데이터를 조작하여 돈을 받는 계좌와 금액을 변경함.

 

ex) 지뢰 찾기 MHS(memory hacking s/w) 사용

MHS프로그램을 이용하여 내가 해킹하고자 하는 메모리의 주소를 찾기 위해 시간 값을 찾는다

주소 값을 찾고 값을 바꾸면 실행되고 있는 프로그램을 조작할 수 있다

 

연습문제

1. 다음 중 스택의 기능으로 적절하지 않은 것은? 4(HEAP)

https://dsnight.tistory.com/50 참조 

 

2. 스택은 메모리의 상위 주소에서 하위 주소 방향으로 사용되며, (        ) 원칙에 따라 나중에 저장된 값을 먼저 사용한다. -후입 선출

 

3. 스택의 가장 끝 주소를 가리키는 R는? 2

 

4. 반복적으로 실행되는 특정 명령에 사용(루프의 반복 횟수나 좌우 방향 시프트 비트 수 기억 등) 하는 R는 무엇인가? 3

 

5. SFP(saved frame pointer)에 대해 간단히 설명하시오.

=이전 함수의 EBP 주소를 가지고 저장하고 있는 공간이다

=SFP(stack frame pointer),  FPO(Frame Pointer Overflow), 1Byte Overflow로 불리며 단 1바이트로 IP의 흐름을 제어할 수 있는 공격 기법이다. SFP의 마지막 한 바이트를 쉘 코드의 주소가 저장되어 있는 스택의 주소로 변조한다면 함수 에필로그에 인해 흐름을 제어할 수 있게 된다.

https://d4m0n.tistory.com/76 참조

 

6. esp 값을 ebp로 저장한다는 의미의 어셈블리어는 무엇인가? 1

 

7. 다음 중 일반적으로 사용하는 셸이 아닌 것은? 4

 

8. 다음 중 SetUIP 권한이 부여된 경우는 무엇인가? 2

9. 버퍼 오버플로 공격에 대해 간단히 설명하시오. 

 - 형태와 길이에 대한 불명확한 정의로 인한 문제로 덮어쓸 수 없는 부분에 임의의 코드를 덮어쓰는 것

 

10. 다음 중 문자열을 나타내는 포맷 스트링은 무엇인가? 3

11. 다음 소스코드를 컴파일해 'test AAAAAAAA'로 실행하면 변경된 i 값이 얼마로 출력되는가?

#include <stdio.h>

int main(int argc, char *argv [])
{
int i=10;
printf("최초 i의 값 : % d\n", i);
printf("% s% n\n", argv [1], &i);
printf("변경된 i의 값 : % d\n", i);
}

12. 메모리 해킹 수행 절차를 순서대로 나열하시오. ㄹ-ㄴ-ㄷ-ㄱ