Bugzilla – Bug 1036244
VUL-0: CVE-2017-8422: KDE KAuth bypass
Last modified: 2024-05-17 11:52:48 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.
Created attachment 723396 [details] First patch from upstream First patch from upstream
Created attachment 723397 [details] Second patch from upstream .
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.
CRD: 2017-05-15
CVE-2017-8422 from KDE project
new CRD: 2017-05-10
In KDE GIT: https://cgit.kde.org/kauth.git/commit/?id=df875f725293af53399f5146362eb158b4f9216a
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
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
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.
This is an autogenerated message for OBS integration: This bug (1036244) was mentioned in https://build.opensuse.org/request/show/494217 42.3 / kauth
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
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
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
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
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