macOS Thread Injection via Task port
Kode
1. Draadkaping
Aanvanklik word die task_threads()
-funksie op die taakpoort aangeroep om 'n draadlys van die afgeleë taak te verkry. 'n Draad word gekies om te kap. Hierdie benadering wyk af van konvensionele kode-inspuitingsmetodes, aangesien die skep van 'n nuwe afgeleë draad verbied word as gevolg van die nuwe mitigasie wat thread_create_running()
blokkeer.
Om die draad te beheer, word thread_suspend()
geroep om sy uitvoering te stuit.
Die enigste toegelate operasies op die afgeleë draad behels die stop en begin daarvan, die herwinning en verandering van sy registerwaardes. Afgeleë funksie-oproepe word geïnisieer deur die registers x0
tot x7
in te stel op die argumente, die pc
te konfigureer om die gewenste funksie te teiken, en die draad te aktiveer. Om te verseker dat die draad nie na die terugkeer afskakel nie, is dit nodig om die terugkeer op te spoor.
Een strategie behels die registreer van 'n uitsonderingshanterer vir die afgeleë draad deur thread_set_exception_ports()
te gebruik, deur die lr
-register na 'n ongeldige adres voor die funksie-oproep te stel. Dit veroorsaak 'n uitsondering na die funksie-uitvoering, wat 'n boodskap na die uitsonderingspoort stuur en die staat inspekteer om die terugkeerwaarde te herstel. As alternatief, soos aangeneem van Ian Beer se triple_fetch-exploit, word lr
ingestel om oneindig te loop. Die draad se register word dan voortdurend gemonitor totdat pc
na daardie instruksie wys.
2. Mach-poorte vir kommunikasie
Die volgende fase behels die vestiging van Mach-poorte om kommunikasie met die afgeleë draad te fasiliteer. Hierdie poorte is instrumenteel in die oordrag van willekeurige stuur- en ontvangsregte tussen take.
Vir tweerigtingkommunikasie word twee Mach-ontvangsregte geskep: een in die plaaslike en die ander in die afgeleë taak. Daarna word 'n stuurreg vir elke poort oorgedra na die teenoorgestelde taak, wat boodskapuitruiling moontlik maak.
Met die fokus op die plaaslike poort, word die ontvangsreg deur die plaaslike taak aangehou. Die poort word geskep met mach_port_allocate()
. Die uitdaging lê daarin om 'n stuurreg na hierdie poort oor te dra na die afgeleë taak.
'n Strategie behels die gebruik van thread_set_special_port()
om 'n stuurreg na die plaaslike poort in die afgeleë draad se THREAD_KERNEL_PORT
te plaas. Daarna word die afgeleë draad geïnstrueer om mach_thread_self()
te roep om die stuurreg te herwin.
Vir die afgeleë poort word die proses in wese omgekeer. Die afgeleë draad word geïnstrueer om 'n Mach-poort te genereer via mach_reply_port()
(aangesien mach_port_allocate()
ongeskik is as gevolg van sy terugkeer-meganisme). By die skep van die poort word mach_port_insert_right()
in die afgeleë draad geroep om 'n stuurreg te vestig. Hierdie reg word dan in die kernel gestoor deur thread_set_special_port()
te gebruik. Terug in die plaaslike taak word thread_get_special_port()
gebruik op die afgeleë draad om 'n stuurreg te bekom na die nuut toegewese Mach-poort in die afgeleë taak.
Voltooiing van hierdie stappe lei tot die vestiging van Mach-poorte, wat die grondslag lê vir tweerigtingkommunikasie.
3. Basiese Geheue Lees-/Skryfprimitiewe
In hierdie gedeelte lê die fokus op die gebruik van die uitvoerprimitief om basiese geheue lees- en skryfprimitiewe te vestig. Hierdie aanvanklike stappe is noodsaaklik om meer beheer oor die afgeleë proses te verkry, alhoewel die primitiewe op hierdie stadium nie baie doeleindes dien nie. Binnekort sal hulle opgradeer word na meer gevorderde weergawes.
Geheue lees en skryf met behulp van die uitvoerprimitief
Die doel is om geheue lees en skryf uit te voer met behulp van spesifieke funksies. Vir geheue lees word funksies met die volgende struktuur gebruik:
En vir skryf na geheue, word funksies soortgelyk aan hierdie struktuur gebruik:
Hierdie funksies stem ooreen met die gegewe saamgestelde instruksies:
Identifiseer Geskikte Funksies
'n Skandering van algemene biblioteke het geskikte kandidate vir hierdie operasies geïdentifiseer:
Lees van Geheue: Die
property_getName()
-funksie van die Objective-C runtime-biblioteek word geïdentifiseer as 'n geskikte funksie vir die lees van geheue. Die funksie word hieronder uiteengesit:
Hierdie funksie tree effektief op soos die read_func
deur die eerste veld van objc_property_t
terug te gee.
Skryf van Geheue: Dit is meer uitdagend om 'n voorafgeboude funksie vir die skryf van geheue te vind. Die
_xpc_int64_set_value()
funksie van libxpc is egter 'n geskikte kandidaat met die volgende disassemblage:
Om 'n 64-bit skryf by 'n spesifieke adres uit te voer, word die afstandsoproep gestruktureer as:
Met hierdie primitiewe gevestig, is die verhoog gestel vir die skep van gedeelde geheue, wat 'n beduidende vordering in die beheer van die afgeleë proses beteken.
4. Gedeelde Geheue Opstelling
Die doel is om gedeelde geheue tussen plaaslike en afgeleë take te vestig, wat data-oordrag vereenvoudig en die aanroep van funksies met veelvuldige argumente fasiliteer. Die benadering behels die benutting van libxpc
en sy OS_xpc_shmem
objek tipe, wat gebaseer is op Mach-geheueinskrywings.
Prosessoorsig:
Geheue-toekenning:
Ken die geheue toe vir deling deur
mach_vm_allocate()
te gebruik.Gebruik
xpc_shmem_create()
om 'nOS_xpc_shmem
objek vir die toegewese geheuegebied te skep. Hierdie funksie sal die skepping van die Mach-geheueinskrywing bestuur en die Mach-stuurreg op offset0x18
van dieOS_xpc_shmem
objek stoor.
Skep van Gedeelde Geheue in Afgeleë Proses:
Ken geheue toe vir die
OS_xpc_shmem
objek in die afgeleë proses met 'n afgeleë oproep namalloc()
.Kopieer die inhoud van die plaaslike
OS_xpc_shmem
objek na die afgeleë proses. Hierdie aanvanklike kopie sal egter verkeerde Mach-geheueinskrywingname hê by offset0x18
.
Korrigeer die Mach-Geheueinskrywing:
Maak gebruik van die
thread_set_special_port()
metode om 'n stuurreg vir die Mach-geheueinskrywing in die afgeleë taak in te voeg.Korrekteer die Mach-geheueinskrywingveld by offset
0x18
deur dit te oorskryf met die naam van die afgeleë geheueinskrywing.
Voltooiing van Gedeelde Geheue Opstelling:
Valideer die afgeleë
OS_xpc_shmem
objek.Stel die gedeelde geheueafbeelding op met 'n afgeleë oproep na
xpc_shmem_remote()
.
Deur hierdie stappe te volg, sal gedeelde geheue tussen die plaaslike en afgeleë take doeltreffend opgestel word, wat eenvoudige data-oordrag en die uitvoering van funksies met veelvuldige argumente moontlik maak.
Addisionele Kodefragmente
Vir geheue-toekenning en die skep van gedeelde geheue objekte:
Vir die skep en regstelling van die gedeelde geheue-object in die afgeleë proses:
Onthou om die besonderhede van Mach-poorte en geheue-invoernaam korrek te hanteer om te verseker dat die gedeelde geheue korrek funksioneer.
5. Volledige beheer bereik
Nadat ons suksesvol gedeelde geheue opgestel en willekeurige uitvoeringsvermoëns verkry het, het ons in wese volledige beheer oor die teikenproses verkry. Die sleutelfunksies wat hierdie beheer moontlik maak, is:
Willekeurige Geheue-operasies:
Voer willekeurige geheuelesings uit deur
memcpy()
aan te roep om data van die gedeelde gebied te kopieer.Voer willekeurige geheue-skrywings uit deur
memcpy()
te gebruik om data na die gedeelde gebied oor te dra.
Hantering van Funksie-oproepe met Meerdere Argumente:
Vir funksies wat meer as 8 argumente vereis, reël die bykomende argumente op die stapel in ooreenstemming met die oproepkonvensie.
Mach-poortoorplasing:
Oordra van Mach-poorte tussen take deur Mach-boodskappe via voorheen opgestelde poorte.
Lêerbeskryweroorplasing:
Oordra van lêerbeskrywers tussen prosesse deur gebruik te maak van lêerpoorte, 'n tegniek wat deur Ian Beer in
triple_fetch
beklemtoon word.
Hierdie omvattende beheer word gekapsuleer binne die threadexec biblioteek, wat 'n gedetailleerde implementering en 'n gebruikersvriendelike API bied vir interaksie met die slagofferproses.
Belangrike oorwegings:
Verseker korrekte gebruik van
memcpy()
vir geheuelees-/skryfoperasies om die stabiliteit van die stelsel en die integriteit van data te handhaaf.Wanneer Mach-poorte of lêerbeskrywers oorgedra word, volg korrekte protokolle en hanteer hulpbronne verantwoordelik om lekke of onbedoelde toegang te voorkom.
Deur hierdie riglyne na te kom en die threadexec
biblioteek te gebruik, kan 'n persoon prosesse doeltreffend bestuur en interaksie daarmee op 'n fynvlakvlak bereik, en sodoende volledige beheer oor die teikenproses verkry.
Verwysings
Last updated