Systemd is the Dekstop replacement for /sbin/init, aiming
to faster boot Linux desktop systems and to better integrate
user session tracking etc.. Part of systemd is systemd-logind
which exactly does that by creating files (ore more
precisely hardlinks and symlinks) inside the /run/user
directory upon X11 desktop logins. Such work was commonly
done by desktop managers like gdm (CVE-2011-0727) or kdm
(CVE-2010-0436). Both failed to securely handle files
inside user owned directories, and so does systemd-logind.
The header shows you where the problem is. We actually need
to race two unlink() calls to end in a symlink() call
that is of use. A link() would just create a hardlink to
the $DISPLAY UNIX-socket which is useless, except you have another
file-remove exploit which you can use to replace
/tmp/.X11-unix/X0 before the link() is called.(This would also
remove the requirement for having console access to exploit
this bug and the need for a race.)
So far. By messing with files and directories inside /run/user
we can create a symlink called display inside arbitrary
system directories pointing to /tmp/.X11-unix/$DISPLAY.
/etc/pam.d is a good choice if you
have kcheckpass installed. /etc/cron.d is another, but
crond only accepts root cronjobs from files
owned and writable by root. So placing a display symlink
somewhere to /home/attacker/foo is of no use.
But wait; is not root's mailbox mode 0600, owned by root
and writable by users by sending him an email?
Yes it is. So lets just do that. crond will ignore leading
and trailing garbage until it finds attackers
cronjob. The symlink from /tmp/.X11-unix/$DISPLAY to
/var/mail/root is made during the restart of the X11
display. Thats why a Ctrl+Alt+Backspace is necessary.
As mentioned, this is not needed if you combine another
file unlink vulnerability.
I wrote the PoC for a core i5, x86_64 and run it successfully
on a FC16 and a openSUSE 12.1. Since we need to race two
times, there is no easy pattern to just brute-fork it,
as we would race to ourself then. Maybe the use of inotify
is an option to make the PoC more reliable (for me it takes
3 or 4 tries to succeed, so thats enough stability for a PoC).