ipwn

[LOB(Lord Of Buffer overflow)] zombie_assassin -> succubus 본문

Write up/LOB

[LOB(Lord Of Buffer overflow)] zombie_assassin -> succubus

ipwn 2018. 1. 21. 12:39

이번 단계는 zombie_assassin이다.


바로 복사본을 만들고 파일들을 살펴보겠다



기본적으로 succubus 파일과 succubus.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
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
/*
        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);
}
 



이번 단계는 코드가 너무 길어 사진 대신 colorscripter을 사용했다.


일단 return address가 사용자 지정함수인 DO와 같아야 한다.


그리고 argv[1]에 \x40 즉 라이브러리 영역이 있으면 바로 종료시켜버린다.


즉 우리가 코드를 작성해서 나온 &"/bin/sh"도 사용 못하고 system함수도 더더욱 그렇다는 말이다.


그리고 스택 영역을 모두 0으로 memset해버리는데, ret과 그 뒤 100byte는 사용을 가능하게 해놨다.


이 문제는 어떻게 해결해야 할까?


바로 사용자 지정함수인 DO, GYE, GUL, YUT, MO를 순차적으로 호출해서 조건을 맞추고, 마지막으로는 


MO함수 인자로 &"/bin/sh"를 넘겨주어서 shell을 가져와야 한다.


하지만 우리는 코드를 작성해서 &"/bin/sh"를 가져올 수 없기 때문에 어딘가에 있을 &"/bin/sh"을 가져와야 하는데,


우리가 "/bin/sh"를 적재할 수 있는 공간이 있다.


ret 뒤로 100byte는 memset을 하지 않기 때문에 공간이 충분하다는 말이다.


일단 바로 DO, GYE, GUL, YUT, MO의 주소를 gdb로 가져와보겠다.



DO, GYE, GUL, YUT, MO의 주소를 찾아왔다.


함수 호출 한 뒤 4byte는 다음으로 넘어갈 return address라는 것을 기억할 것이다.


그리고 그 ret 뒤 4byte 부터는 호출한 함수에 넘겨질 인자값이다.


즉 우리가 넘겨줄 payload는 


dummy*44 + &DO + &GYE + &GUL + &YUT + &MO + dummy*4 + &"/bin/sh" + "/bin/sh"


이 될 것인데, ret부터 100byte동안은 memset이 되지 않으므로 "/bin/sh"의 주소를 간단히 가져올 수 있을 것이다.


우리는 복사본에 


dummy*44 + &DO + &GYE + &GUL + &YUT + &MO + dummy*4 + dummy*4(&"/bin/sh") + "/bin/sh"


를 넘겨주어서 &"/bin/sh"의 주소를 찾아낼 것이다.


먼저 이 값을 복사본에 넘겨주어서 core dump를 가져와보자.



성공적으로 core dump가 가져와졌다.


core dump를 읽어서 &"/bin/sh"를 찾아보겠다.



"BBBB"의 값 뒤의 "/bin/sh"를 찾아냈다.


이제 우리가 넘겨줄 payload가 완성됐다.


dummy*44 + &DO + &GYE + &GUL + &YUT + &MO + dummy*4 + 0xbffffa98(&"/bin/sh") + "/bin/sh"


가 우리가 넘겨줄 payload가 될 것이다.


한 번 복사본에 payload를 넘겨주고 shell이 가져와지는지 확인해보겠다.



성공적으로 shell이 가져와졌다.


이제 원본에 payload를 넣어주고 권한이 상승된 shell을 가져오겠다.



성공적으로 권한이 상승한 shell을 가져왔다.


succubus로 넘어가는 password는 here to stay이다.

Comments