[시스템해킹]버퍼오버플로우 실습
오버플로우에 대한 기본개념은 http://hackersstudy.tistory.com/27 을 보면 알 수 있다. 좀더 보충 해서 설명하자면 Buffer Overflow 공격에 취약한 함수는 strcpy, strcat, gets, fscanf, scanf, sprintf, sscanf, vfscanf, vsprintf, vscanf, streadd, strecpy, strtrns 이러한 함수 들이 있는데 이러한 함수들의 특징은 문자열의 최대크기를 정하지 않는다는 점이다.
STACK에는 지역변수, 인자, 함수종료후 돌아갈 곳의 주소(ret값)이 저장 되어 있다. 이 RET값을 다른 주소값으로 변환하여 관리자 권한을 획득하거나 악성코드의 주소등으로 바꾸는 등등 이런 것들이 STACK 기반의 버퍼오버플로우 공격이다.
HEAP에는 malloc, calloc 등의 함수를 이용하여 프로그래머가 직접 공간을 할당하게 되는데, 이곳에 저장된 데이터 및 함수를 변경하여 원하는 결과를 얻어낼 수 있다. 이것이 HEAP 기반의 버퍼오버플로우 공격이다.
<그림 1 컴퓨터 메모리 구조>
실습문제
버퍼오버플로우를 시켜 함수 종료후 돌아가는 값인 ret의 주소를 쉘 프로그램의 주소로 덮어씌워서 쉘 프로그램을 실행시켜보자.
[코드1 stack.c]
실습을 하기에 앞서 ASLR(Address Space Layout Randomization)을 해제해야한다. ASLR은 리눅스 자체에서 오버플로우 공격을 막기 위해 프로그램 실행 시 메모리 주소를 랜덤 하게 바꾸어 주는 기술인데 해제하지 않으면 실습이 안되기 때문에 해제를 하고 시작해야 한다
gcc -fno-stack-protector -mpreferred-stack-boundary=2 -z execstack -o filename filename.c
-fno-stack-protector : 스택 보호 기법 해제
-mpreferred-stack-boundary=2 : 스택 더미 없애기
-z execstack : 스택 메모리에 실행권한 부여
여기까지했다면
$ gdb filename
으로 gdb를 실행시켜보자. gdb 란 디버깅 작업 또는 프로그램의 안정성을 검사할 때 쓰는 것인데, 나는 해당 함수안의 어셈블리코드를 보기위해서 사용하였다. 만약 오류가 난다면 gdb를 사용하여 오류지점을 찾을 수 있다.
gdb 실행시킨뒤
(gdb) disas main
을 입력해주면 어셈블리코드가 출력된다.만약 No symbol table is loaded. Use the "file" command. 라는 실패 문구가 출력 된다면, debug option으로 compilegcc filename.c -o filename -ggdb
와 같이 재컴파일을 해주도록 하자.
<그림2 stack.c main함수 부분 어셈블리 코드>
스택기반 버퍼오버플로우는 argv로 들어오는 인자값을 buffer의 크기보다 크게 주어서 ret값의 주소가 있는 영역까지 넘치게 하여서 ret값을 악성코드로의 주소로 덮어버리는 것이다. 여기 실습에서는 널리 배포되어 있는 eggshell 소스로 쉘 프로그램을 실행하게 할것이다. stack프로그램 리턴주소대신에 eggshell 프로그램안에 있는 쉘코드를 집어넣어 동작하게 할것이다.
[코드2 eggshell.c]
<그림3 eggshell 주소>
소스를 gcc로 컴파일해서 실행하여면 eggshell 프로그램의 쉘코드가 위치한 주소를 알 수 있다. 이제 이 주소를 ret값 위에 덮어 씌우기만 하면 된다.주소값을 입력할때 리틀-엔디안(Little-Endian)방식을 사용합니다. 예를 들어 위에 eggshell 주소가 0xbffff6a8이라면
\xa8\xf6\xff\bf
라고 입력해주면 된다.
<그림4 버퍼오버플로우 발생>
위에 그림을 보면 a가 11개까지는 오류가 발생하지 않는데, 12개부터 오류가 발생하는걸 볼 수 있다. 위에서 stack.c 코드를 보면 버퍼를 8로 설정해놧는데 왜 8개를 넘는 11개를 입력 하였는데 오류가 나지 않는걸까? 먼저 ./stack + a*11 이기때문에 위에 입력한 건 12바이트라고 할수 있다. 13바이트부터 오류가 발생하는 이유는 ebp(Extended Base Pointer)때문이다. 버퍼의 8byte + ebp의 4byte 이기때문에 12바이트이고 그 뒤부터 ret값이 오게된다.
perel언어를 사용하기위해서 LANGUAGE를 설정해줘야 한다
export LANG = "ko_KR.euckr"
echo $LANG 으로 자신의 LANGUAGE를 확인 할수 있다
<그림5 쉘 프로그램 실행 성공>
마지막으로
$./filename `perl -e 'print "A"x12, "자신이 실행하고자하는 프로그램의 주소(little edian으로 입력)"'`
를 입력하면 쉘 코드가 실행되는 걸 알 수 있다.
출처 http://blog.naver.com/skddms/110180973377
'네트워크및보안&해킹 > 보안&해킹' 카테고리의 다른 글
CrackMe2 문제풀이 (6) | 2015.07.17 |
---|---|
DLL Injection (6) | 2015.06.21 |
CrackMe 문제풀이 (리버싱 기초) (6) | 2015.06.08 |
리버스 엔지니어링 (3) | 2015.06.08 |
버퍼오버플로우 (928) | 2015.06.08 |