brunch

매거진 Rnfwoa

You can make anything
by writing

C.S.Lewis

by kcats Jun 14. 2016

BOF 배낭여행(1)

어셈블리어로 hello world! 그리고 쉘코드

 1. 들어가면서

    안녕하세요 Rnfwoa의 kcats입니다. 시스템 공부를 할 때 가장 먼저 언급되는 것이 BOF(Buffer OverFlow)죠. 그래서 간단하고 쉽게 BOF에 대해 설명하려고 합니다. 이름하여 BOF 배낭여행!! ( 원래 진지하게 쓰려고 했는데 글이 안써져서 약을 빨았습니다)

    초기의 BOF공격은 메모리에 쉘코드를 올린 후 실행하는 방식이었습니다. 최신 방어기법이 적용된 운영체제와 바이너리에서는 이 방법을 사용할 수 없죠. 하지만 초기의 BOF가 어떤 것이고, 어떻게 진화되어 왔는 지 아는 것이 중요하다고 생각해요. 그래야 그 당시 사람들의 고민과 현재의 고민을 연결지어 생각해 볼 수 있죠.

    이 문서는 hello world!를 출력하는 어셈블리어에 대한 이야기합니다. 이를 응용하면 쉘코드를 만들 수 있습니다. 쉘코드는 BOF로 프로그램의 흐름(리턴 어드레스, 함수포인터)을(를) 변경한 후 쉘을 획득할 때 사용하며, exploit-db나 shell-storm에서 쉘코드를 구할 수 있습니다. 하지만 가져다 쓰기만 하고 원리는 이해하지 못하면 응용을 할 수 없죠.

    프로그래밍 언어를 배울 때, 일반적으로 hello world를 출력하는 프로그램을 만들어 보고 입문하죠. 하지만 어셈블리어를 공부할 때는 그렇지 않죠(제가 그랬습니다). 어셈블리어의 문법을 공부하고, 리버싱을 하는 방식으로 공부하는 것도 좋지만, 만들어 보면서 구조를 이해하는 것이 더 좋았을 것 같다는 생각이 들더군요. 그래서 간단하게 어셈블리어를 이용해서 hello world를 찍어 본 후 쉘코드를 만들어보도록 하겠습니다.


2. hello world!\n


    컴퓨터는 010101로 이루어진 기계어를 쉽게 해석할 수 있지만 사람은 그렇지 않죠. 물론, 폰 노이만 형님처럼 ㅚ물은 어셈블리어도 필요없겠지만요. 우리는 ㅚ물이 아니니 어셈블리어로 프로그램을 만들어야 합니다.

    


기계어만 알면 되잖아? (Feat. 폰 노이만) 



    어셈블리어를 이용해서 hello world!를 찍어봅시다. 그러기 위해서 시스템 콜(system call)을 먼저 이해해야 합니다. 시스템 콜의 정의는 아래와 같습니다. 화면에 hello world를 출력하려면 운영체제의 시스템 콜을 이용해야 합니다. C언어에서 printf함수를 사용하는 것처럼요.


    시스템 호출(system call)은 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다. 보통 C나 C++과 같은 고급 언어로 작성된 프로그램들은 직접 시스템 호출을 사용할 수 없기 때문에 고급 API를 통해 시스템 호출에 접근하게 하는 방법이다.


    시스템 콜의 호출규약(calling convention)을 확인 해보도록 합시다. 시스템 콜의 어셈블리어는 int 0x80이고, eax 레지스터로 시스템 콜의 번호를 지정합니다. 시스템 콜의 인자는 호출할 시스템 콜이 필요한 인자에 맞춰서 ebx, ecx, edx, esi, edi에 넣어줍니다. 

http://syscalls.kernelgrok.com에서 참고한 system call table


sys_write를 호출하여 hello world를 찍고 sys_exit를 호출하여 정상종료하는 코드를 작성하겠습니다. 백문여불여일견. 코드를 보여드리도록 하겠습니다. 


hello world.s
.intel_syntax noprefix

어셈블리어는 INTEL형식과 AT&T형식이 있는데, INTEL 형식을 prefix없이 사용하겠다고 설정합니다. AT&T형식과 INTEL 형식은 operand의 src와 dst의 방향이 다릅니다. 예를 들어 eax에 1을 저장하라는 명령어가 intel 형식에서 mov eax, 1이라면, AT&T형식에서는 mov 1, $eax입니다.  


.globl main

main라는 곳에서 코드가 시작한다는 알린다고 보면 됩니다. main은 3번째 줄에서 시작합니다.


5~8번째 줄까지는 주석으로 hello world!\n 의 헥사값을 4바이트 단위로 구분하여 나타냈습니다. 12~15번째 줄에 있는 push의 operand값과 비교해보시면 리틀엔디안으로 인해 방향이 변경된 것을 알 수 있습니다. 아래 그림을 참고하면 hello world의 헥스값을 알 수 있습니다.


    

xor eax, eax

    자신을 xor하면 0이 됩니다. 그러므로 eax에 어떤 값이 있더라도 xor eax,eax 를 하면 0이 됩니다. 

mov eax, 0보다 xor eax, eax이 명령어의 길이가 짧아서 쉘코드에도 자주 사용됩니다.


cdq 

부호확장 명령어입니다. eax에 있는 부호를 edx로 확장하는데, eax에 0이 들어가 있었으므로 edx의 값도 0이 됩니다. 


mov dl, 0xd

    mov dl, 0xd는 mov edx, 0xd보다 명령어의 길이가 작습니다. edx를 0으로 초기화했으므로 edx중 dl에 0xd에 값을 넣으면 됩니다. 0xd는 십진수로 13을 의미합니다. hello world!\n의 길이는 13입니다.


push 0xa
push 0x21646c72
push 0x6f77206f
push 0x6c6c6568

    스택에 hello world!\n을 push합니다. 4개의 push 명령이 실행 된 후 스택은 아래 그림과 같습니다. 0xa부터 0x6c6c6568까지 스택에 들어가면 esp는 가장 낮은 주소를 가리키게 됩니다. hello world\n!의 시작주소죠!


mov ecx, esp
mov ebx, 1
mov al, 4

    mov ecx, esp로 esp(hello world!\n의 주소)를 ecx에 저장합니다. 이는 sys_write의 인자 const char __user *buf를 의미하며, 출력할 문자를 의미합니다. mov ebx, 1은 unsigned int fd에 표준출력(stdout)의 파일디스크립터 1을 저장하는 명령입니다. mov al,4는 위에서 언급한 것과 같이 시스템 콜 sys_write의 번호입니다. 


int 0x80
mov eax, 1
int 0x80

    sys_write를 호출 한후 sys_exit를 호출합니다. 인자는 error code가 있지만 따로 eb에 지정해주지 않아도 됩니다.


   자 이제 소스코드를 컴파일 해봅시다. 테스트 환경이 ubuntu 14.04 x64이므로 x86(32비트) 어셈블리어로 hello world를 찍기 위해서 gcc를 아래와 같이 업데이트 해줍니다. 우분투 외의 경우는 링크를 참고하세요


$ sudo apt-get install g++-multilib libc6-dev-i386

http://www.cyberciti.biz/tips/compile-32bit-application-using-gcc-64-bit-linux.html


업데이트를 마치고 난 뒤에 컴파일할 때 옵션으로 -m32를 주고 컴파일하면 됩니다.

컴파일 후 hello world! 출력

3. 마치면서

    어셈블리어로 hello world를 출력해봤습니다. 직접 구현하면서 시스템 콜과 어셈블리어에 대한 이해가 되셨길 바랍니다. 다음 문서에서 쉘을 호출하는 코드를 어셈블리어로 작성하고 bof에 대해서도 알아보도록 하겠습니다.

4. 참고자료

http://forum.falinux.com/zbxe/index.php?document_srl=550700&mid=lecture_tiphttp://wmihttp://www.felixcloutier.com/x86/CWD:CDQ:CQO.html


http://www.joinc.co.kr/w/Site/Assembly/Documents/ProgrammingGroundUp/makefirstprog.html

http://syscalls.kernelgrok.com

http://www.cyberciti.biz/tips/compile-32bit-application-using-gcc-64-bit-linux.html

http://forum.falinux.com/zbxe/index.php?document_srl=550700&mid=lecture_tip


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari