본문 바로가기

Security/System Hacking

No.2 Buffer OverFlow Attack

(1) Buffer OverFlow Attack

 

버퍼 오버플로우에 대해 알아 보겠습니다.

 

=> 프로그래머가 버퍼 오버플로우에 취약한 함수를 쓰면 매우 간단히 취약점이 발견됩니다.

예를 들어봅시다.

 

abc.c

=> abc라는 이름으로 c로 코딩된 파일입니다.

 

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

char buffer[10];                                          ----------------> 2번

strcpy (buffer, argv[1]);                        ---------------> 3번

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

}

 

 

1번 : argc는 실행되는 프로그램의 인수 갯수입니다.

        *argv[]는 포인터 배열로서 인자로 입력되는 값에 번지수를 차례로 저장시킵니다.

       argv[0] => 실행 파일의 이름

       argv[1] => 첫번째 인자의 값

       argv[2] => 두번째 인자의 값

 

2번 : 10byte의 값을 버퍼에 할당 합니다.

3번 : 버퍼에 첫번째 인자를 저장합니다.

4번 : 버퍼에 저장된 내용을 출력합니다.

 

자 이때 실제 공격은 strcpy (buffer, argv[1]);   이 부분에서 일어 납니다.

 

gcc -o abc abc.c

gdb abc = > 어셈으로 된 함수를 펼쳐보입니다.

disass main

 

이렇게 해놓고 보시면

strcpy는 인수의 경계를 체크하지 않는 함수입니다.

즉, buffer[10] => 즉, 12바이트를 저장합니다 왜냐하면 일반적으로 메모리에는 4byte값이 할당 되기 떄문입니다.

 

이때 버퍼에 값이 인수를 16개를 주면 어떻게될까요? 나머지 인수4개는 사라질까요?

아닙니다.

주소 공간인 buffer에 12개 그리고 ebp에 4개가 저장됩니다.

즉, ret주소에 저장된 메모리 주소가 인수4개로 덮어씌워지는 것입니다.

 

이때 위에서 앞서배웠던 SetUID에서 bash 쉘을 올릴수 있었던 test파일을 다시 관리자 권한으로 SetUID를 줍시다.

 

자 그리고나서 ./test AAAAAAAAAAAAA이런식으로 A라는 인수를

16개를 입력합니다.

 

그럼 세그먼트 오류가 발생되지만 인수값이 저장이 안되는 것이 아니라 위에 설명했듯이 저장이 됩니다.

그리고나서 공격에 사용되는 egg shell을 사용합니다.

 

egg shell? => 기계어로 만든 코드를 메모리에 로드시켜주고, 그 시작 주소가 어디인지를 알려주는 툴입니다.

 

#./egg

 

합니다 그럼 메모리 값이 나오고 예를 들어 0xAAAAAAAA 이 떴다 하면 이 메모리에 쉘이 적재 된 것입니다.

이제 다시 일반 사용자로가서 perl을 이용합니다.

perl을 이용해 A문자열과 셸의 메모리 주소를 abc에 직접적으로 실행 시킵니다.

이때 공격시에는 셸의 주소를 1byte씩 거꾸로 입력하는데 이는 스택이기떄문입니다 즉,  LIFO의 성질 떄문인데요 나중에 들어온것이 먼저 나간다 이것의 성질 때문입니다.

 

#perl -e 'system' "./abc" , "AAAAAAAAAAAAAAAA \x48 \xfb \xff \xbf"'id

 

이렇게 해봅시다

명령어의 뜻은 abc를 실행시의 메모리의 값을 하나씩 꺼내 id의 값을 얻어 오는 것입니다.

저렇게 되면 일단 bash 셸을 수행하는 abc때문에

프롬포트가

bash#으로 바뀌 어 있고

bash# id

 

해보시면 uid가 root로 변한 것을 알수 있습니다.

 

(2) 버퍼 오버 플로우에 취약한 함수 

 

 종류

내용 

 strcpy

(char *dest, const char *src) 

 strcat

(char *dest, const char *src) 

 getwd

(char *buf) 

 fscanf

(FILE *stream, const char *format) 

 scanf

(const char *format) 

 realpath

(char *path, char resloved_path[]) 

 sprintf

(char *str, const char *fromat) 

 gets

(char *s)