티스토리 뷰

Security

버퍼오버플로우 실습

on1ystar 2019. 1. 23. 01:41
728x90
반응형

본 글의 목적은 제가 공부한 내용을 바탕으로 정리하면서 저와 같이 공부하시는 분 들을 위함입니다. 때문에 부족한 부분이 있을 수 있고, 잘못된 부분이 있을 수 있습니다. 만약 있을 경우, 생각을 고칠 수 있도록 저에게 알려주시면 정말 감사하겠습니다 !!



<실습 환경>

가상 환경 : VMware Workstation 10

OX : Linux-Ubuntu 16.04.02-64bit

Setting : echo 0 > /proc/sys/kernel/randomize_va_space (ASLR 해제)

sudo dpkg --add-architecture i386

sudo apt-get update

sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 zlib1g:i386  

(64bit 환경에서 32bit 바이너리를 실행시키기 위함)


ASLR이란, 메모리상의 공격을 어렵게 하기 위해 스택이나 힙, 라이브러리 등의 주소를 랜덤으로 프로세스 주소 공간에 배치함으로써 실행할 때 마다 데이터의 주소가 바뀌게 하는 기법입니다


버퍼오버플로우 – shell 실행시키기


우선 bof파일을 실행시켜 보겠습니다.


어떤 [input] 값을 넣어 주어야 실행되는 파일인 것 같습니다. 그래서 그냥 아무 값이나 넣어봤습니다.


input 값을 이용해서 스택을 오버플로우 시켜 shell을 실행시키는 문제겠네요.

이 파일은 c코드가 있어서 한 번 보겠습니다.

#include <stdio.h>

#include <string.h>

 

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

{

        char buffer[100];    

        if(argc!= 2)

        {

               printf("[+]usage : ./bof [input]\n");

               return 0;

        }

        printf("[+]this is buffer overflow practice :)\n");

        printf("[+]expliot me! :P\n");

        strcpy(buffer, argv[1]);

        printf("[+]buffer address : %p\n", buffer);

        printf("[+]your input : %s\n", buffer);

        return 0;

 

}

char buffer배열이 100으로 선언되어 있고, bufferstrcpy함수를 이용해서 우리가 넣어주는 input값을 복사해주고 있네요. 그리고 이 buffer의 주소는 0xffffcf44라고 알려줍니다.

이미 고정된 메모리의 크기에(char100byte) 가변 값인 입력 값을 이용하여 메모리를 넘치게 해서 리턴 주소 값을 변조하는 것이 버퍼오버플로우의 핵심입니다.

 

strcpy취약점

이 함수는 NULL문자를 만나기 전까지의 문자열을 복사합니다. 하지만 복사하는 분자열의 길이를 검사하지 않습니다.

때문에 공격자 입장에서 원하는 길이의 입력 값을 넣어도 특별한 조치가 취해지지 않기 때문에 특히 BOF에 취약한 함수입니다.

따라서 위의 코드는 strcpy를 이용한 문자열 복사를 사용하기 때문에 취약점이 존재하는 코드입니다.


 

스택 메모리 구조


STACK은 함수 call을 할 때 이전 위치(주소)로 돌아오기 위해 RETSEP 값을 입력하고 STACK FRAME을 만듭니다. 따라서 RET에는 함수가 끝난 다음의 주소가 있고, SEP에는 베이스 포인터인 ebp레지스터를 위치시켜 놓습니다.

함수가 실행되기 전에 스택에서는 먼저 ebp 레지스터를 push합니다.

다음에 espebp랑 같이 놓고 이 esp의 주소 값을 빼 주면서 데이터를 담을 공간을 확보해 나갑니다. ( 스택 메모리 구조는 높은 주소에서 낮은 주소로 쌓아 나가기 때문에 )


Buffer 시작 주소

사실 buffer의 시작 주소는 위의 코드에서 친절하게 0xffffcf44 라고 알려주었습니다. 만약 이를 알려주지 않았다면 직접 디스어셈블을 해서 buffer를 사용한 레지스터의 주소를 알아내야 합니다.

 GDB를 이용해 main을 디스어셈블 해보겠습니다.


내려가다 보면 strcpy함수를 콜 하는 것을 확인할 수 있습니다.

위에 lea -0x64(%ebp), %eax를 보면,

 

 6410진수로 100, 그러니까 ebp-0x64를 하고 eax에 담아 eaxpush해 줌으로써 buffer배열에 메모리공간 100byte를 할당하는 것도 확인할 수 있습니다.


RET 위치 계산

RET의 주소를 몰라도 위의 정보들을 가지고 input값으로 ret에 원하는 주소 값을 넣을 수 있습니다.

먼저 buffer의 크기가 100바이트입니다. 그리고 ebp의 크기는 4바이트입니다. 따라서 100+4바이트를 입력하면 그 뒤에 ret레지스터가 위치합니다. ret레지스터 역시 4바이트이므로 이를 변조시켜 주면 됩니다.


103개 문자를 넣을 때 까지는 이상 없다가 104개부터 Segmentation fault가 뜹니다.

그럼 이제 입력 값을 만들어 보겠습니다.

 

사용할 쉘 코드 : \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80 (25바이트)

처음 buffer 값에 25바이트 쉘 코드를 넣어주고, 나머지를 의미 없는 문자로 79개 넣어주겠습니다.

이제 RET에 들어갈 buffer주소를 넣어야 하는데, 이 때 주의해야할 점이 바이트를 저장하는 방식이 리틀 엔디안이므로 buffer의 주소를 바이트 단위로 끊어서 반대로 넣어주어야 합니다.


실행



안됩니다... 그리고 왠지 모르겠지만 buffer address주소도 갑자기 바뀌었습니다.

Buffer 주소를 확인해보기 위해 다시 gdb로 돌아갔습니다.


strcpy가 끝나는 곳에 브레이크 포인트를 건 후, aA10개씩 번갈아 가며 총 100개의 문자를 입력해 보고 esp의 위치와 값들을 출력해 봤습니다.

0xffffceb4가 시작이므로 esp주소이고, ebp의 주소가 0xffffcf18인걸 보니까 0xffffcf14에서 A(41)가 끝나는 다음 값0x00000000ebp의 값인 것도 확인했습니다. 그렇다면 다음 4바이트의 위치가 ret의 주소가 됩니다.

그렇다면 100+4(ebp)+4(ret)는 맞기 때문에 쉘 코드의 문제이거나 변조 값을 buffer의 주소 값이 아닌 esp의 주소 값으로 변조하는 건가 생각했습니다.


esp의 주소로 넣어주니까 쉘 코드가 실행이 됩니다 !

자세히 보니까 바뀐 buffer address 주소도 esp주소네요.


참고 : http://blog.naver.com/PostView.nhn?blogId=sysganda&logNo=30165051688

https://dool2ly.tistory.com/83

https://bpsecblog.wordpress.com/2016/05/16/memory_protect_linux_1/

https://baeknamu.com/110

https://redscreen.tistory.com/27

728x90
반응형

'Security' 카테고리의 다른 글

plt got  (1) 2019.02.03
리버싱 실습(Easy_ELF)  (0) 2019.01.24
취약점(vulnerability)  (0) 2019.01.20
쉘 코드(/bin/sh  (0) 2019.01.16
SQL 인젝션  (0) 2019.01.14
댓글