System hacking training/Hackerschool LOB

LEVEL 17 succubus write-up

fkillrra 2018. 5. 17. 20:42

zombie_assassin -> succubus


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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
[zombie_assassin@localhost zombie_assassin]$ cat succubus.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
 
// the inspector
int check = 0;
 
void MO(char *cmd)
{
        if(check != 4)
                exit(0);
 
        printf("welcome to the MO!\n");
 
    // olleh!
    system(cmd);
}
 
void YUT(void)
{
        if(check != 3)
                exit(0);
 
        printf("welcome to the YUT!\n");
        check = 4;
}
 
void GUL(void)
{
        if(check != 2)
                exit(0);
 
        printf("welcome to the GUL!\n");
        check = 3;
}
 
void GYE(void)
{
    if(check != 1)
        exit(0);
 
    printf("welcome to the GYE!\n");
    check = 2;
}
 
void DO(void)
{
    printf("welcome to the DO!\n");
    check = 1;
}
 
main(int argc, char *argv[])
{
    char buffer[40];
    char *addr;
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    // you cannot use library
    if(strchr(argv[1], '\x40')){
        printf("You cannot use library\n");
        exit(0);
    }
 
    // check address
    addr = (char *)&DO;
        if(memcmp(argv[1]+44&addr, 4!= 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }
 
        // overflow!
        strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
 
        // stack destroyer
    // 100 : extra space for copied argv[1]
        memset(buffer, 044);
    memset(buffer+48+10000xbfffffff - (int)(buffer+48+100));
 
    // LD_* eraser
    // 40 : extra space for memset function
    memset(buffer-300003000-40);
}
cs

문제를 보니 상당히 긴 코드가 나온다.

RTL Chaining에 대해 공부를 했기 때문에 문제 출제 의도를 쉽게 파악할 수 있었다.

RTL Chaining 이란?

이 기법을 간단히 설명하자면

RTL이라는 기법을 응용하여 함수의 호출을 연계하는 것이다.

이 문제를 풀이할때 이 기법을 사용할 수 밖에 없는데 그 이유는 문제를 분석하면서 알 수 있었다.

  • main() 에서 모든 argv[1]의 값에서 '\x40'을 검사하여 예외처리 시킨다.
  • addr에 &DO의 주소를 넣고 argv[1][44] 부터 4byte 즉, ret의 값이 &DO인지 확인하고 아닐시 예외처리 한다.
  • 이후 strcpy()의 사용으로 인해 bof가 터진다.
  • memset()로 buffer와 argv[1]의 모든 주소값을 0으로 세팅한다.
  • LD_PRELOAD 로 인한 후킹도 memset()를 이용하여 방지한다.

이제 함수를 연계적으로 호출하기 위해 각 함수의 주소를 gdb로 구해줬다.

각 함수의 주소를 구했으니 세그폴트가 뜨는지 확인해보았다.

예외처리에 걸리지 않고 잘 실행이 된다.

이제 마지막으로 호출한 DO의 인자값으로 /bin/sh을 넘겨주면 되는데

인자값이 넘어가는 부분에 BBBB를 넣고 주소를 확인한 뒤

core 파일을 확인하였다.

/bin/sh이 들어간 주소를 인자로 넘겨야하기 때문에 페이로드 구성을 아래와 같이 하였다.

`python -c 'print "dummy(44byte)" + "&DO" + "&GYE" + "&GUL" + "&YUT" + "&MO" + "/bin/sh이 들어간 주소" + "/bin/sh"'`

따라서 /bin/sh이 들어간 주소는 0x42424242가 들어간 주소 + 4의 주소이고

바로 다음 /bin/sh을 넣어주면 된다.

core 파일에서 /bin/sh이 들어간 위치는 0xbffffa68 이다.

따라서 익스를 하면..!

쉘을 띄울 수 있다.

 

반응형