-
Notifications
You must be signed in to change notification settings - Fork 0
/
cfi_call.cpp
204 lines (195 loc) · 7.11 KB
/
cfi_call.cpp
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef int (*int_arg_fn)(int);
typedef int (*uint_arg_fn)(unsigned int);
typedef int (*void_p_arg_fn)(void *);
typedef void *(*void_p_ret_fn)(int);
typedef int (*float_arg_fn)(float);
// int, int
int int_arg_1(int arg) {
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int int_arg_2(int arg) {
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int int_arg_3(int arg) {
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int int_arg_4(int arg) {
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
// int, uint
int bad_uint_arg_1(unsigned int arg) {
printf("Evil1: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_uint_arg_2(unsigned int arg) {
printf("Evil1: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_uint_arg_3(unsigned int arg) {
printf("Evil1: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_uint_arg_4(unsigned int arg) {
printf("Evil1: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
// int, void*
int bad_void_p_arg_1(void * arg) {
printf("Evil2: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_void_p_arg_2(void * arg) {
printf("Evil2: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_void_p_arg_3(void * arg) {
printf("Evil2: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
int bad_void_p_arg_4(void * arg) {
printf("Evil2: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
// void*, int
void * bad_void_p_ret_1(int arg){
printf("Evil3: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
void * bad_void_p_ret_2(int arg){
printf("Evil3: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
void * bad_void_p_ret_3(int arg){
printf("Evil3: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
void * bad_void_p_ret_4(int arg){
printf("Evil3: CFI will not protect transfer to here\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
return 0;
}
// static
int float_arg(float arg) {
printf("CFI should protect transfer to here\n");
printf("Original args : %f\n", arg);
printf("In %s: (%f)\n", __FUNCTION__, (double)arg);
return 0;
}
// static
int not_entry_point(int arg) {
// nop sled for x86 / x86-64
// these instructions act as a buffer
// for an indirect control flow transfer to skip
// a valid function entry point, but continue
// to execute normal code
__asm__ volatile (
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
"nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
);
printf("CFI ensures control flow only transfers to potentially valid destinations\n");
printf("In %s: (%d)\n", __FUNCTION__, arg);
// need to exit or the program will segfault anyway,
// since the indirect call skipped the function preamble
exit(arg);
}
void print_err(){
printf("Signature Mismatch!\n");
exit(-1);
}
void print_one(int poped){
printf("%d\n", poped);
}
void print_two(int poped1, int poped2){
printf("%d, %d\n", poped1, poped2);
}
struct foo {
// Exploit Type Weakness
// 여기에 assign 되는 순서대로 table elem에 들어간다.
int_arg_fn int_funcs[4];
uint_arg_fn uint_funcs[4];
void_p_arg_fn void_p_arg_funcs[4];
void_p_ret_fn void_p_ret_funcs[4];
float_arg_fn float_funcs[1];
int_arg_fn not_entries[1];
};
// the struct aligns the function pointer arrays
// so indexing past the end will reliably
// call working function pointers
static struct foo f = {
// Exploit Type Weakness
.int_funcs = {int_arg_1, int_arg_2, int_arg_3, int_arg_4},
.uint_funcs = {bad_uint_arg_1, bad_uint_arg_2, bad_uint_arg_3, bad_uint_arg_4 },
.void_p_arg_funcs = {bad_void_p_arg_1, bad_void_p_arg_2, bad_void_p_arg_3, bad_void_p_arg_4},
.void_p_ret_funcs = {bad_void_p_ret_1, bad_void_p_ret_2, bad_void_p_ret_3, bad_void_p_ret_4},
.float_funcs = {float_arg},
.not_entries = {(int_arg_fn)((uintptr_t)(not_entry_point)+0x20)}
};
int call_int_funcs(int_arg_fn fp, int idx){
fp(idx);
}
int call_uint_funcs(uint_arg_fn fp, int idx){
fp(idx);
}
int call_void_p_arg_funcs(void_p_arg_fn fp, int idx){
fp(idx);
}
int call_void_p_ret_funcs(void_p_ret_fn fp, int idx){
fp(idx);
}
int main(int argc, const char *argv[]) {
// if(argc != 2) {
// printf("Usage: %s <option>\n", argv[0]);
// printf("Option values:\n");
// printf("\t0\tCall correct function\n");
// printf("\t1\tCall the wrong function but with the same signature\n");
// printf("\t2\tCall a float function with an int function signature\n");
// printf("\t3\tCall into the middle of a function\n");
// printf("\n");
// printf("\tAll other options are undefined, but should be caught by CFI :)\n");
// printf("\n\n");
// printf("Here are some pointers so clang doesn't optimize away members of `struct foo f`:\n");
// printf("\tint_funcs: %p\n", (void*)f.int_funcs);
// printf("\tu_int_funcs: %p\n", (void*)f.uint_funcs);
// printf("\tvoid_p_arg_funcs: %p\n", (void*)f.void_p_arg_funcs);
// printf("\tvoid_p_ret_funcs: %p\n", (void*)f.void_p_ret_funcs);
// printf("\tfloat_funcs: %p\n", (void*)f.float_funcs);
// printf("\tnot_entries: %p\n", (void*)f.not_entries);
// return 1;
// }
printf("Calling a function:\n");
int idx = argv[1][0] - '0';
printf("idx : %d\n", idx);
call_int_funcs(f.int_funcs[idx], idx);
call_uint_funcs(f.uint_funcs[idx], idx);
call_void_p_arg_funcs(f.void_p_arg_funcs[idx], idx);
call_void_p_ret_funcs(f.void_p_ret_funcs[idx], idx);
// f.int_funcs[idx](idx);
// f.uint_funcs[idx](idx);
// f.void_p_arg_funcs[idx](idx);
// f.void_p_ret_funcs[idx](idx);
return 0;
}