macOS IPC - Inter Process Communication
Last updated
Last updated
Učite i vežbajte hakovanje AWS-a:HackTricks Obuka AWS Crveni Tim Stručnjak (ARTE) Učite i vežbajte hakovanje GCP-a: HackTricks Obuka GCP Crveni Tim Stručnjak (GRTE)
Mach koristi taskove kao najmanju jedinicu za deljenje resursa, pri čemu svaki task može sadržati više niti. Ovi taskovi i niti su mapirani 1:1 na POSIX procese i niti.
Komunikacija između taskova se odvija putem Mach Inter-Process Communication (IPC), koristeći jednosmerne komunikacione kanale. Poruke se prenose između portova, koji deluju kao vrste redova poruka upravljanih od strane jezgra.
Port je osnovni element Mach IPC-a. Može se koristiti za slanje poruka i za njihovo primanje.
Svaki proces ima IPC tabelu, u kojoj je moguće pronaći mach portove procesa. Ime mach porta zapravo predstavlja broj (pokazivač na jezgrovni objekat).
Proces takođe može poslati ime porta sa određenim pravima drugom tasku i jezgro će napraviti ovaj unos u IPC tabeli drugog taska.
Prava na portovima, koja definišu koje operacije task može izvršiti, ključna su za ovu komunikaciju. Moguća prava na portovima su (definicije odavde):
Pravo na primanje, koje omogućava primanje poruka poslatih portu. Mach portovi su MPSC (multiple-producer, single-consumer) redovi, što znači da može postojati samo jedno pravo na primanje za svaki port u celom sistemu (za razliku od cevi, gde više procesa može držati deskriptore fajlova za čitanje sa jednog kraja cevi).
Task sa Pravom na primanje može primati poruke i kreirati Prava na slanje, omogućavajući mu slanje poruka. Originalno samo sopstveni task ima Pravo na primanje nad svojim portom.
Ako vlasnik Prava na primanje umre ili ga ubije, pravo na slanje postaje beskorisno (mrtvo ime).
Pravo na slanje, koje omogućava slanje poruka portu.
Pravo na slanje se može klonirati tako da task koji poseduje Pravo na slanje može klonirati pravo i dodeliti ga trećem tasku.
Imajte na umu da se prava na portovima takođe mogu prosleđivati putem Mac poruka.
Pravo na jednokratno slanje, koje omogućava slanje jedne poruke portu i zatim nestaje.
Ovo pravo ne može biti klonirano, ali se može premestiti.
Pravo na set portova, koje označava set portova umesto pojedinačnog porta. Skidanje poruke sa seta portova skida poruku sa jednog od portova koje sadrži. Set portova se može koristiti za osluškivanje više portova istovremeno, slično kao select
/poll
/epoll
/kqueue
u Unix-u.
Mrtvo ime, koje nije stvarno pravo na portu, već samo oznaka. Kada se port uništi, sva postojeća prava na portu postaju mrtva imena.
Taskovi mogu preneti SEND prava drugima, omogućavajući im da pošalju poruke nazad. SEND prava takođe mogu biti klonirana, tako da task može duplicirati pravo i dati ga trećem tasku. Ovo, zajedno sa posredničkim procesom poznatim kao bootstrap server, omogućava efikasnu komunikaciju između taskova.
Portovi fajlova omogućavaju da se deskriptori fajlova enkapsuliraju u Mac portove (koristeći prava na Mach portovima). Moguće je kreirati fileport
od datog FD koristeći fileport_makeport
i kreirati FD iz fileporta koristeći fileport_makefd
.
Kao što je ranije pomenuto, moguće je slati prava korišćenjem Mach poruka, međutim, ne možete poslati pravo bez već postojećeg prava za slanje Mach poruke. Kako se onda uspostavlja prva komunikacija?
Za to je uključen bootstrap server (launchd na Mac-u), pošto svako može dobiti SEND pravo ka bootstrap serveru, moguće je zatražiti od njega pravo da se pošalje poruka drugom procesu:
Task A kreira novi port, dobijajući PRIMI right nad njim.
Task A, kao nosilac PRIMI prava, generiše SEND pravo za port.
Task A uspostavlja vezu sa bootstrap serverom, i šalje mu SEND pravo za port koji je generisao na početku.
Zapamtite da svako može dobiti SEND pravo ka bootstrap serveru.
Task A šalje poruku bootstrap_register
bootstrap serveru da poveže dati port sa imenom kao što je com.apple.taska
Task B interaguje sa bootstrap serverom da izvrši bootstrap pretragu za imenom servisa (bootstrap_lookup
). Da bi bootstrap server mogao da odgovori, task B će mu poslati SEND pravo ka portu koji je prethodno kreirao unutar poruke pretrage. Ako je pretraga uspešna, server duplira SEND pravo primljeno od Task A i prebacuje ga Task B.
Zapamtite da svako može dobiti SEND pravo ka bootstrap serveru.
Sa ovim SEND pravom, Task B je sposoban da pošalje poruku Task A.
Za dvosmernu komunikaciju obično task B generiše novi port sa PRIMI pravom i SEND pravom, i daje SEND pravo Task A tako da može slati poruke TASK B (dvosmerna komunikacija).
Bootstrap server ne može autentifikovati ime servisa koje tvrdi task. Ovo znači da bi task potencijalno mogao predstavljati bilo koji sistemski task, kao što je lažno tvrditi ime autorizacionog servisa a zatim odobravati svaki zahtev.
Zatim, Apple čuva imena sistema pruženih servisa u sigurnim konfiguracionim fajlovima, smeštenim u SIP-zaštićenim direktorijumima: /System/Library/LaunchDaemons
i /System/Library/LaunchAgents
. Pored svakog imena servisa, takođe je sačuvana povezana binarna datoteka. Bootstrap server će kreirati i držati PRIMI pravo za svako od ovih imena servisa.
Za ove unapred definisane servise, proces pretrage se malo razlikuje. Kada se traži ime servisa, launchd pokreće servis dinamički. Novi tok rada je sledeći:
Task B pokreće bootstrap pretragu za imenom servisa.
launchd proverava da li je task pokrenut i ako nije, ga pokreće.
Task A (servis) izvršava bootstrap check-in (bootstrap_check_in()
). Ovde, bootstrap server kreira SEND pravo, zadržava ga, i prebacuje PRIMI pravo Task A.
launchd duplira SEND pravo i šalje ga Task B.
Task B generiše novi port sa PRIMI pravom i SEND pravom, i daje SEND pravo Task A (servisu) tako da može slati poruke TASK B (dvosmerna komunikacija).
Međutim, ovaj proces se odnosi samo na unapred definisane sistemski taskove. Ne-sistemski taskovi i dalje funkcionišu kao što je opisano originalno, što bi potencijalno moglo omogućiti za predstavljanje.
Stoga, launchd nikada ne bi trebalo da se sruši ili će ceo sistem pasti.
Funkcija mach_msg
, suštinski sistemski poziv, koristi se za slanje i primanje Mach poruka. Funkcija zahteva da poruka bude poslata kao početni argument. Ova poruka mora početi sa strukturom mach_msg_header_t
, a zatim sledi stvarni sadržaj poruke. Struktura je definisana na sledeći način:
Procesi koji poseduju pravo na prijem mogu primati poruke na Mach portu. Nasuprot tome, pošiljaoci imaju dozvolu za slanje ili jednokratno slanje. Pravo jednokratnog slanja je isključivo za slanje jedne poruke, nakon čega postaje nevažeće.
Početno polje msgh_bits
je mapa bitova:
Prvi bit (najznačajniji) se koristi za označavanje da je poruka kompleksna (više o tome ispod)
i 4. bit se koriste od strane jezgra
5 najmanje značajnih bitova 2. bajta mogu se koristiti za vaučer: druga vrsta porta za slanje kombinacija ključ/vrednost.
5 najmanje značajnih bitova 3. bajta mogu se koristiti za lokalni port
5 najmanje značajnih bitova 4. bajta mogu se koristiti za udaljeni port
Tipovi koji se mogu navesti u vaučeru, lokalnim i udaljenim portovima su (iz mach/message.h):
Na primer, MACH_MSG_TYPE_MAKE_SEND_ONCE
može se koristiti da ukazuje da bi trebalo izvesti i preneti jednokratno slanje prava za ovaj port. Takođe se može specificirati MACH_PORT_NULL
da bi se sprečilo da primalac može da odgovori.
Da bi se postigla jednostavna dvosmerna komunikacija, proces može specificirati mach port u mach zaglavlju poruke nazvan reply port (msgh_local_port
) gde primalac poruke može poslati odgovor na ovu poruku.
Imajte na umu da se ovakva vrsta dvosmerne komunikacije koristi u XPC porukama koje očekuju odgovor (xpc_connection_send_message_with_reply
i xpc_connection_send_message_with_reply_sync
). Ali se obično stvaraju različiti portovi kako je objašnjeno ranije da bi se stvorila dvosmerna komunikacija.
Ostala polja zaglavlja poruke su:
msgh_size
: veličina celog paketa.
msgh_remote_port
: port preko kojeg je poslata ova poruka.
msgh_voucher_port
: mach vaučeri.
msgh_id
: ID ove poruke, koji tumači primalac.
Imajte na umu da se mach poruke šalju preko mach porta
, koji je kanal komunikacije sa jednim primaocem, više pošiljalaca ugrađen u mach kernel. Više procesa može slati poruke na mach port, ali u svakom trenutku samo jedan proces može čitati iz njega.
Poruke se zatim formiraju mach_msg_header_t
zaglavljem praćenim telom i trailerom (ako postoji) i može dozvoliti odobrenje za odgovor na nju. U tim slučajevima, kernel jednostavno treba da prosledi poruku iz jednog zadatka drugom.
Trailer je informacija dodata poruci od strane kernela (ne može je postaviti korisnik) koja se može zatražiti prilikom prijema poruke sa zastavicom MACH_RCV_TRAILER_<trailer_opt>
(postoji različite informacije koje se mogu zatražiti).
Međutim, postoje i druge više kompleksne poruke, poput onih koje prenose dodatna prava porta ili dele memoriju, gde kernel takođe mora da pošalje ove objekte primaocu. U ovim slučajevima, najznačajniji bit zaglavlja msgh_bits
je postavljen.
Mogući deskriptori za prenos su definisani u mach/message.h
:
U 32 bitnom režimu, svi deskriptori su 12B i tip deskriptora je u 11. U 64 bitnom režimu, veličine variraju.
Kernel će kopirati deskriptore iz jednog zadatka u drugi, ali prvo kreira kopiju u jezgrovitoj memoriji. Ova tehnika, poznata kao "Feng Shui", zloupotrebljena je u nekoliko eksploatacija kako bi naterala kernel da kopira podatke u svojoj memoriji, omogućavajući procesu da šalje deskriptore sebi. Zatim proces može primati poruke (kernel će ih osloboditi).
Takođe je moguće poslati prava porta ranjivom procesu, i prava porta će se jednostavno pojaviti u procesu (čak i ako ih ne obrađuje).
Imajte na umu da su portovi povezani sa imenikom zadatka, pa prilikom kreiranja ili pretrage porta, takođe se pretražuje imenik zadatka (više u mach/mach_port.h
):
mach_port_allocate
| mach_port_construct
: Kreirajte port.
mach_port_allocate
takođe može kreirati skup portova: primi pravo nad grupom portova. Svaki put kada se primi poruka, naznačen je port sa kog je poslata.
mach_port_allocate_name
: Promenite ime porta (podrazumevano je 32-bitni ceo broj)
mach_port_names
: Dobijanje imena porta iz cilja
mach_port_type
: Dobijanje prava zadatka nad imenom
mach_port_rename
: Preimenujte port (kao dup2 za FD-ove)
mach_port_allocate
: Alocirajte novi PRIMI, PORT_SET ili DEAD_NAME
mach_port_insert_right
: Kreirajte novo pravo u portu gde imate PRIMI
mach_port_...
mach_msg
| mach_msg_overwrite
: Funkcije korišćene za slanje i primanje mach poruka. Verzija za prepisivanje omogućava da se navede drugi bafer za prijem poruke (druga verzija će ga jednostavno ponovo koristiti).
Pošto su funkcije mach_msg
i mach_msg_overwrite
one koje se koriste za slanje i primanje poruka, postavljanje prekidača na njih omogućilo bi inspekciju poslatih i primljenih poruka.
Na primer, počnite sa debagovanjem bilo koje aplikacije koju možete debagovati jer će učitati libSystem.B
koja će koristiti ovu funkciju.
Dobijanje vrednosti iz registara:
Pregledajte zaglavlje poruke proveravajući prvi argument:
Taj tip mach_msg_bits_t
je vrlo čest kako bi omogućio odgovor.
Ime je podrazumevano ime dodeljeno portu (proverite kako se povećava u prva 3 bajta). ipc-object
je zamagljeni jedinstveni identifikator porta.
Takođe obratite pažnju kako portovi sa samo send
pravom identifikuju vlasnika (ime porta + pid).
Takođe obratite pažnju na upotrebu +
za označavanje drugih zadataka povezanih sa istim portom.
Takođe je moguće koristiti procesxp da biste videli i registrovana imena servisa (sa onemogućenim SIP-om zbog potrebe za com.apple.system-task-port
):
Možete instalirati ovaj alat u iOS preuzimanjem sa http://newosxbook.com/tools/binpack64-256.tar.gz
Obratite pažnju kako pošiljalac dodeljuje port, kreira send right za ime org.darlinghq.example
i šalje ga bootstrap serveru dok je pošiljalac zatražio send right za to ime i koristio ga je da pošalje poruku.
Ovaj program demonstrira kako se može koristiti IPC za komunikaciju između procesa na macOS operativnom sistemu. Program kreira poruku i šalje je drugom procesu korišćenjem IPC mehanizma. Poruka sadrži informacije o trenutnom vremenu i datumu. Nakon slanja poruke, program čeka na odgovor od drugog procesa. Ako odgovor sadrži određeni ključ, program dobija privilegije za pristup određenim resursima na sistemu.
Postoje neki posebni portovi koji omogućavaju izvođenje određenih osetljivih radnji ili pristup određenim osetljivim podacima u slučaju da zadaci imaju dozvole za slanje (SEND) nad njima. Ovo čini ove portove vrlo zanimljivim iz perspektive napadača ne samo zbog mogućnosti već i zato što je moguće deliti dozvole za slanje između zadataka.
Ovi portovi su predstavljeni brojevima.
Prava za slanje (SEND) mogu se dobiti pozivanjem host_get_special_port
i prava za primanje (RECEIVE) pozivanjem host_set_special_port
. Međutim, oba poziva zahtevaju port host_priv
koji može pristupiti samo root. Osim toga, u prošlosti je root mogao pozvati host_set_special_port
i preuzeti proizvoljne koji su omogućavali na primer zaobilaženje potpisa koda preuzimanjem HOST_KEXTD_PORT
(SIP sada sprečava ovo).
Oni su podeljeni u 2 grupe: Prvih 7 portova su u vlasništvu jezgra pri čemu je 1 HOST_PORT
, 2 HOST_PRIV_PORT
, 3 HOST_IO_MASTER_PORT
, a 7 je HOST_MAX_SPECIAL_KERNEL_PORT
.
Oni koji počinju od broja 8 su u vlasništvu sistemskih demona i mogu se pronaći deklarisani u host_special_ports.h
.
Host port: Ako proces ima privilegiju slanja (SEND) nad ovim portom, može dobiti informacije o sistemu pozivanjem njegovih rutina poput:
host_processor_info
: Dobijanje informacija o procesoru
host_info
: Dobijanje informacija o domaćinu
host_virtual_physical_table_info
: Virtuelna/fizička tabela stranica (zahteva MACH_VMDEBUG)
host_statistics
: Dobijanje statistika domaćina
mach_memory_info
: Dobijanje rasporeda memorije jezgra
Host Priv port: Proces sa pravom slanja (SEND) nad ovim portom može izvršiti privilegovane radnje poput prikazivanja podataka o pokretanju ili pokušaja učitavanja proširenja jezgra. Proces mora biti root da bi dobio ovu dozvolu.
Osim toga, da bi pozvao kext_request
API, potrebno je imati druge privilegije com.apple.private.kext*
koje se dodeljuju samo Apple binarnim datotekama.
Druge rutine koje se mogu pozvati su:
host_get_boot_info
: Dobijanje machine_boot_info()
host_priv_statistics
: Dobijanje privilegovanih statistika
vm_allocate_cpm
: Alokacija kontinualne fizičke memorije
host_processors
: Pravo slanja domaćinima procesora
mach_vm_wire
: Čini memoriju rezidentnom
Pošto root može pristupiti ovoj dozvoli, mogao bi pozvati host_set_[special/exception]_port[s]
da preuzme specijalne ili izuzetne portove domaćina.
Moguće je videti sve specijalne portove domaćina pokretanjem:
Ovo su portovi rezervisani za dobro poznate servise. Moguće ih je dobiti/postaviti pozivanjem task_[get/set]_special_port
. Mogu se pronaći u task_special_ports.h
:
Sa ovde:
TASK_KERNEL_PORT[task-self send right]: Port koji se koristi za kontrolu ovog zadatka. Koristi se za slanje poruka koje utiču na zadatak. Ovo je port koji vraća mach_task_self (vidi Task Ports ispod).
TASK_BOOTSTRAP_PORT[bootstrap send right]: Bootstrap port zadatka. Koristi se za slanje poruka koje zahtevaju povratak drugih sistema servisnih portova.
TASK_HOST_NAME_PORT[host-self send right]: Port koji se koristi za zahtevanje informacija o sadržaju domaćina. Ovo je port koji vraća mach_host_self.
TASK_WIRED_LEDGER_PORT[ledger send right]: Port koji imenuje izvor iz kojeg ovaj zadatak crpi svoju žičanu jezgru memorije.
TASK_PAGED_LEDGER_PORT[ledger send right]: Port koji imenuje izvor iz kojeg ovaj zadatak crpi svoju podrazumevanu memoriju upravljane memorije.
Originalno, Mach nije imao "procese", već "zadatke" koji su se smatrali više kao kontejneri niti. Kada je Mach spojen sa BSD svaki zadatak je bio povezan sa BSD procesom. Stoga, svaki BSD proces ima detalje potrebne da bude proces, a svaki Mach zadatak takođe ima svoje unutrašnje funkcije (osim nepostojećeg pid 0 koji je kernel_task
).
Postoje dve veoma interesantne funkcije koje su povezane sa ovim:
task_for_pid(target_task_port, pid, &task_port_of_pid)
: Dobijanje SEND prava za zadatak povezan sa određenim pid
i davanje toga prava određenom target_task_port
(koji je obično pozivački zadatak koji je koristio mach_task_self()
, ali može biti SEND port preko drugog zadatka.)
pid_for_task(task, &pid)
: Dajući SEND pravo zadatku, pronađi sa kojim PID-om je taj zadatak povezan.
Da bi izvršio radnje unutar zadatka, zadatak je trebao SEND
pravo sebi pozivajući mach_task_self()
(koji koristi task_self_trap
(28)). Sa ovlašćenjem, zadatak može izvršiti nekoliko radnji kao što su:
task_threads
: Dobijanje SEND prava nad svim zadacima niti zadatka
task_info
: Dobijanje informacija o zadatku
task_suspend/resume
: Pauziranje ili nastavljanje zadatka
task_[get/set]_special_port
thread_create
: Kreiranje niti
task_[get/set]_state
: Kontrola stanja zadatka
i još se može naći u mach/task.h
Primetite da sa SEND pravom nad zadatkom drugog zadatka, moguće je izvršiti takve radnje nad drugim zadatkom.
Osim toga, task_port je takođe vm_map
port koji omogućava čitanje i manipulaciju memorijom unutar zadatka pomoću funkcija poput vm_read()
i vm_write()
. To u osnovi znači da će zadatak sa SEND pravima nad task_portom drugog zadatka biti u mogućnosti da ubaci kod u taj zadatak.
Zapamtite da je kernel takođe zadatak, ako neko uspe da dobije SEND dozvole nad kernel_task
, biće u mogućnosti da natera kernel da izvrši bilo šta (jailbreaks).
Pozovi mach_task_self()
da dobiješ ime za ovaj port za pozivački zadatak. Ovaj port se nasleđuje samo preko exec()
; novi zadatak kreiran sa fork()
dobija novi zadatak port (kao poseban slučaj, zadatak takođe dobija novi zadatak port nakon exec()
u suid binarnom fajlu). Jedini način da pokreneš zadatak i dobiješ njegov port je da izvedeš "port swap dance" dok radiš fork()
.
Ovo su ograničenja za pristup portu (iz macos_task_policy
iz binarnog fajla AppleMobileFileIntegrity
):
Ako aplikacija ima com.apple.security.get-task-allow
privilegiju procesi od iste korisnika mogu pristupiti zadatkovom portu (obično dodato od strane Xcode-a za debagovanje). Proces notarizacije neće dozvoliti to u produkcijskim verzijama.
Aplikacije sa com.apple.system-task-ports
privilegijom mogu dobiti zadatkov port za bilo koji proces, osim kernela. U starijim verzijama se zvalo task_for_pid-allow
. Ovo je dozvoljeno samo Apple aplikacijama.
Root može pristupiti zadatkovim portovima aplikacija koje nisu kompajlovane sa hardened runtime-om (i ne od strane Apple-a).
Port imena zadatka: Neovlašćena verzija zadatkovog porta. Referiše na zadatak, ali ne dozvoljava kontrolu. Jedina stvar koja se čini dostupnom kroz njega je task_info()
.
Niti takođe imaju povezane portove, koji su vidljivi iz zadatka koji poziva task_threads
i iz procesora sa processor_set_threads
. SEND pravo na port niti omogućava korišćenje funkcija iz podsistema thread_act
, kao što su:
thread_terminate
thread_[get/set]_state
act_[get/set]_state
thread_[suspend/resume]
thread_info
...
Bilo koja nit može dobiti ovaj port pozivom mach_thread_sef
.
Možeš preuzeti shell kod sa:
Inter-process communication (IPC) is a set of methods for the exchange of data among multiple threads in one or more processes. macOS provides several IPC mechanisms, such as Mach ports, XPC services, and UNIX domain sockets. These mechanisms can be abused by malicious actors to escalate privileges or perform other unauthorized actions on a system.
Mach Ports
Mach ports are low-level communication endpoints used by processes to send and receive messages. They can be used for inter-process communication within a single system or between different systems. Malicious actors can abuse Mach ports to intercept sensitive data or manipulate inter-process communication to their advantage.
XPC Services
XPC services allow processes to communicate with each other securely. However, if not properly configured, they can be exploited by attackers to execute arbitrary code or escalate privileges. It is essential to review and secure XPC services to prevent unauthorized access and privilege escalation.
UNIX Domain Sockets
UNIX domain sockets enable communication between processes on the same system. They can be misused by threat actors to bypass security mechanisms and gain unauthorized access to sensitive resources. Securing UNIX domain sockets is crucial to protect against IPC-based attacks.
To enhance the security of macOS systems, it is important to understand how IPC mechanisms work and implement proper controls to prevent abuse by malicious entities. Regular security assessments and monitoring can help detect and mitigate potential IPC-related vulnerabilities.
Kompajlujte prethodni program i dodajte ovlašćenja kako biste mogli da ubacite kod sa istim korisnikom (ako ne, moraćete koristiti sudo).