| Title | XnSoft XnView 2.52.5.0 Heap Buffer Overflow Remote Code Execution |
|---|
| Description | A heap buffer overflow exists in the BRUN chunk decoder of the XnView FLI file parser. The BRUN chunk handler uses a 16-bit starting_line field to compute the write address in a heap buffer. The handler does not check this value against the buffer size. An attacker who supplies a crafted FLI file with a large starting_line value can write arbitrary data past the image buffer into heap memory.
CVSS 3.1 Base Score: 9.1 (Critical) - AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
== Disclosure ==
This vulnerability has been responsibly reported to the vendor and subsequently fixed by the vendor with the release of XnView Classic 2.52.6 (https://newsgroup.xnview.com/viewtopic.php?t=51359)
== Detailed description ==
The FLI animation format divides each frame into chunks. Each chunk has a 6-byte header. The header contains a 32-bit size field and a 16-bit type field. The BRUN chunk (type 12) uses a compressed line-based encoding. Its data starts with two 16-bit fields:
- starting_line (uint16): The line number where the decoder writes pixel data. The handler loads this with MOVZX. The range is 0 to 65535.
- num_lines (uint16): The number of scanlines to process.
After these fields comes per-line compressed data. Each line starts with a packet count byte. Each packet has a 1-byte unsigned skip, a 1-byte signed count, and count bytes of pixel data when count is positive.
The BRUN handler is at runtime address 0x0087E54A. The PE loads at base 0x005C0000 each run. The write-address computation is at 0x0087E584:
0x0087E579: mov ecx, dword ptr [ebp + 0xc] ; ecx = image object
0x0087E57C: add edi, esi ; edi = starting_line + line_counter
0x0087E584: imul edi, dword ptr [ecx + 8] ; edi *= width
0x0087E588: add edi, dword ptr [ebp + 0x14] ; edi += image_buf
The value in edi is the heap address where the decoder writes pixel data. The image_buf allocation is width times height bytes. For an 8x3 image this is 24 bytes. But starting_line can be 65535. This gives a maximum write offset of 65535 times 8, or 524,280 bytes. The handler does not compare starting_line against height. It does not validate that the computed address stays within the image_buf allocation.
4b. Code flow from input to vulnerable condition
1. XnView opens the FLI file. It reads the 128-byte header. It extracts width, height, depth, and frame count.
2. For each frame, XnView reads the 16-byte frame header. It iterates over chunks. A jump table at 0x0087E7E8 dispatches to per-type handlers. The index is chunk type minus 10. BRUN type 12 dispatches to entry 2 at 0x0087E54A.
3. The BRUN handler reads starting_line and num_lines from the chunk data. It loops over num_lines. For each line it reads packets. It writes pixel data to the address (starting_line + line_counter) * width + image_buf.
4. When starting_line is larger than height, the write address exceeds the image_buf allocation. The write lands on heap objects near image_buf in memory.
5. After the decoder processes all chunks, it calls a function pointer in the image object. At 0x008220EA:
0x008220EA: mov ecx, dword ptr [esi + 0xac] ; load function pointer
0x008220F0: test ecx, ecx
0x008220F2: je skip
0x008220F4: push dword ptr [esi + 0xa8] ; push argument
0x008220FA: lea eax, [ebx - 1]
0x008220FD: push dword ptr [ebp + 0xc]
0x00822100: push eax
0x00822101: call ecx ; indirect call
6. If the overflow wrote a gadget address to [esi+0xAC] and an EIP target to [esi+0xA8], the call ecx redirects execution to the attacker chain.
4c. Buffer size and injection point
Buffer: image_buf. The heap allocates width * height bytes. For the PoC, width is 8 and height is 3. The buffer is 24 bytes.
Injection point: The starting_line field at offset 0 in the BRUN chunk data. This field sits right after the 6-byte chunk header. It is a 16-bit unsigned value.
Write formula: write_address = starting_line * width + image_buf
Maximum legal value: starting_line should be at most height minus 1. For a 3-line image this is 2. The handler does not check this.
Actual values in the PoC: starting_line ranges from 22500 to 43771. These produce write offsets of 180,000 to 350,152 bytes past image_buf.
|
|---|
| Source | ⚠️ https://newsgroup.xnview.com/viewtopic.php?t=51359 |
|---|
| User | jonzab (UID 97521) |
|---|
| Submission | 09/22/2026 09:44 (15 days ago) |
|---|
| Moderation | 10/07/2026 09:48 (15 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 414926 [XnView Classic 2.52.5 FLI File Parser starting_line heap-based overflow] |
|---|
| Points | 17 |
|---|