macOS MIG - Mach Interface Generator
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.
Basic Information
MIGλ Mach IPC μ½λ μμ±μ λ¨μννκΈ° μν΄ λ§λ€μ΄μ‘μ΅λλ€. κΈ°λ³Έμ μΌλ‘ μλ²μ ν΄λΌμ΄μΈνΈκ° μ£Όμ΄μ§ μ μλ‘ ν΅μ νκΈ° μν΄ νμν μ½λλ₯Ό μμ±ν©λλ€. μμ±λ μ½λκ° λ³΄κΈ° μ’μ§ μλλΌλ, κ°λ°μλ μ΄λ₯Ό κ°μ Έμ€κΈ°λ§ νλ©΄ κ·Έμ μ½λλ μ΄μ λ³΄λ€ ν¨μ¬ κ°λ¨ν΄μ§ κ²μ λλ€.
μ μλ μΈν°νμ΄μ€ μ μ μΈμ΄(IDL)μμ .defs νμ₯μλ₯Ό μ¬μ©νμ¬ μ§μ λ©λλ€.
μ΄ μ μλ 5κ°μ μΉμ μΌλ‘ ꡬμ±λ©λλ€:
- μλΈμμ€ν
μ μΈ: ν€μλ subsystemμ μ΄λ¦κ³Ό idλ₯Ό λνλ΄λ λ° μ¬μ©λ©λλ€. μλ²κ° 컀λμμ μ€νλμ΄μΌ νλ κ²½μ° **
KernelServer**λ‘ νμν μλ μμ΅λλ€. - ν¬ν¨ λ° μν¬νΈ: MIGλ C μ μ²λ¦¬κΈ°λ₯Ό μ¬μ©νλ―λ‘ μν¬νΈλ₯Ό μ¬μ©ν μ μμ΅λλ€. λν, μ¬μ©μ λλ μλ² μμ± μ½λμ λν΄
uimportλ°simportλ₯Ό μ¬μ©ν μ μμ΅λλ€. - νμ
μ μΈ: λ°μ΄ν° νμ
μ μ μν μ μμ§λ§, μΌλ°μ μΌλ‘
mach_types.defsλ°std_types.defsλ₯Ό κ°μ Έμ΅λλ€. μ¬μ©μ μ μ νμ μ κ²½μ° μΌλΆ ꡬ문μ μ¬μ©ν μ μμ΅λλ€: - [i
n/out]tran: λ€μ΄μ€λ λ©μμ§ λλ λκ°λ λ©μμ§λ‘ λ³νν΄μΌ νλ ν¨μ c[user/server]type: λ€λ₯Έ C νμ μ λ§€ν.destructor: νμ μ΄ ν΄μ λ λ μ΄ ν¨μλ₯Ό νΈμΆν©λλ€.- μμ : RPC λ©μλμ μ μμ λλ€. 5κ°μ§ μ νμ΄ μμ΅λλ€:
routine: μλ΅μ κΈ°λν©λλ€.simpleroutine: μλ΅μ κΈ°λνμ§ μμ΅λλ€.procedure: μλ΅μ κΈ°λν©λλ€.simpleprocedure: μλ΅μ κΈ°λνμ§ μμ΅λλ€.function: μλ΅μ κΈ°λν©λλ€.
Example
μ μ νμΌμ μμ±ν©λλ€. μ΄ κ²½μ° λ§€μ° κ°λ¨ν ν¨μλ₯Ό μ¬μ©ν©λλ€:
subsystem myipc 500; // Arbitrary name and id
userprefix USERPREF; // Prefix for created functions in the client
serverprefix SERVERPREF; // Prefix for created functions in the server
#include <mach/mach_types.defs>
#include <mach/std_types.defs>
simpleroutine Subtract(
server_port : mach_port_t;
n1 : uint32_t;
n2 : uint32_t);
첫 λ²μ§Έ μΈμλ λ°μΈλ©ν ν¬νΈμ΄λ©° MIGλ μλ΅ ν¬νΈλ₯Ό μλμΌλ‘ μ²λ¦¬ν©λλ€(ν΄λΌμ΄μΈνΈ μ½λμμ mig_get_reply_port()λ₯Ό νΈμΆνμ§ μλ ν). λν, μμ
μ IDλ μ§μ λ μλΈμμ€ν
IDλΆν° μμ°¨μ μΌλ‘ μμλ©λλ€(μμ
μ΄ λ μ΄μ μ¬μ©λμ§ μλ κ²½μ° μμ λκ³ skipμ΄ μ¬μ©λμ΄ μ¬μ ν ν΄λΉ IDλ₯Ό μ¬μ©ν μ μμ΅λλ€).
μ΄μ MIGλ₯Ό μ¬μ©νμ¬ μλ‘ ν΅μ ν μ μλ μλ² λ° ν΄λΌμ΄μΈνΈ μ½λλ₯Ό μμ±νμ¬ Subtract ν¨μλ₯Ό νΈμΆνμμμ€:
mig -header myipcUser.h -sheader myipcServer.h myipc.defs
νμ¬ λλ ν 리μ μ¬λ¬ κ°μ μλ‘μ΄ νμΌμ΄ μμ±λ©λλ€.
Tip
μμ€ν μμ λ 볡μ‘ν μμ λ₯Ό μ°ΎμΌλ €λ©΄:
mdfind mach_port.defs
κ·Έλ¦¬κ³ νμΌκ³Ό λμΌν ν΄λμμ μ»΄νμΌνλ €λ©΄:mig -DLIBSYSCALL_INTERFACE mach_ports.defs
νμΌ **myipcServer.c**μ **myipcServer.h**μμ μμ λ λ©μμ§ IDμ λ°λΌ νΈμΆν ν¨μλ₯Ό μ μνλ ꡬ쑰체 **SERVERPREFmyipc_subsystem**μ μ μΈ λ° μ μλ₯Ό μ°Ύμ μ μμ΅λλ€(μμ λ²νΈλ‘ 500μ μ§μ νμ΅λλ€):
/* Description of this subsystem, for use in direct RPC */
const struct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {
myipc_server_routine,
500, // start ID
501, // end ID
(mach_msg_size_t)sizeof(union __ReplyUnion__SERVERPREFmyipc_subsystem),
(vm_address_t)0,
{
{ (mig_impl_routine_t) 0,
// Function to call
(mig_stub_routine_t) _XSubtract, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__Subtract_t)},
}
};
μ΄μ ꡬ쑰λ₯Ό κΈ°λ°μΌλ‘ ν¨μ **myipc_server_routine**μ λ©μμ§ IDλ₯Ό κ°μ Έμμ νΈμΆν μ μ ν ν¨μλ₯Ό λ°νν©λλ€:
mig_external mig_routine_t myipc_server_routine
(mach_msg_header_t *InHeadP)
{
int msgh_id;
msgh_id = InHeadP->msgh_id - 500;
if ((msgh_id > 0) || (msgh_id < 0))
return 0;
return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
}
μ΄ μμ μμλ μ μμμ 1κ°μ ν¨μλ§ μ μνμ§λ§, λ λ§μ ν¨μλ₯Ό μ μνλ€λ©΄, κ·Έ ν¨μλ€μ SERVERPREFmyipc_subsystem λ°°μ΄ μμ μμΉνμ κ²μ΄λ©°, 첫 λ²μ§Έ ν¨μλ ID 500μ, λ λ²μ§Έ ν¨μλ ID 501μ ν λΉλμμ κ²μ
λλ€β¦
ν¨μκ° replyλ₯Ό 보λ΄μΌ νλ€λ©΄, ν¨μ mig_internal kern_return_t __MIG_check__Reply__<name>λ μ‘΄μ¬ν κ²μ
λλ€.
μ€μ λ‘ μ΄ κ΄κ³λ **myipcServer.h**μ ꡬ쑰체 **subsystem_to_name_map_myipc**μμ νμΈν μ μμ΅λλ€ (**λ€λ₯Έ νμΌμμλ **`subsystemto_name_map*****λ‘ νμλ¨):
#ifndef subsystem_to_name_map_myipc
#define subsystem_to_name_map_myipc \
{ "Subtract", 500 }
#endif
λ§μ§λ§μΌλ‘, μλ²κ° μλνλλ‘ νλ λ λ€λ₯Έ μ€μν κΈ°λ₯μ **myipc_server**λ‘, μ΄λ μμ λ IDμ κ΄λ ¨λ ν¨μλ₯Ό νΈμΆνλ μν μ ν©λλ€:
mig_external boolean_t myipc_server
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
mig_routine_t routine;
OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
/* μ΅μ ν¬κΈ°: routine()μ΄ λ€λ₯΄λ©΄ μ
λ°μ΄νΈν©λλ€ */
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
OutHeadP->msgh_local_port = MACH_PORT_NULL;
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
OutHeadP->msgh_reserved = 0;
if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
(*routine) (InHeadP, OutHeadP);
return TRUE;
}
IDλ‘ νΈμΆν ν¨μλ₯Ό μ κ·Όνλ μ΄μ μ κ°μ‘°λ μ€μ νμΈνμΈμ.
λ€μμ ν΄λΌμ΄μΈνΈκ° μλ²μμ Subtract ν¨μλ₯Ό νΈμΆν μ μλ κ°λ¨ν μλ² λ° ν΄λΌμ΄μΈνΈλ₯Ό μμ±νλ μ½λμ λλ€:
// gcc myipc_server.c myipcServer.c -o myipc_server
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "myipcServer.h"
kern_return_t SERVERPREFSubtract(mach_port_t server_port, uint32_t n1, uint32_t n2)
{
printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);
return KERN_SUCCESS;
}
int main() {
mach_port_t port;
kern_return_t kr;
// Register the mach service
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
return 1;
}
// myipc_server is the function that handles incoming messages (check previous exlpanation)
mach_msg_server(myipc_server, sizeof(union __RequestUnion__SERVERPREFmyipc_subsystem), port, MACH_MSG_TIMEOUT_NONE);
}
NDR_record
NDR_recordλ libsystem_kernel.dylibμ μν΄ λ΄λ³΄λ΄μ§λ©°, MIGκ° μμ€ν
μ 무κ΄νκ² λ°μ΄ν°λ₯Ό λ³νν μ μλλ‘ νλ ꡬ쑰체μ
λλ€. MIGλ μλ‘ λ€λ₯Έ μμ€ν
κ°μ μ¬μ©λλλ‘ μ€κ³λμκΈ° λλ¬Έμ (κ°μ λ¨Έμ μμλ§ μ¬μ©λλ κ²μ΄ μλλλ€).
μ΄κ²μ ν₯λ―Έλ‘μ΄λ°, λ§μ½ _NDR_recordκ° μ΄μ§ νμΌμμ μμ‘΄μ±μΌλ‘ λ°κ²¬λλ€λ©΄ (jtool2 -S <binary> | grep NDR λλ nm), μ΄λ ν΄λΉ μ΄μ§ νμΌμ΄ MIG ν΄λΌμ΄μΈνΈ λλ μλ²μμ μλ―Έν©λλ€.
κ²λ€κ° MIG μλ²λ __DATA.__constμ λμ€ν¨μΉ ν
μ΄λΈμ κ°μ§κ³ μμ΅λλ€ (macOS 컀λμμλ __CONST.__constdata, λ€λ₯Έ *OS 컀λμμλ __DATA_CONST.__constμ μμ΅λλ€). μ΄λ **jtool2**λ‘ λ€νν μ μμ΅λλ€.
κ·Έλ¦¬κ³ MIG ν΄λΌμ΄μΈνΈλ __mach_msgλ₯Ό μ¬μ©νμ¬ μλ²μ μ μ‘νκΈ° μν΄ __NDR_recordλ₯Ό μ¬μ©ν κ²μ
λλ€.
μ΄μ§ λΆμ
jtool
λ§μ μ΄μ§ νμΌμ΄ μ΄μ MIGλ₯Ό μ¬μ©νμ¬ mach ν¬νΈλ₯Ό λ ΈμΆνλ―λ‘, MIGκ° μ¬μ©λμμμ μλ³νλ λ°©λ²κ³Ό κ° λ©μμ§ IDμ λν΄ MIGκ° μ€ννλ ν¨μλ₯Ό μλ κ²μ΄ ν₯λ―Έλ‘μ΅λλ€.
jtool2λ Mach-O μ΄μ§ νμΌμμ MIG μ 보λ₯Ό ꡬ문 λΆμνμ¬ λ©μμ§ IDλ₯Ό νμνκ³ μ€νν ν¨μλ₯Ό μλ³ν μ μμ΅λλ€:
jtool2 -d __DATA.__const myipc_server | grep MIG
λν, MIG ν¨μλ νΈμΆλλ μ€μ ν¨μμ λνΌμ λΆκ³Όνλ―λ‘, ν΄λΉ ν¨μμ λμ€μ΄μ λΈλ¦¬λ₯Ό κ°μ Έμ€κ³ BLμ κ²μνλ©΄ νΈμΆλλ μ€μ ν¨μλ₯Ό μ°Ύμ μ μμ΅λλ€:
jtool2 -d __DATA.__const myipc_server | grep BL
Assembly
μ΄μ μ μμ λ λ©μμ§ IDμ λ°λΌ μ¬λ°λ₯Έ ν¨μλ₯Ό νΈμΆνλ κΈ°λ₯μ λ΄λΉνλ ν¨μλ myipc_serverλΌκ³ μΈκΈλμμ΅λλ€. κ·Έλ¬λ μΌλ°μ μΌλ‘ λ°μ΄λ리μ κΈ°νΈ(ν¨μ μ΄λ¦)κ° μκΈ° λλ¬Έμ λμ»΄νμΌλ λͺ¨μ΅μ΄ μ΄λ»κ² μκ²Όλμ§ νμΈνλ κ²μ΄ ν₯λ―Έλ‘μ΅λλ€. μ΄ ν¨μμ μ½λλ λ
ΈμΆλ ν¨μμλ λ
립μ μ΄κΈ° λλ¬Έμ νμ λ§€μ° μ μ¬ν©λλ€:
int _myipc_server(int arg0, int arg1) {
var_10 = arg0;
var_18 = arg1;
// μ¬λ°λ₯Έ ν¨μ ν¬μΈν°λ₯Ό μ°ΎκΈ° μν μ΄κΈ° λͺ
λ Ήμ΄
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f;
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
*(int32_t *)(var_18 + 0x4) = 0x24;
*(int32_t *)(var_18 + 0xc) = 0x0;
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
*(int32_t *)(var_18 + 0x10) = 0x0;
if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) {
rax = *(int32_t *)(var_10 + 0x14);
// μ΄ ν¨μλ₯Ό μλ³νλ λ° λμμ΄ λλ sign_extend_64 νΈμΆ
// μ΄λ νΈμΆν΄μΌ ν νΈμΆμ ν¬μΈν°λ₯Ό raxμ μ μ₯ν©λλ€
// μ£Όμ 0x100004040(ν¨μ μ£Όμ λ°°μ΄)μ μ¬μ©μ νμΈν©λλ€
// 0x1f4 = 500 (μμ ID)
rax = *(sign_extend_64(rax - 0x1f4) * 0x28 + 0x100004040);
var_20 = rax;
// if - else, ifλ falseλ₯Ό λ°ννκ³ , elseλ μ¬λ°λ₯Έ ν¨μλ₯Ό νΈμΆνκ³ trueλ₯Ό λ°νν©λλ€
if (rax == 0x0) {
*(var_18 + 0x18) = **_NDR_record;
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
var_4 = 0x0;
}
else {
// λ κ°μ μΈμλ‘ μ¬λ°λ₯Έ ν¨μλ₯Ό νΈμΆνλ κ³μ°λ μ£Όμ
(var_20)(var_10, var_18);
var_4 = 0x1;
}
}
else {
*(var_18 + 0x18) = **_NDR_record;
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
var_4 = 0x0;
}
rax = var_4;
return rax;
}
μ€μ λ‘ 0x100004000 ν¨μλ‘ κ°λ©΄ routine_descriptor ꡬ쑰체 λ°°μ΄μ μ°Ύμ μ μμ΅λλ€. ꡬ쑰체μ 첫 λ²μ§Έ μμλ ν¨μκ° κ΅¬νλ μ£Όμμ΄λ©°, ꡬ쑰체λ 0x28 λ°μ΄νΈλ₯Ό μ°¨μ§νλ―λ‘, 0λΆν° μμνμ¬ 0x28 λ°μ΄νΈλ§λ€ 8 λ°μ΄νΈλ₯Ό κ°μ Έμ€λ©΄ νΈμΆλ ν¨μμ μ£Όμκ° λ©λλ€:
.png)
.png)
μ΄ λ°μ΄ν°λ μ΄ Hopper μ€ν¬λ¦½νΈλ₯Ό μ¬μ©νμ¬ μΆμΆν μ μμ΅λλ€.
Debug
MIGμ μν΄ μμ±λ μ½λλ λν kernel_debugλ₯Ό νΈμΆνμ¬ μ§μ
λ° μ’
λ£ μμ
μ λν λ‘κ·Έλ₯Ό μμ±ν©λλ€. trace λλ **kdv**λ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό νμΈν μ μμ΅λλ€: kdv all | grep MIG
References
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.


