macOS IPC - Inter Process Communication
Last updated
Last updated
Leer & oefen AWS Hacking:HackTricks Opleiding AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Opleiding GCP Red Team Expert (GRTE)
Mach gebruik take as die kleinste eenheid vir die deel van hulpbronne, en elke taak kan verskeie drade bevat. Hierdie take en drade word 1:1 gekarteer na POSIX-prosesse en drade.
Kommunikasie tussen take vind plaas via Mach Interproses Kommunikasie (IPC), wat eenrigting kommunikasiekanaal benut. Boodskappe word oorgedra tussen hawens, wat soortgelyk aan boodskaprye optree wat deur die kernel bestuur word.
'n Hawe is die basiese element van Mach IPC. Dit kan gebruik word om boodskappe te stuur en te ontvang.
Elke proses het 'n IPC-tabel, waarin dit moontlik is om die mach-hawens van die proses te vind. Die naam van 'n mach-hawe is eintlik 'n nommer (‘n wyser na die kernel-voorwerp).
'n Proses kan ook 'n hawenaam met sekere regte na 'n ander taak stuur en die kernel sal hierdie inskrywing in die IPC-tabel van die ander taak laat verskyn.
Haweregte, wat definieer watter operasies 'n taak kan uitvoer, is sleutel tot hierdie kommunikasie. Die moontlike haweregte is (definisies vanaf hier):
Ontvangsreg, wat die ontvangs van boodskappe wat na die hawe gestuur is, moontlik maak. Mach-hawens is MPSC (meervoudige-vervaardiger, enkelverbruiker) rye, wat beteken dat daar slegs een ontvangsreg vir elke hawe in die hele stelsel kan wees (in teenstelling met pype, waar meervoudige prosesse almal lêerbeskrywers na die lees-einde van een pyp kan hê).
'n Taak met die Ontvangsreg kan boodskappe ontvang en Sendregte skep, wat dit moontlik maak om boodskappe te stuur. Aanvanklik het slegs die eie taak Ontvangsreg oor sy hawe.
As die eienaar van die Ontvangsreg sterf of dit doodmaak, word die sendreg nutteloos (dood naam).
Sendreg, wat dit moontlik maak om boodskappe na die hawe te stuur.
Die Sendreg kan gekloneer word sodat 'n taak wat 'n Sendreg besit, die reg kan kloon en dit aan 'n derde taak kan toeken.
Let daarop dat haweregte ook deur Mac-boodskappe oorgedra kan word.
Send-eenkeer-reg, wat dit moontlik maak om een boodskap na die hawe te stuur en dan te verdwyn.
Hierdie reg kan nie gekloneer word nie, maar dit kan geskuif word.
Hawestelreg, wat 'n hawe stel aandui eerder as 'n enkele hawe. Die ontkoppeling van 'n boodskap van 'n hawe stel ontkoppel 'n boodskap van een van die hawens wat dit bevat. Hawestelle kan gebruik word om gelyktydig na verskeie hawens te luister, soos select
/poll
/epoll
/kqueue
in Unix.
Dood naam, wat nie 'n werklike hawe reg is nie, maar bloot 'n plekhouer. Wanneer 'n hawe vernietig word, verander alle bestaande hawe regte na die hawe in dood name.
Take kan SEND-regte na ander oordra, wat hulle in staat stel om boodskappe terug te stuur. SEND-regte kan ook gekloneer word, sodat 'n taak die reg kan dupliseer en dit aan 'n derde taak kan gee. Dit, saam met 'n bemiddelende proses wat bekend staan as die opstartsdiens, maak effektiewe kommunikasie tussen take moontlik.
Lêerhawens maak dit moontlik om lêerbeskrywers in Mac-hawens in te sluit (deur Mach-haweregte te gebruik). Dit is moontlik om 'n fileport
vanaf 'n gegewe FD te skep deur fileport_makeport
te gebruik en 'n FD vanaf 'n lêerhawe te skep deur fileport_makefd
te gebruik.
Soos voorheen genoem, is dit moontlik om regte te stuur deur Mach-boodskappe, maar jy kan nie 'n reg stuur sonder om reeds 'n reg te hê om 'n Mach-boodskap te stuur nie. Hoe word die eerste kommunikasie dan gevestig?
Hiervoor is die opstartsdiens (launchd in Mac) betrokke, aangesien almal 'n SEND-reg na die opstartsdiens kan kry, is dit moontlik om dit te vra vir 'n reg om 'n boodskap na 'n ander proses te stuur:
Taak A skep 'n nuwe hawe, kry die ONTVANG reg daaroor.
Taak A, as die houer van die ONTVANG reg, skep 'n SEND reg vir die hawe.
Taak A vestig 'n verbindings met die opstartsdiens, en stuur dit die SEND reg vir die hawe wat dit aan die begin geskep het.
Onthou dat enigeen 'n SEND reg na die opstartsdiens kan kry.
Taak A stuur 'n bootstrap_register
boodskap na die opstartsdiens om die gegewe hawe met 'n naam soos com.apple.taska
te assosieer.
Taak B interaksie met die opstartsdiens om 'n opstarts soektog vir die diensnaam (bootstrap_lookup
) uit te voer. Sodat die opstartsdiens kan reageer, sal taak B 'n SEND reg na 'n hawe wat dit voorheen geskep het binne die soektog-boodskap stuur. As die soektog suksesvol is, dupliseer die bediener die SEND reg wat van Taak A ontvang is en stuur dit na Taak B.
Onthou dat enigeen 'n SEND reg na die opstartsdiens kan kry.
Met hierdie SEND reg is Taak B in staat om 'n boodskap na Taak A te stuur.
Vir 'n tweerigting kommunikasie skep taak B gewoonlik 'n nuwe hawe met 'n ONTVANG reg en 'n SEND reg, en gee die SEND reg aan Taak A sodat dit boodskappe aan TAASK B kan stuur (tweerigting kommunikasie).
Die opstartsdiens kan nie die diensnaam autentiseer wat deur 'n taak beweer word nie. Dit beteken 'n taak kan potensieel enige stelseltaak naboots, soos valse goedkeuring van 'n outorisasiediensnaam en dan elke versoek goedkeur.
Dan stoor Apple die name van stelselverskafde dienste in veilige konfigurasie lêers, geleë in SIP-beskermde gids: /System/Library/LaunchDaemons
en /System/Library/LaunchAgents
. Saam met elke diensnaam word ook die geassosieerde binêre lêer gestoor. Die opstartsdiens sal 'n ONTVANG reg vir elkeen van hierdie diensname skep en behou.
Vir hierdie voorgedefinieerde dienste, verskil die soektogproses effens. Wanneer 'n diensnaam opgesoek word, begin launchd die diens dinamies. Die nuwe werkstroom is as volg:
Taak B inisieer 'n opstarts soektog vir 'n diensnaam.
launchd kontroleer of die taak loop en as dit nie is nie, begin dit.
Taak A (die diens) voer 'n opstarts inligting uit (bootstrap_check_in()
). Hier skep die opstarts diens 'n SEND reg, behou dit, en oorhandig die ONTVANG reg aan Taak A.
launchd dupliseer die SEND reg en stuur dit na Taak B.
Taak B skep 'n nuwe hawe met 'n ONTVANG reg en 'n SEND reg, en gee die SEND reg aan Taak A (die diens) sodat dit boodskappe aan TAASK B kan stuur (tweerigting kommunikasie).
Hierdie proses geld egter slegs vir voorgedefinieerde stelseltake. Nie-stelsel take werk steeds soos aanvanklik beskryf, wat potensieel die moontlikheid vir nabootsing kan toelaat.
Daarom behoort launchd nooit te bots nie, anders sal die hele stelsel bots.
Die mach_msg
-funksie, essensieel 'n stelseloproep, word gebruik om Mach-boodskappe te stuur en te ontvang. Die funksie vereis dat die boodskap as die aanvanklike argument gestuur word. Hierdie boodskap moet begin met 'n mach_msg_header_t
-struktuur, gevolg deur die werklike boodskapinhoud. Die struktuur word soos volg gedefinieer:
Prosesse wat 'n ontvangsreg besit, kan boodskappe op 'n Mach-poort ontvang. Omgekeerd word aan die senders 'n stuur of 'n eenmalige stuur reg toegeken. Die eenmalige stuur reg is uitsluitlik vir die stuur van 'n enkele boodskap, waarna dit ongeldig word.
Die aanvanklike veld msgh_bits
is 'n bietjiekaart:
Die eerste bit (mees betekenisvolle) word gebruik om aan te dui dat 'n boodskap kompleks is (meer hieroor hieronder)
Die 3de en 4de word deur die kernel gebruik
Die 5 minst betekenisvolle bits van die 2de byte kan gebruik word vir voucher: 'n ander tipe poort om sleutel/waarde kombinasies te stuur.
Die 5 minst betekenisvolle bits van die 3de byte kan gebruik word vir plaaslike poort
Die 5 minst betekenisvolle bits van die 4de byte kan gebruik word vir afgeleë poort
Die tipes wat in die voucher, plaaslike en afgeleë poorte gespesifiseer kan word is (vanaf mach/message.h):
Byvoorbeeld, MACH_MSG_TYPE_MAKE_SEND_ONCE
kan gebruik word om aan te dui dat 'n stuur-eenmaal-reg afgelei en oorgedra moet word vir hierdie poort. Dit kan ook gespesifiseer word as MACH_PORT_NULL
om te voorkom dat die ontvanger kan antwoord.
Om 'n maklike tweerigting kommunikasie te bereik, kan 'n proses 'n mach-poort spesifiseer in die mach boodskap kop genoem die antwoordpoort (msgh_local_port
) waar die ontvanger van die boodskap 'n antwoord kan stuur op hierdie boodskap.
Let daarop dat hierdie soort tweerigting kommunikasie gebruik word in XPC-boodskappe wat 'n antwoord verwag (xpc_connection_send_message_with_reply
en xpc_connection_send_message_with_reply_sync
). Maar gewoonlik word verskillende poorte geskep soos voorheen verduidelik om die tweerigting kommunikasie te skep.
Die ander velde van die boodskap kop is:
msgh_size
: die grootte van die hele pakkie.
msgh_remote_port
: die poort waarop hierdie boodskap gestuur word.
msgh_voucher_port
: mach vouchers.
msgh_id
: die ID van hierdie boodskap, wat deur die ontvanger geïnterpreteer word.
Let daarop dat mach-boodskappe oor 'n mach-poort
gestuur word, wat 'n enkele ontvanger, veelvuldige stuurder kommunikasiekanaal is wat in die mach-kernel ingebou is. Meer as een proses kan boodskappe stuur na 'n mach-poort, maar op enige punt kan slegs 'n enkele proses daarvan lees.
Boodskappe word dan gevorm deur die mach_msg_header_t
kop gevolg deur die liggaam en deur die trailer (indien enige) en dit kan toestemming verleen om daarop te antwoord. In hierdie gevalle hoef die kernel net die boodskap van die een taak na die ander oor te dra.
'n Trailer is inligting wat deur die kernel by die boodskap gevoeg word (kan nie deur die gebruiker ingestel word nie) wat aangevra kan word in die boodskap ontvangs met die vlae MACH_RCV_TRAILER_<trailer_opt>
(daar is verskillende inligting wat aangevra kan word).
Daar is egter ander meer komplekse boodskappe, soos dié wat addisionele poortregte deurgee of geheue deel, waar die kernel ook hierdie voorwerpe na die ontvanger moet stuur. In hierdie gevalle is die mees beduidende bit van die kop msgh_bits
ingestel.
Die moontlike beskrywers om deur te gee is gedefinieer in mach/message.h
:
In 32bits, al die beskrywers is 12B en die beskrywerstipe is in die 11de een. In 64 bits, varieer die groottes.
Die kernel sal die beskrywers van die een taak na die ander kopieer, maar eerste 'n kopie in die kernel-geheue skep. Hierdie tegniek, bekend as "Feng Shui", is misbruik in verskeie aanvalle om die kernel data in sy geheue te laat kopieer sodat 'n proses beskrywers na homself kan stuur. Dan kan die proses die boodskappe ontvang (die kernel sal hulle vrymaak).
Dit is ook moontlik om poortregte na 'n kwesbare proses te stuur, en die poortregte sal net in die proses verskyn (selfs al hanteer hy dit nie).
Let daarop dat poorte aan die taaknaamruimte gekoppel is, sodat om 'n poort te skep of te soek, die taaknaamruimte ook ondersoek word (meer in mach/mach_port.h
):
mach_port_allocate
| mach_port_construct
: Skep 'n poort.
mach_port_allocate
kan ook 'n poortstel skep: ontvangsreg oor 'n groep poorte. Wanneer 'n boodskap ontvang word, word die poort aangedui waarvandaan dit afkomstig is.
mach_port_allocate_name
: Verander die naam van die poort (standaard 32-bis integer)
mach_port_names
: Kry poortname van 'n teiken
mach_port_type
: Kry regte van 'n taak oor 'n naam
mach_port_rename
: Hernoem 'n poort (soos dup2 vir FD's)
mach_port_allocate
: Allokeer 'n nuwe ONTVANG, POORT_STEL of DOOD_NAAM
mach_port_insert_right
: Skep 'n nuwe reg in 'n poort waar jy ONTVANG het
mach_port_...
mach_msg
| mach_msg_overwrite
: Funksies wat gebruik word om mach-boodskappe te stuur en te ontvang. Die oorskrywingsweergawe maak dit moontlik om 'n ander buffer vir boodskaponvangst te spesifiseer (die ander weergawe sal dit net hergebruik).
Aangesien die funksies mach_msg
en mach_msg_overwrite
diegene is wat gebruik word om boodskappe te stuur en te ontvang, sal dit moontlik wees om 'n breekpunt daarop te stel om die gestuurde en ontvangsboodskappe te ondersoek.
Begin byvoorbeeld met die foutopsporing van enige toepassing wat jy kan foutopspoor aangesien dit libSystem.B
sal laai wat hierdie funksie sal gebruik.
Om die argumente van mach_msg
te kry, ondersoek die registers. Dit is die argumente (van mach/message.h):
Kry die waardes uit die registre:
Ondersoek die boodskap kop deur die eerste argument te kontroleer:
Daardie tipe mach_msg_bits_t
is baie algemeen om 'n antwoord toe te laat.
Die naam is die versteknaam wat aan die poort gegee word (kyk hoe dit in die eerste 3 byte toeneem). Die ipc-object
is die versteekte unieke identifiseerder van die poort.
Let ook op hoe die poorte met slegs send
regte die eienaar daarvan identifiseer (poortnaam + pid).
Let ook op die gebruik van +
om ander take wat aan dieselfde poort gekoppel is aan te dui.
Dit is ook moontlik om procesxp te gebruik om ook die geregistreerde diensname te sien (met SIP wat gedeaktiveer is weens die behoefte aan com.apple.system-task-port
):
Jy kan hierdie instrument in iOS installeer deur dit af te laai vanaf http://newosxbook.com/tools/binpack64-256.tar.gz
Merk op hoe die sender 'n poort toewys, 'n send right skep vir die naam org.darlinghq.example
en dit na die bootstrap server stuur terwyl die sender vir die send right van daardie naam gevra het en dit gebruik het om 'n boodskap te stuur.
Hierdie program wys hoe om 'n boodskap te stuur na 'n ander proses deur gebruik te maak van Inter-Process Communication (IPC) in macOS. Die sender proses skep 'n boodskap en stuur dit na die ander proses deur die gebruik van 'n IPC meganisme soos mach_msg
.
Daar is sekere spesiale poorte wat toelaat om sekere sensitiewe aksies uit te voer of toegang te verkry tot sekere sensitiewe data in die geval waar 'n taak die SEND-permissies oor hulle het. Dit maak hierdie poorte baie interessant vanuit 'n aanvaller se perspektief nie net vanweë die vermoëns nie, maar omdat dit moontlik is om SEND-permissies oor take te deel.
Hierdie poorte word voorgestel deur 'n nommer.
SEND regte kan verkry word deur host_get_special_port
te roep en RECEIVE regte deur host_set_special_port
te roep. Nietemin, beide oproepe vereis die host_priv
poort wat slegs root kan toegang verkry. Verder was dit in die verlede vir root moontlik om host_set_special_port
te roep en willekeurige poorte te kap wat byvoorbeeld toegelaat het om kodehandtekeninge te omseil deur HOST_KEXTD_PORT
te kap (SIP voorkom dit nou).
Hierdie is verdeel in 2 groepe: Die eerste 7 poorte word besit deur die kernel waarvan die 1 HOST_PORT
, die 2 HOST_PRIV_PORT
, die 3 HOST_IO_MASTER_PORT
en die 7 is HOST_MAX_SPECIAL_KERNEL_PORT
.
Diegene wat begin vanaf nommer 8 word besit deur stelseldaemons en hulle kan gevind word wat verklaar is in host_special_ports.h
.
Gasheerpoort: As 'n proses SEND-bevoegdheid oor hierdie poort het, kan hy inligting oor die sisteem kry deur sy roetines te roep soos:
host_processor_info
: Kry verwerkerinligting
host_info
: Kry gasheerinligting
host_virtual_physical_table_info
: Virtuele/Fisiese bladsytabel (vereis MACH_VMDEBUG)
host_statistics
: Kry gasheerstatistieke
mach_memory_info
: Kry kernelgeheue-indeling
Gasheer Priv-poort: 'n Proses met SEND-reg oor hierdie poort kan bevoorregte aksies uitvoer soos die vertoon van opstartdata of probeer om 'n kerneluitbreiding te laai. Die proses moet root wees om hierdie toestemming te kry.
Verder, om die kext_request
API te roep, is dit nodig om ander toestemmings te hê com.apple.private.kext*
wat slegs aan Apple-binêre lêers gegee word.
Ander roetines wat geroep kan word is:
host_get_boot_info
: Kry machine_boot_info()
host_priv_statistics
: Kry bevoorregte statistieke
vm_allocate_cpm
: Allokeer Aaneenlopende Fisiese Geheue
host_processors
: Stuur reg na gasheerverwerkers
mach_vm_wire
: Maak geheue residens
Aangesien root toegang tot hierdie toestemming kan verkry, kan dit host_set_[special/exception]_port[s]
roep om gasheer spesiale of uitsonderingspoorte te kap.
Dit is moontlik om alle gasheer spesiale poorte te sien deur die volgende te hardloop:
Hierdie is poorte wat gereserveer is vir bekende dienste. Dit is moontlik om hulle te kry/stel deur task_[get/set]_special_port
te roep. Hulle kan gevind word in task_special_ports.h
:
Van hier:
TASK_KERNEL_PORT[taak-self stuur reg]: Die poort wat gebruik word om hierdie taak te beheer. Gebruik om boodskappe te stuur wat die taak beïnvloed. Dit is die poort wat teruggegee word deur mach_task_self (sien Taak Poorte hieronder).
TASK_BOOTSTRAP_PORT[bootstrap stuur reg]: Die taak se bootstrap poort. Gebruik om boodskappe te stuur wat die terugkeer van ander stelseldienspoorte aanvra.
TASK_HOST_NAME_PORT[host-self stuur reg]: Die poort wat gebruik word om inligting van die gasheer te versoek. Dit is die poort wat teruggegee word deur mach_host_self.
TASK_WIRED_LEDGER_PORT[ledger stuur reg]: Die poort wat die bron noem waaruit hierdie taak sy bedrade kernelgeheue trek.
TASK_PAGED_LEDGER_PORT[ledger stuur reg]: Die poort wat die bron noem waaruit hierdie taak sy verstekgeheue bestuurde geheue trek.
Oorspronklik het Mach nie "prosesse" gehad nie, dit het "take" gehad wat meer as 'n houer van drade beskou is. Toe Mach saamgevoeg is met BSD was elke taak gekorreleer met 'n BSD-proses. Daarom het elke BSD-proses die besonderhede wat dit nodig het om 'n proses te wees en elke Mach-taak het ook sy innerlike werking (behalwe vir die nie-bestaande pid 0 wat die kernel_task
is).
Daar is twee baie interessante funksies wat hiermee verband hou:
task_for_pid(target_task_port, pid, &task_port_of_pid)
: Kry 'n STUUR reg vir die taakpoort van die taak wat verband hou met die gespesifiseerde pid
en gee dit aan die aangeduide target_task_port
(wat gewoonlik die aanroeperstaak is wat mach_task_self()
gebruik het, maar kan 'n STUUR poort oor 'n ander taak wees.)
pid_for_task(task, &pid)
: Gegewe 'n STUUR reg vir 'n taak, vind uit aan watter PID hierdie taak verband hou.
Om aksies binne die taak uit te voer, het die taak 'n STUUR
reg na homself nodig deur mach_task_self()
te roep (wat die task_self_trap
(28) gebruik). Met hierdie toestemming kan 'n taak verskeie aksies uitvoer soos:
task_threads
: Kry STUUR reg oor alle taakpoorte van die drade van die taak
task_info
: Kry inligting oor 'n taak
task_suspend/resume
: Ophou of hervat 'n taak
task_[get/set]_special_port
thread_create
: Skep 'n draad
task_[get/set]_state
: Beheer taaktoestand
en meer kan gevind word in mach/task.h
Let daarop dat met 'n STUUR reg oor 'n taakpoort van 'n verskillende taak, is dit moontlik om sulke aksies oor 'n verskillende taak uit te voer.
Verder is die taak_poort ook die vm_map
poort wat toelaat om geheue te lees en te manipuleer binne 'n taak met funksies soos vm_read()
en vm_write()
. Dit beteken basies dat 'n taak met STUUR regte oor die taak_poort van 'n ander taak in staat sal wees om kode in daardie taak in te spuit.
Onthou dat omdat die kernel ook 'n taak is, as iemand daarin slaag om 'n STUUR toestemmings oor die kernel_task
te kry, sal dit in staat wees om die kernel enige iets te laat uitvoer (jailbreaks).
Roep mach_task_self()
aan om die naam vir hierdie poort vir die aanroeperstaak te kry. Hierdie poort word slegs geërf oor exec()
; 'n nuwe taak wat geskep is met fork()
kry 'n nuwe taakpoort (as 'n spesiale geval, kry 'n taak ook 'n nuwe taakpoort na exec()
in 'n suid-binêre). Die enigste manier om 'n taak te skep en sy poort te kry, is om die "poortruil dans" uit te voer terwyl 'n fork()
gedoen word.
Hierdie is die beperkings om toegang tot die poort te verkry (vanaf macos_task_policy
van die binêre AppleMobileFileIntegrity
):
As die program die com.apple.security.get-task-allow
toestemming het, kan prosesse van dieselfde gebruiker toegang tot die taakpoort kry (gewoonlik bygevoeg deur Xcode vir foutopsporing). Die notariseringsproses sal dit nie toelaat vir produksie vrystellings nie.
Programme met die com.apple.system-task-ports
toestemming kan die taakpoort vir enige proses kry, behalwe die kernel. In ouer weergawes was dit genoem task_for_pid-allow
. Dit word slegs aan Apple-toepassings toegeken.
Root kan toegang tot taakpoorte van toepassings kry wat nie met 'n verharde hardloopomgewing saamgestel is nie (en nie van Apple nie).
Die taaknaampoort: 'n Onbevoorregte weergawe van die taakpoort. Dit verwys na die taak, maar laat nie toe om dit te beheer nie. Die enigste ding wat beskikbaar lyk deur dit is task_info()
.
Drade het ook geassosieerde poorte, wat sigbaar is vanaf die taak wat task_threads
aanroep en vanaf die verwerker met processor_set_threads
. 'n STUUR reg oor die draadpoort maak dit moontlik om die funksie van die thread_act
subsisteem te gebruik, soos:
thread_terminate
thread_[get/set]_state
act_[get/set]_state
thread_[suspend/resume]
thread_info
...
Enige draad kan hierdie poort kry deur na mach_thread_sef
te roep.
Jy kan 'n shellkode kry van:
Introduction to ARM64v8Hierdie lêer bevat die voorregte wat aan die toepassing toegeken is vir die interproseskommunikasie (IPC). Die voorregte in hierdie lêer bepaal watter aksies die toepassing mag uitvoer binne die konteks van IPC. Dit is belangrik om die inhoud van hierdie lêer te monitor en te verseker dat slegs die nodige voorregte toegeken word om die veiligheid van die stelsel te handhaaf.
Kompileer die vorige program en voeg die bevoegdhede by om kode in te spuit met dieselfde gebruiker (as nie, sal jy sudo moet gebruik).