Bug 1036245 (CVE-2017-8849) - VUL-0: CVE-2017-8849: smb4k local root exploit
Summary: VUL-0: CVE-2017-8849: smb4k local root exploit
Status: RESOLVED FIXED
Alias: CVE-2017-8849
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Normal
Target Milestone: ---
Assignee: Security Team bot
QA Contact: Security Team bot
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-04-26 10:22 UTC by Sebastian Krahmer
Modified: 2017-05-20 06:48 UTC (History)
4 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Krahmer 2017-04-26 10:22:05 UTC
+++ This bug was initially created as a clone of Bug #1036244 +++

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 1 Sebastian Krahmer 2017-04-26 10:22:42 UTC
This is the split off for fixing/removing smb4k.
Comment 2 Andreas Stieger 2017-04-26 12:35:27 UTC
This was sent to security@kde.org and pending an answer/confirmation from them.
We do not expect a quick fix to we available, also due to bug 1036244.
An initial thought for a maintenance update would be to remove the mount capability from the package while retaining the network browsing functionality.
Comment 3 Marcus Meissner 2017-05-02 11:16:08 UTC
CRD: 2017-05-15
Comment 4 Sebastian Krahmer 2017-05-03 13:46:09 UTC
New CRD: 2017-05-10
Comment 5 Sebastian Krahmer 2017-05-09 13:09:30 UTC
CVE-2017-8849
Comment 6 Matthias Gerstner 2017-05-17 14:47:29 UTC
I have just submitted maintenance updates for Leap 41.2, 42.2 that will remove
the dbus service and policy files, thus disarming the local root exploit for
smb4k.

mr#495637, mr#495638

QA reproducer:

Before installing the update:

  $ rpm -ql smb4k | fgrep mounthelper.
  /etc/dbus-1/system.d/net.sourceforge.smb4k.mounthelper.conf
  /usr/share/dbus-1/system-services/net.sourceforge.smb4k.mounthelper.service
  /usr/share/polkit-1/actions/net.sourceforge.smb4k.mounthelper.policy

After installing the update 

  $ rpm -ql smb4k | fgrep mounthelper.
  -> no matches
Comment 7 Bernhard Wiedemann 2017-05-17 16:03:38 UTC
This is an autogenerated message for OBS integration:
This bug (1036245) was mentioned in
https://build.opensuse.org/request/show/495656 42.2 / smb4k
Comment 8 Andreas Stieger 2017-05-18 16:06:30 UTC
released for 42.2
Comment 9 Swamp Workflow Management 2017-05-18 19:12:01 UTC
openSUSE-SU-2017:1343-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1036245
CVE References: CVE-2017-8849
Sources used:
openSUSE Leap 42.2 (src):    smb4k-1.2.1-3.3.1