Bug 1036244 (CVE-2017-8422) - VUL-0: CVE-2017-8422: KDE KAuth bypass
Summary: VUL-0: CVE-2017-8422: KDE KAuth bypass
Status: IN_PROGRESS
Alias: CVE-2017-8422
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Normal
Target Milestone: ---
Assignee: E-mail List
QA Contact: Security Team bot
URL: https://smash.suse.de/issue/184419/
Whiteboard: CVSSv2:SUSE:CVE-2017-8422:6.9:(AV:L/A...
Keywords:
Depends on:
Blocks:
 
Reported: 2017-04-26 10:18 UTC by Sebastian Krahmer
Modified: 2024-05-17 11:52 UTC (History)
8 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments
First patch from upstream (6.92 KB, patch)
2017-05-02 07:30 UTC, Sebastian Krahmer
Details | Diff
Second patch from upstream (7.25 KB, patch)
2017-05-02 07:31 UTC, Sebastian Krahmer
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Krahmer 2017-04-26 10:18:55 UTC
This document describes a generic root exploit against KDE.

The exploit is achieved by abusing a logic flaw within
the KAuth framework which is present in KDE4 (org.kde.auth) and KDE5
(org.kde.kf5auth). It is possible to spoof what KAuth calls
callerID's which are indeed DBUS unique names of the sender of a DBUS message.
Exploitation requires a helper which is doing some privileged work
as root. For this document I chose smb4k because it contains
another vulnerability that makes exploitation a lot easier;
but in general any KAuth privileged helper code can be triggered
by users with arbitrary arguments.

I will describe the overall problem by walking through the smb4k code and explain
which DBUS functions are called and how a particular smb4k bug maps
into the bigger picture of the KAuth flaw.

Theres a problem with smb4k using the KAuth framework
and trusting all the arguments passed to the helper:

ActionReply Smb4KMountHelper::mount(const QVariantMap &args)
{

...

command << args["mh_command"].toString();
command << args["mh_unc"].toString();
command << args["mh_mountpoint"].toString();
command << args["mh_options"].toStringList();

...

proc.setProgram(command);
// Run the mount process.
proc.start();
...
}

This code is running as root, triggered via DBUS activation by smb4k GUI code
running as user, and the "args" supplied by the user, via:

void Smb4KMountJob::slotStartMount()
{
...
      Action::executeActions(actions, NULL, "net.sourceforge.smb4k.mounthelper");
...

after filling "actions" (theres only one) with the proper Name
(net.sourceforge.smb4k.mounthelper.mount) and HelperID
(net.sourceforge.smb4k.mounthelper) in order to trigger DBUS activation as well as
the argument dictionary which contains the "mh_command" etc. key/value pairs.
(Its calling the list-version of Action::executeAction() [note the
trailing 's'] with a one-element list. But that doesnt matter.)
The important thing here is that the arguments are created by code
running as user, potentially containing evil input, and are evaluated
by the helper program running as root.

The above call ends at DBusHelperProxy::executeAction(), still at callers side.
This function translates it into a DBUS method call thats
finally running privileged, whos interface is this:

<interface name="org.kde.kf5auth">
    <method name="performAction" >
        <arg name="action" type="s" direction="in" />
        <arg name="callerID" type="ay" direction="in" />
        <arg name="arguments" type="ay" direction="in" />
         <arg name="r" type="ay" direction="out" />
     </method>
...

Unlike the smb4k mount helper DBUS interface itself, which isnt
accessible as user, KAuth DBUS (org.kde.kf5auth) is:

<busconfig>
  <policy context="default">
    <allow send_interface="org.kde.kf5auth"/>
    <allow receive_sender="org.kde.kf5auth"/>
    <allow receive_interface="org.kde.kf5auth"/>
  </policy>
</busconfig>

The code for actually doing the call from user to root is this:

void DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
{
...
QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.kf5auth"), QLatin1String("performAction"));

QList<QVariant> args;
args << action << BackendsManager::authBackend()->callerID() << blob;
message.setArguments(args);

m_actionsInProgress.push_back(action);

QDBusPendingCall pendingCall = m_busConnection.asyncCall(message);

...

with the user supplied (created by smb4k when running as user)
arguments dictionary attached to the DBUS message, passing along the
potentially evil "mh_command" key.

There are two problems:

The KAuth frameworks "performAction" method is passed the callerID by the user
and the method is invokable by the user. This allows to mask as any caller,
bypassing any polkit checks that may happen later in the KAuth polkit backend
via PolicyKitBackend::isCallerAuthorized(const QString &action, QByteArray callerID).
The second problem is smb4k trusting the arguments that are passed from the user and which
are forwarded by the KAuth DBUS service running as root to the mount helper
DBUS service which is also running as root but not allowed to be contacted by users.
Thats a logical flaw. It was probably not expected that users invoke
"performAction" themself, using it as a proxy into DBUS services and
faking caller IDs en-passant. The callerID usually looks like ":1.123"
and is a DBUS unique name that maps to the sender of the message.
This ID should be obtained via a DBUS function while the message is arriving,
so it can actually be trusted and used as a subject for polit authorizations
when using systembus-name subjects. Allowing callers to freely specify this ID
is taking down the whole idea of authentication and authorization.

I made an exploit for smb4k that works on openSUSE Leap 42.2 thats using the org.kde.auth
interface (rather than the new org.kde.kf5auth) but both interfaces
share the same problems. In order to test the callerID spoofing,
I "protected" the smb4k helper code via "auth_admin" polkit settings and
tried mounting SMB shares via smb4k GUI. This asked for the root password,
as its expected. The exploit however still works, as its spoofing the callerID
to be DBUs itself and the request is taken as legit.
Comment 2 Sebastian Krahmer 2017-05-02 07:30:46 UTC
Created attachment 723396 [details]
First patch from upstream

First patch from upstream
Comment 3 Sebastian Krahmer 2017-05-02 07:31:34 UTC
Created attachment 723397 [details]
Second patch from upstream

.
Comment 4 Sebastian Krahmer 2017-05-02 07:32:22 UTC
I will inform the distros list to see whether discussion yields
that the patches are indeed correct.

From my first look it seems to be OK.
Comment 5 Marcus Meissner 2017-05-02 11:15:16 UTC
CRD: 2017-05-15
Comment 7 Sebastian Krahmer 2017-05-03 07:33:11 UTC
CVE-2017-8422 from KDE project
Comment 8 Sebastian Krahmer 2017-05-03 13:46:37 UTC
new CRD: 2017-05-10
Comment 11 Bernhard Wiedemann 2017-05-10 12:01:40 UTC
This is an autogenerated message for OBS integration:
This bug (1036244) was mentioned in
https://build.opensuse.org/request/show/494070 42.2 / kauth
https://build.opensuse.org/request/show/494072 42.2 / kdelibs4
Comment 12 Antonio Larrosa 2017-05-10 12:09:47 UTC
kdelibs4 submit to SUSE:SLE-12:Update
https://build.suse.de/request/show/132468

kauth submit to openSUSE:Backports:SLE-12-SP2 
https://build.opensuse.org/request/show/494215


kauth submit to Leap:42.2:Update
https://build.opensuse.org/request/show/494070

kdelibs4 submit to Leap:42.2:Update
https://build.opensuse.org/request/show/494072


kauth submit to KDE:Frameworks5:LTS
https://build.opensuse.org/request/show/494212

kdelibs4 submit to KDE:Applications 
https://build.opensuse.org/request/show/494213
Comment 13 Marcus Meissner 2017-05-10 13:02:37 UTC
Sebastians oss-sec posting:

-----8<----- snip ------



This document describes a generic root exploit against kde.

The exploit is achieved by abusing a logic flaw within
the KAuth framework which is present in kde4 (org.kde.auth) and kde5
(org.kde.kf5auth). It is possible to spoof what KAuth calls
callerID's which are indeed DBUS unique names of the sender of a DBUS
message.
Exploitation requires a helper which is doing some privileged work
as root. Kde ships quite some of them, but for this writeup I chose the
smb4k helper because it contains another vulnerability that makes
exploitation a lot easier; but in general any KAuth privileged helper code
can be triggered by users with arbitrary arguments which leads to
LPE on default kde installations.

I will describe the overall problem by walking through the smb4k code and
explain which DBUS functions are called and how a particular smb4k bug maps
into the bigger picture of the KAuth flaw.

Theres a problem with smb4k using the KAuth framework
and trusting all the arguments passed to the helper:

ActionReply Smb4KMountHelper::mount(const QVariantMap &args)
{

...

command << args["mh_command"].toString();
command << args["mh_unc"].toString();
command << args["mh_mountpoint"].toString();
command << args["mh_options"].toStringList();

...

proc.setProgram(command);
// Run the mount process.
proc.start();
...
}

This code is running as root, triggered via DBUS activation by smb4k GUI
code running as user, and the "args" supplied by the user, via:

void Smb4KMountJob::slotStartMount()
{
...

 Action::executeActions(actions, NULL, "net.sourceforge.smb4k.mounthelper");
...
}

after filling "actions" (theres only one) with the proper Name
(net.sourceforge.smb4k.mounthelper.mount) and HelperID
(net.sourceforge.smb4k.mounthelper) in order to trigger DBUS activation as
well as the argument dictionary which contains the "mh_command" etc.
key/value pairs. Its calling the list-version of Action::executeAction()
[note the trailing 's'] with a one-element list, but that doesn't matter.
The important thing here is that the arguments are created by code
running as user - potentially containing evil input - and are evaluated
by the helper program running as root.

The above call ends at DBusHelperProxy::executeAction(), still at callers
side. This function translates it into a DBUS method call which is
finally running privileged and has the following interface:

<interface name="org.kde.kf5auth">
...
    <method name="performAction" >
        <arg name="action" type="s" direction="in" />
        <arg name="callerID" type="ay" direction="in" />
        <arg name="arguments" type="ay" direction="in" />
        <arg name="r" type="ay" direction="out" />
    </method>
...
</interface>

Unlike the root helpers DBUS interfaces itself, which are not
accessible as user, the KAuth DBUS interface org.kde.kf5auth is:

<busconfig>
  <policy context="default">
    <allow send_interface="org.kde.kf5auth"/>
    <allow receive_sender="org.kde.kf5auth"/>
    <allow receive_interface="org.kde.kf5auth"/>
  </policy>
</busconfig>

The code for actually doing the call from user to root is this:

void DBusHelperProxy::executeAction(const QString &action,
     const QString &helperID, const QVariantMap &arguments)
{
...

QDBusMessage::createMethodCall(helperID, QLatin1String("/"),
   QLatin1String("org.kde.kf5auth"), QLatin1String("performAction"));

QList<QVariant> args;
args << action << BackendsManager::authBackend()->callerID() << blob;
message.setArguments(args);

m_actionsInProgress.push_back(action);

QDBusPendingCall pendingCall = m_busConnection.asyncCall(message);

...
}

This code is invoking the performAction() DBUS method, passing along the
user supplied arguments dictionary, in our smb4k case containing the
handcrafted evil "mh_command" key, amongst others key/value pairs.

There are two problems:

The KAuth frameworks performAction() method is passed the callerID by the
user and the method is invokable by the user. This allows to mask as any
caller, bypassing any polkit checks that may happen later in the KAuth
polkit backend via calls into

PolicyKitBackend::isCallerAuthorized(const QString &action,
                                     QByteArray callerID)

The second problem is smb4k trusting the arguments that are passed from the
user and which are forwarded by the KAuth DBUS service running as root to
the mount helper DBUS service which is also running as root but not allowed
to be contacted by users.
Thats a logical flaw. It was probably not intented that users invoke
performAction() themself, using it as a proxy into DBUS services and
faking caller IDs en-passant. The callerID usually looks like ":1.123"
and is a DBUS unique name that maps to the sender of the message.
You can think of it like the source address of an IP packet.
This ID should be obtained via a DBUS function while the message is
arriving, so it can actually be trusted and used as a subject for polit
authorizations when using systembus-name subjects. Allowing callers to
arbitrarily choosing values for this ID is taking down the whole idea
of authentication and authorization.

I made an exploit for smb4k that works on openSUSE Leap 42.2 thats using
the org.kde.auth interface (rather than org.kde.kf5auth) but both
interfaces share the same problems. The exploit also works on the latest
Fedora26 Alpha kde spin with SELinux in enforcing mode. In order to test
the callerID spoofing, I "protected" the smb4k helper code via "auth_admin"
polkit settings and tried mounting SMB shares via smb4k GUI. This asked for
the root password, as its expected. The exploit however still works, as its
spoofing the callerID to be DBUs itself and the request is taken as legit,
requiring no root password.
Comment 14 Bernhard Wiedemann 2017-05-10 14:01:10 UTC
This is an autogenerated message for OBS integration:
This bug (1036244) was mentioned in
https://build.opensuse.org/request/show/494217 42.3 / kauth
Comment 15 Bernhard Wiedemann 2017-05-10 16:01:43 UTC
This is an autogenerated message for OBS integration:
This bug (1036244) was mentioned in
https://build.opensuse.org/request/show/494349 Backports:SLE-12-SP1 / kauth
https://build.opensuse.org/request/show/494353 42.1 / kauth
Comment 16 Bernhard Wiedemann 2017-05-10 18:01:41 UTC
This is an autogenerated message for OBS integration:
This bug (1036244) was mentioned in
https://build.opensuse.org/request/show/494397 42.1+42.2+Backports:SLE-12-SP1+Backports:SLE-12-SP2 / kdelibs4
Comment 18 Swamp Workflow Management 2017-05-15 16:11:01 UTC
openSUSE-SU-2017:1254-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1036244
CVE References: CVE-2017-8422
Sources used:
SUSE Package Hub for SUSE Linux Enterprise 12 (src):    kauth-5.20.0-7.1, kauth-5.26.0-6.1, kdelibs4-4.14.18-9.1, kdelibs4-4.14.25-8.2, kdelibs4-apidocs-4.14.18-9.1, kdelibs4-apidocs-4.14.25-8.2
Comment 19 Swamp Workflow Management 2017-05-15 16:22:52 UTC
openSUSE-SU-2017:1272-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1036244
CVE References: CVE-2017-8422
Sources used:
openSUSE Leap 42.2 (src):    kauth-5.26.0-2.3.1, kdelibs4-4.14.25-7.4.1, kdelibs4-apidocs-4.14.25-7.4.1
openSUSE Leap 42.1 (src):    kauth-5.21.0-16.1, kdelibs4-4.14.18-18.1, kdelibs4-apidocs-4.14.18-18.1
Comment 21 Swamp Workflow Management 2017-05-18 16:23:52 UTC
SUSE-SU-2017:1335-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1036244
CVE References: CVE-2017-8422
Sources used:
SUSE Linux Enterprise Server for Raspberry Pi 12-SP2 (src):    kdelibs4-4.12.0-10.1
SUSE Linux Enterprise Server 12-SP2 (src):    kdelibs4-4.12.0-10.1
SUSE Linux Enterprise Server 12-SP1 (src):    kdelibs4-4.12.0-10.1
SUSE Linux Enterprise Desktop 12-SP2 (src):    kdelibs4-4.12.0-10.1
SUSE Linux Enterprise Desktop 12-SP1 (src):    kdelibs4-4.12.0-10.1